Removed disclosure from view cell in favor of button. Updated sync logic for incrementals. Store revision date from server record. Apply more accessability font size support for editor and picker controls

This commit is contained in:
Kyle Spearrin 2016-06-30 18:53:43 -04:00
parent 7a48128e43
commit 17af08b7d4
17 changed files with 166 additions and 6236 deletions

View file

@ -6,7 +6,6 @@ using Bit.App.Controls;
using Xamarin.Forms; using Xamarin.Forms;
using Xamarin.Forms.Platform.Android; using Xamarin.Forms.Platform.Android;
using AView = Android.Views.View; using AView = Android.Views.View;
using Android.Widget;
[assembly: ExportRenderer(typeof(ExtendedViewCell), typeof(ExtendedViewCellRenderer))] [assembly: ExportRenderer(typeof(ExtendedViewCell), typeof(ExtendedViewCellRenderer))]
namespace Bit.Android.Controls namespace Bit.Android.Controls
@ -23,22 +22,6 @@ namespace Bit.Android.Controls
if(View != null) if(View != null)
{ {
View.SetBackgroundColor(extendedCell.BackgroundColor.ToAndroid()); View.SetBackgroundColor(extendedCell.BackgroundColor.ToAndroid());
if(extendedCell.ShowDisclousure)
{
var resourceId = Resource.Drawable.ion_chevron_right;
if(!string.IsNullOrWhiteSpace(extendedCell.DisclousureImage))
{
var fileName = System.IO.Path.GetFileNameWithoutExtension(extendedCell.DisclousureImage);
resourceId = context.Resources.GetIdentifier(fileName, "drawable", context.PackageName);
}
var image = new DisclosureImage(context, extendedCell);
image.SetImageResource(resourceId);
image.SetPadding(10, 10, 30, 10);
//View.SetAccessoryView(image);
}
} }
return View; return View;
@ -55,29 +38,5 @@ namespace Bit.Android.Controls
View.SetBackgroundColor(cell.BackgroundColor.ToAndroid()); View.SetBackgroundColor(cell.BackgroundColor.ToAndroid());
} }
} }
private class DisclosureImage : ImageView
{
private ExtendedViewCell _cell;
public DisclosureImage(Context context, ExtendedViewCell cell) : base(context)
{
_cell = cell;
}
public override bool OnTouchEvent(MotionEvent e)
{
switch(e.Action)
{
case MotionEventActions.Up:
_cell.OnDisclousureTapped();
break;
default:
break;
}
return true;
}
}
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -125,10 +125,12 @@ namespace Bit.App
} }
else if(pinUnlock && !string.IsNullOrWhiteSpace(_authService.PIN)) else if(pinUnlock && !string.IsNullOrWhiteSpace(_authService.PIN))
{ {
var lockPinPage = (currentPage?.CurrentPage as LockPinPage);
if((currentPage?.CurrentPage as LockPinPage) == null) if(lockPinPage == null)
{ {
await Current.MainPage.Navigation.PushModalAsync(new ExtendedNavigationPage(new LockPinPage()), false); lockPinPage = new LockPinPage();
await Current.MainPage.Navigation.PushModalAsync(new ExtendedNavigationPage(lockPinPage), false);
lockPinPage.PinControl.Entry.Focus();
} }
} }
else else

View file

@ -8,35 +8,10 @@ namespace Bit.App.Controls
public static readonly BindableProperty BackgroundColorProperty = public static readonly BindableProperty BackgroundColorProperty =
BindableProperty.Create(nameof(BackgroundColor), typeof(Color), typeof(ExtendedTextCell), Color.White); BindableProperty.Create(nameof(BackgroundColor), typeof(Color), typeof(ExtendedTextCell), Color.White);
public static readonly BindableProperty ShowDisclousureProperty =
BindableProperty.Create(nameof(DisclousureImage), typeof(bool), typeof(ExtendedTextCell), false);
public static readonly BindableProperty DisclousureImageProperty =
BindableProperty.Create(nameof(DisclousureImage), typeof(string), typeof(ExtendedTextCell), string.Empty);
public Color BackgroundColor public Color BackgroundColor
{ {
get { return (Color)GetValue(BackgroundColorProperty); } get { return (Color)GetValue(BackgroundColorProperty); }
set { SetValue(BackgroundColorProperty, value); } set { SetValue(BackgroundColorProperty, value); }
} }
public bool ShowDisclousure
{
get { return (bool)GetValue(ShowDisclousureProperty); }
set { SetValue(ShowDisclousureProperty, value); }
}
public string DisclousureImage
{
get { return (string)GetValue(DisclousureImageProperty); }
set { SetValue(DisclousureImageProperty, value); }
}
public event EventHandler DisclousureTapped;
public void OnDisclousureTapped()
{
DisclousureTapped?.Invoke(this, EventArgs.Empty);
}
} }
} }

