mirror of
https://github.com/bitwarden/android.git
synced 2024-12-18 23:31:52 +03:00
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:
parent
7a48128e43
commit
17af08b7d4
17 changed files with 166 additions and 6236 deletions
|
@ -6,7 +6,6 @@ using Bit.App.Controls;
|
|||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using AView = Android.Views.View;
|
||||
using Android.Widget;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedViewCell), typeof(ExtendedViewCellRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
|
@ -23,22 +22,6 @@ namespace Bit.Android.Controls
|
|||
if(View != null)
|
||||
{
|
||||
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;
|
||||
|
@ -55,29 +38,5 @@ namespace Bit.Android.Controls
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
6191
src/Android/Resources/Resource.Designer.cs
generated
6191
src/Android/Resources/Resource.Designer.cs
generated
File diff suppressed because it is too large
Load diff
|
@ -125,10 +125,12 @@ namespace Bit.App
|
|||
}
|
||||
else if(pinUnlock && !string.IsNullOrWhiteSpace(_authService.PIN))
|
||||
{
|
||||
|
||||
if((currentPage?.CurrentPage as LockPinPage) == null)
|
||||
var lockPinPage = (currentPage?.CurrentPage as LockPinPage);
|
||||
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
|
||||
|
|
|
@ -8,35 +8,10 @@ namespace Bit.App.Controls
|
|||
public static readonly BindableProperty BackgroundColorProperty =
|
||||
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
|
||||
{
|
||||
get { return (Color)GetValue(BackgroundColorProperty); }
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class LabeledDetailCell : ExtendedViewCell
|
||||
public class LabeledDetailCell : ViewCell
|
||||
{
|
||||
public LabeledDetailCell()
|
||||
{
|
||||
|
@ -20,19 +20,33 @@ namespace Bit.App.Controls
|
|||
Style = (Style)Application.Current.Resources["text-muted"],
|
||||
};
|
||||
|
||||
var stackLayout = new StackLayout
|
||||
var labelDetailStackLayout = new StackLayout
|
||||
{
|
||||
Padding = new Thickness(20, 5),
|
||||
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||
HorizontalOptions = LayoutOptions.StartAndExpand,
|
||||
VerticalOptions = LayoutOptions.FillAndExpand,
|
||||
Children = { Label, Detail },
|
||||
Padding = new Thickness(15, 5, 5, 5),
|
||||
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 Detail { get; private set; }
|
||||
public Button Button { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace Bit.App.Controls
|
|||
Value = new Label
|
||||
{
|
||||
Text = valueText,
|
||||
FontSize = Device.GetNamedSize(NamedSize.Default, typeof(Label)),
|
||||
LineBreakMode = LineBreakMode.TailTruncation,
|
||||
VerticalOptions = LayoutOptions.CenterAndExpand
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Bit.App.Controls
|
|||
Label = new Label
|
||||
{
|
||||
HorizontalTextAlignment = TextAlignment.Center,
|
||||
FontSize = 30,
|
||||
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
|
||||
FontFamily = "Courier"
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace Bit.App.Models.Data
|
|||
Id = folder.Id;
|
||||
UserId = userId;
|
||||
Name = folder.Name;
|
||||
RevisionDateTime = folder.RevisionDate;
|
||||
}
|
||||
|
||||
public FolderData(CipherResponse cipher, string userId)
|
||||
|
@ -37,6 +38,7 @@ namespace Bit.App.Models.Data
|
|||
Id = cipher.Id;
|
||||
UserId = userId;
|
||||
Name = data.Name;
|
||||
RevisionDateTime = cipher.RevisionDate;
|
||||
}
|
||||
|
||||
[PrimaryKey]
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using SQLite;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Bit.App.Models.Data
|
||||
{
|
||||
|
@ -36,6 +35,7 @@ namespace Bit.App.Models.Data
|
|||
Password = site.Password;
|
||||
Notes = site.Notes;
|
||||
Favorite = site.Favorite;
|
||||
RevisionDateTime = site.RevisionDate;
|
||||
}
|
||||
|
||||
public SiteData(CipherResponse cipher, string userId)
|
||||
|
@ -55,6 +55,7 @@ namespace Bit.App.Models.Data
|
|||
Password = data.Password;
|
||||
Notes = data.Notes;
|
||||
Favorite = cipher.Favorite;
|
||||
RevisionDateTime = cipher.RevisionDate;
|
||||
}
|
||||
|
||||
[PrimaryKey]
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace Bit.App.Pages
|
|||
|
||||
var tgr = new TapGestureRecognizer();
|
||||
tgr.Tapped += Tgr_Tapped;
|
||||
PinControl.Label.GestureRecognizers.Add(tgr);
|
||||
|
||||
Title = "Verify PIN";
|
||||
Content = stackLayout;
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace Bit.App.Pages
|
|||
|
||||
var tgr = new TapGestureRecognizer();
|
||||
tgr.Tapped += Tgr_Tapped;
|
||||
PinControl.Label.GestureRecognizers.Add(tgr);
|
||||
|
||||
Title = "Set PIN";
|
||||
Content = stackLayout;
|
||||
|
|
|
@ -12,7 +12,6 @@ using XLabs.Ioc;
|
|||
using Bit.App.Utilities;
|
||||
using PushNotification.Plugin.Abstractions;
|
||||
using Plugin.Settings.Abstractions;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -59,7 +58,6 @@ namespace Bit.App.Pages
|
|||
|
||||
if(Device.OS == TargetPlatform.iOS)
|
||||
{
|
||||
listView.Margin = new Thickness(0, 0, -15, 0);
|
||||
listView.RowHeight = -1;
|
||||
}
|
||||
|
||||
|
@ -195,7 +193,7 @@ namespace Bit.App.Pages
|
|||
_page = page;
|
||||
|
||||
// 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.Clicked += page.DeleteClickedAsync;
|
||||
|
||||
|
@ -210,9 +208,8 @@ namespace Bit.App.Pages
|
|||
ContextActions.Add(deleteAction);
|
||||
ContextActions.Add(moreAction);
|
||||
|
||||
DisclousureTapped += VaultListViewCell_DisclousureTapped;
|
||||
ShowDisclousure = true;
|
||||
DisclousureImage = "more";
|
||||
Button.Image = "more";
|
||||
Button.Command = new Command(() => ShowMore());
|
||||
}
|
||||
|
||||
public VaultListPageModel.Site SiteParameter
|
||||
|
@ -228,10 +225,9 @@ namespace Bit.App.Pages
|
|||
_page.MoreClickedAsync(site);
|
||||
}
|
||||
|
||||
private void VaultListViewCell_DisclousureTapped(object sender, EventArgs e)
|
||||
private void ShowMore()
|
||||
{
|
||||
var cell = sender as VaultListViewCell;
|
||||
_page.MoreClickedAsync(cell.SiteParameter);
|
||||
_page.MoreClickedAsync(SiteParameter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,6 +260,7 @@ namespace Bit.App.Pages
|
|||
};
|
||||
|
||||
View = stackLayout;
|
||||
Height = 40;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,15 +156,10 @@ namespace Bit.App.Services
|
|||
|
||||
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 deleteTask = DeleteCiphersAsync(ciphers.Result.Deleted);
|
||||
|
||||
foreach(var cipherId in ciphers.Result.Deleted)
|
||||
{
|
||||
await _siteRepository.DeleteAsync(cipherId);
|
||||
}
|
||||
|
||||
await Task.WhenAll(siteTask, folderTask);
|
||||
|
||||
if(folderTask.Exception != null || siteTask.Exception != null)
|
||||
await Task.WhenAll(siteTask, folderTask, deleteTask);
|
||||
if(folderTask.Exception != null || siteTask.Exception != null || deleteTask.Exception != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -179,14 +174,15 @@ namespace Bit.App.Services
|
|||
|
||||
foreach(var serverFolder in serverFolders)
|
||||
{
|
||||
var data = new FolderData(serverFolder, _authService.UserId);
|
||||
var existingLocalFolder = localFolders.SingleOrDefault(f => f.Id == serverFolder.Id);
|
||||
if(existingLocalFolder == null)
|
||||
{
|
||||
var data = new FolderData(serverFolder, _authService.UserId);
|
||||
await _folderRepository.InsertAsync(data);
|
||||
}
|
||||
else
|
||||
else if(existingLocalFolder.RevisionDateTime != serverFolder.RevisionDate)
|
||||
{
|
||||
var data = new FolderData(serverFolder, _authService.UserId);
|
||||
await _folderRepository.UpdateAsync(data);
|
||||
}
|
||||
}
|
||||
|
@ -208,14 +204,15 @@ namespace Bit.App.Services
|
|||
|
||||
foreach(var serverSite in serverSites)
|
||||
{
|
||||
var data = new SiteData(serverSite, _authService.UserId);
|
||||
var existingLocalSite = localSites.SingleOrDefault(s => s.Id == serverSite.Id);
|
||||
if(existingLocalSite == null)
|
||||
{
|
||||
var data = new SiteData(serverSite, _authService.UserId);
|
||||
await _siteRepository.InsertAsync(data);
|
||||
}
|
||||
else
|
||||
else if(existingLocalSite.RevisionDateTime != serverSite.RevisionDate)
|
||||
{
|
||||
var data = new SiteData(serverSite, _authService.UserId);
|
||||
await _siteRepository.UpdateAsync(data);
|
||||
}
|
||||
}
|
||||
|
@ -230,5 +227,16 @@ namespace Bit.App.Services
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
26
src/iOS/Controls/ExtendedEditorRenderer.cs
Normal file
26
src/iOS/Controls/ExtendedEditorRenderer.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,9 @@ namespace Bit.iOS.Controls
|
|||
var view = e.NewElement as ExtendedPicker;
|
||||
if(view != null)
|
||||
{
|
||||
var descriptor = UIFontDescriptor.PreferredBody;
|
||||
Control.Font = UIFont.FromDescriptor(descriptor, descriptor.PointSize);
|
||||
|
||||
SetBorder(view);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Bit.App.Controls;
|
||||
using Bit.iOS.Controls;
|
||||
using CoreGraphics;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
@ -18,31 +17,6 @@ namespace Bit.iOS.Controls
|
|||
if(cell != null)
|
||||
{
|
||||
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;
|
||||
|
|
|
@ -103,6 +103,7 @@
|
|||
<Compile Include="Controls\ContentPageRenderer.cs" />
|
||||
<Compile Include="Controls\CustomButtonRenderer.cs" />
|
||||
<Compile Include="Controls\CustomLabelRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedEditorRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedSwitchCellRenderer.cs" />
|
||||
<Compile Include="Controls\ListViewRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedViewCellRenderer.cs" />
|
||||
|
|
Loading…
Reference in a new issue