View file

@ -2,7 +2,7 @@
namespace Bit.App.Controls namespace Bit.App.Controls
{ {
public class LabeledDetailCell : ExtendedViewCell public class LabeledDetailCell : ViewCell
{ {
public LabeledDetailCell() public LabeledDetailCell()
{ {
@ -20,19 +20,33 @@ namespace Bit.App.Controls
Style = (Style)Application.Current.Resources["text-muted"], Style = (Style)Application.Current.Resources["text-muted"],
}; };
var stackLayout = new StackLayout var labelDetailStackLayout = new StackLayout
{ {
Padding = new Thickness(20, 5), HorizontalOptions = LayoutOptions.StartAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand,
Children = { Label, Detail }, Children = { Label, Detail },
Padding = new Thickness(15, 5, 5, 5),
Spacing = 0 Spacing = 0
}; };
View = stackLayout; Button = new Button
{
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.FillAndExpand,
WidthRequest = 50
};
var containerStackLayout = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Children = { labelDetailStackLayout, Button }
};
View = containerStackLayout;
} }
public Label Label { get; private set; } public Label Label { get; private set; }
public Label Detail { get; private set; } public Label Detail { get; private set; }
public Button Button { get; private set; }
} }
} }

View file

@ -38,6 +38,7 @@ namespace Bit.App.Controls
Value = new Label Value = new Label
{ {
Text = valueText, Text = valueText,
FontSize = Device.GetNamedSize(NamedSize.Default, typeof(Label)),
LineBreakMode = LineBreakMode.TailTruncation, LineBreakMode = LineBreakMode.TailTruncation,
VerticalOptions = LayoutOptions.CenterAndExpand VerticalOptions = LayoutOptions.CenterAndExpand
}; };

View file

@ -12,7 +12,7 @@ namespace Bit.App.Controls
Label = new Label Label = new Label
{ {
HorizontalTextAlignment = TextAlignment.Center, HorizontalTextAlignment = TextAlignment.Center,
FontSize = 30, FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
FontFamily = "Courier" FontFamily = "Courier"
}; };

View file

@ -23,6 +23,7 @@ namespace Bit.App.Models.Data
Id = folder.Id; Id = folder.Id;
UserId = userId; UserId = userId;
Name = folder.Name; Name = folder.Name;
RevisionDateTime = folder.RevisionDate;
} }
public FolderData(CipherResponse cipher, string userId) public FolderData(CipherResponse cipher, string userId)
@ -37,6 +38,7 @@ namespace Bit.App.Models.Data
Id = cipher.Id; Id = cipher.Id;
UserId = userId; UserId = userId;
Name = data.Name; Name = data.Name;
RevisionDateTime = cipher.RevisionDate;
} }
[PrimaryKey] [PrimaryKey]

View file

@ -2,7 +2,6 @@
using SQLite; using SQLite;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Models.Api; using Bit.App.Models.Api;
using Newtonsoft.Json.Linq;
namespace Bit.App.Models.Data namespace Bit.App.Models.Data
{ {
@ -36,6 +35,7 @@ namespace Bit.App.Models.Data
Password = site.Password; Password = site.Password;
Notes = site.Notes; Notes = site.Notes;
Favorite = site.Favorite; Favorite = site.Favorite;
RevisionDateTime = site.RevisionDate;
} }
public SiteData(CipherResponse cipher, string userId) public SiteData(CipherResponse cipher, string userId)
@ -55,6 +55,7 @@ namespace Bit.App.Models.Data
Password = data.Password; Password = data.Password;
Notes = data.Notes; Notes = data.Notes;
Favorite = cipher.Favorite; Favorite = cipher.Favorite;
RevisionDateTime = cipher.RevisionDate;
} }
[PrimaryKey] [PrimaryKey]

View file

@ -53,6 +53,7 @@ namespace Bit.App.Pages
var tgr = new TapGestureRecognizer(); var tgr = new TapGestureRecognizer();
tgr.Tapped += Tgr_Tapped; tgr.Tapped += Tgr_Tapped;
PinControl.Label.GestureRecognizers.Add(tgr);
Title = "Verify PIN"; Title = "Verify PIN";
Content = stackLayout; Content = stackLayout;

View file

@ -44,6 +44,7 @@ namespace Bit.App.Pages
var tgr = new TapGestureRecognizer(); var tgr = new TapGestureRecognizer();
tgr.Tapped += Tgr_Tapped; tgr.Tapped += Tgr_Tapped;
PinControl.Label.GestureRecognizers.Add(tgr);
Title = "Set PIN"; Title = "Set PIN";
Content = stackLayout; Content = stackLayout;

View file

@ -12,7 +12,6 @@ using XLabs.Ioc;
using Bit.App.Utilities; using Bit.App.Utilities;
using PushNotification.Plugin.Abstractions; using PushNotification.Plugin.Abstractions;
using Plugin.Settings.Abstractions; using Plugin.Settings.Abstractions;
using System.Windows.Input;
namespace Bit.App.Pages namespace Bit.App.Pages
{ {
@ -59,7 +58,6 @@ namespace Bit.App.Pages
if(Device.OS == TargetPlatform.iOS) if(Device.OS == TargetPlatform.iOS)
{ {
listView.Margin = new Thickness(0, 0, -15, 0);
listView.RowHeight = -1; listView.RowHeight = -1;
} }
@ -195,7 +193,7 @@ namespace Bit.App.Pages
_page = page; _page = page;
// Adding whitespace to Delete action to account for the negative margin offset on the listview // Adding whitespace to Delete action to account for the negative margin offset on the listview
var deleteAction = new MenuItem { Text = AppResources.Delete + " ", IsDestructive = true }; var deleteAction = new MenuItem { Text = AppResources.Delete, IsDestructive = true };
deleteAction.SetBinding(MenuItem.CommandParameterProperty, new Binding(".")); deleteAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
deleteAction.Clicked += page.DeleteClickedAsync; deleteAction.Clicked += page.DeleteClickedAsync;
@ -210,9 +208,8 @@ namespace Bit.App.Pages
ContextActions.Add(deleteAction); ContextActions.Add(deleteAction);
ContextActions.Add(moreAction); ContextActions.Add(moreAction);
DisclousureTapped += VaultListViewCell_DisclousureTapped; Button.Image = "more";
ShowDisclousure = true; Button.Command = new Command(() => ShowMore());
DisclousureImage = "more";
} }
public VaultListPageModel.Site SiteParameter public VaultListPageModel.Site SiteParameter
@ -228,10 +225,9 @@ namespace Bit.App.Pages
_page.MoreClickedAsync(site); _page.MoreClickedAsync(site);
} }
private void VaultListViewCell_DisclousureTapped(object sender, EventArgs e) private void ShowMore()
{ {
var cell = sender as VaultListViewCell; _page.MoreClickedAsync(SiteParameter);
_page.MoreClickedAsync(cell.SiteParameter);
} }
} }
@ -264,6 +260,7 @@ namespace Bit.App.Pages
}; };
View = stackLayout; View = stackLayout;
Height = 40;
} }
} }
} }

View file

@ -156,15 +156,10 @@ namespace Bit.App.Services
var siteTask = SyncSitesAsync(ciphers.Result.Revised.Where(c => c.Type == Enums.CipherType.Site), false); var siteTask = SyncSitesAsync(ciphers.Result.Revised.Where(c => c.Type == Enums.CipherType.Site), false);
var folderTask = SyncFoldersAsync(ciphers.Result.Revised.Where(c => c.Type == Enums.CipherType.Folder), false); var folderTask = SyncFoldersAsync(ciphers.Result.Revised.Where(c => c.Type == Enums.CipherType.Folder), false);
var deleteTask = DeleteCiphersAsync(ciphers.Result.Deleted);
foreach(var cipherId in ciphers.Result.Deleted) await Task.WhenAll(siteTask, folderTask, deleteTask);
{ if(folderTask.Exception != null || siteTask.Exception != null || deleteTask.Exception != null)
await _siteRepository.DeleteAsync(cipherId);
}
await Task.WhenAll(siteTask, folderTask);
if(folderTask.Exception != null || siteTask.Exception != null)
{ {
return false; return false;
} }
@ -179,14 +174,15 @@ namespace Bit.App.Services
foreach(var serverFolder in serverFolders) foreach(var serverFolder in serverFolders)
{ {
var data = new FolderData(serverFolder, _authService.UserId);
var existingLocalFolder = localFolders.SingleOrDefault(f => f.Id == serverFolder.Id); var existingLocalFolder = localFolders.SingleOrDefault(f => f.Id == serverFolder.Id);
if(existingLocalFolder == null) if(existingLocalFolder == null)
{ {
var data = new FolderData(serverFolder, _authService.UserId);
await _folderRepository.InsertAsync(data); await _folderRepository.InsertAsync(data);
} }
else else if(existingLocalFolder.RevisionDateTime != serverFolder.RevisionDate)
{ {
var data = new FolderData(serverFolder, _authService.UserId);
await _folderRepository.UpdateAsync(data); await _folderRepository.UpdateAsync(data);
} }
} }
@ -208,14 +204,15 @@ namespace Bit.App.Services
foreach(var serverSite in serverSites) foreach(var serverSite in serverSites)
{ {
var data = new SiteData(serverSite, _authService.UserId);
var existingLocalSite = localSites.SingleOrDefault(s => s.Id == serverSite.Id); var existingLocalSite = localSites.SingleOrDefault(s => s.Id == serverSite.Id);
if(existingLocalSite == null) if(existingLocalSite == null)
{ {
var data = new SiteData(serverSite, _authService.UserId);
await _siteRepository.InsertAsync(data); await _siteRepository.InsertAsync(data);
} }
else else if(existingLocalSite.RevisionDateTime != serverSite.RevisionDate)
{ {
var data = new SiteData(serverSite, _authService.UserId);
await _siteRepository.UpdateAsync(data); await _siteRepository.UpdateAsync(data);
} }
} }
@ -230,5 +227,16 @@ namespace Bit.App.Services
await _siteRepository.DeleteAsync(site.Id); await _siteRepository.DeleteAsync(site.Id);
} }
} }
private async Task DeleteCiphersAsync(IEnumerable<string> cipherIds)
{
var tasks = new List<Task>();
foreach(var cipherId in cipherIds)
{
tasks.Add(_siteRepository.DeleteAsync(cipherId));
tasks.Add(_folderRepository.DeleteAsync(cipherId));
}
await Task.WhenAll(tasks);
}
} }
} }

View file

@ -0,0 +1,26 @@
using System;
using System.ComponentModel;
using Bit.App.Controls;
using Bit.iOS.Controls;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(ExtendedEditor), typeof(ExtendedEditorRenderer))]
namespace Bit.iOS.Controls
{
public class ExtendedEditorRenderer : EditorRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
var view = e.NewElement as ExtendedEditor;
if(view != null)
{
var descriptor = UIFontDescriptor.PreferredBody;
Control.Font = UIFont.FromDescriptor(descriptor, descriptor.PointSize);
}
}
}
}

View file

@ -18,6 +18,9 @@ namespace Bit.iOS.Controls
var view = e.NewElement as ExtendedPicker; var view = e.NewElement as ExtendedPicker;
if(view != null) if(view != null)
{ {
var descriptor = UIFontDescriptor.PreferredBody;
Control.Font = UIFont.FromDescriptor(descriptor, descriptor.PointSize);
SetBorder(view); SetBorder(view);
} }
} }

View file

@ -1,6 +1,5 @@
using Bit.App.Controls; using Bit.App.Controls;
using Bit.iOS.Controls; using Bit.iOS.Controls;
using CoreGraphics;
using UIKit; using UIKit;
using Xamarin.Forms; using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS; using Xamarin.Forms.Platform.iOS;
@ -18,31 +17,6 @@ namespace Bit.iOS.Controls
if(cell != null) if(cell != null)
{ {
cell.BackgroundColor = extendedCell.BackgroundColor.ToUIColor(); cell.BackgroundColor = extendedCell.BackgroundColor.ToUIColor();
if(extendedCell.ShowDisclousure)
{
cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
if(!string.IsNullOrEmpty(extendedCell.DisclousureImage))
{
var detailDisclosureButton = UIButton.FromType(UIButtonType.Custom);
detailDisclosureButton.SetImage(UIImage.FromBundle(extendedCell.DisclousureImage), UIControlState.Normal);
try
{
detailDisclosureButton.SetImage(UIImage.FromBundle(extendedCell.DisclousureImage + "_selected"), UIControlState.Selected);
}
catch
{
detailDisclosureButton.SetImage(UIImage.FromBundle(extendedCell.DisclousureImage), UIControlState.Selected);
}
detailDisclosureButton.Frame = new CGRect(0f, 0f, 50f, 100f);
detailDisclosureButton.TouchUpInside += (sender, e) =>
{
extendedCell.OnDisclousureTapped();
};
cell.AccessoryView = detailDisclosureButton;
}
}
} }
return cell; return cell;

View file

@ -103,6 +103,7 @@
<Compile Include="Controls\ContentPageRenderer.cs" /> <Compile Include="Controls\ContentPageRenderer.cs" />
<Compile Include="Controls\CustomButtonRenderer.cs" /> <Compile Include="Controls\CustomButtonRenderer.cs" />
<Compile Include="Controls\CustomLabelRenderer.cs" /> <Compile Include="Controls\CustomLabelRenderer.cs" />
<Compile Include="Controls\ExtendedEditorRenderer.cs" />
<Compile Include="Controls\ExtendedSwitchCellRenderer.cs" /> <Compile Include="Controls\ExtendedSwitchCellRenderer.cs" />
<Compile Include="Controls\ListViewRenderer.cs" /> <Compile Include="Controls\ListViewRenderer.cs" />
<Compile Include="Controls\ExtendedViewCellRenderer.cs" /> <Compile Include="Controls\ExtendedViewCellRenderer.cs" />