From 4e906f9370ddb1b2dc3bfd2a9eb26f238a51dc14 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Sat, 14 May 2016 01:34:42 -0400 Subject: [PATCH] Wired up view page functionality. Expanded LabeledValueCell. Created custom group template for vault list page. --- src/App/Controls/ExtendedTableView.cs | 9 +++ src/App/Controls/LabeledValueCell.cs | 53 +++++++---------- src/App/Models/Page/VaultViewSitePageModel.cs | 29 ++++++++- src/App/Pages/VaultAddSitePage.cs | 11 ++-- src/App/Pages/VaultEditSitePage.cs | 9 ++- src/App/Pages/VaultListPage.cs | 56 +++++++++++++++++- src/App/Pages/VaultViewSitePage.cs | 22 ++++--- src/iOS/Controls/ExtendedTableViewRenderer.cs | 6 ++ src/iOS/Resources/fa-folder-open.png | Bin 0 -> 314 bytes src/iOS/Resources/fa-folder-open@2x.png | Bin 0 -> 456 bytes src/iOS/Resources/fa-folder-open@3x.png | Bin 0 -> 623 bytes src/iOS/iOS.csproj | 9 +++ 12 files changed, 155 insertions(+), 49 deletions(-) create mode 100644 src/iOS/Resources/fa-folder-open.png create mode 100644 src/iOS/Resources/fa-folder-open@2x.png create mode 100644 src/iOS/Resources/fa-folder-open@3x.png diff --git a/src/App/Controls/ExtendedTableView.cs b/src/App/Controls/ExtendedTableView.cs index e3fc629c8..550fcad3f 100644 --- a/src/App/Controls/ExtendedTableView.cs +++ b/src/App/Controls/ExtendedTableView.cs @@ -11,6 +11,9 @@ namespace Bit.App.Controls public static readonly BindableProperty EnableSelectionProperty = BindableProperty.Create(nameof(EnableSelection), typeof(bool), typeof(ExtendedTableView), true); + public static readonly BindableProperty SeparatorColorProperty = + BindableProperty.Create(nameof(SeparatorColor), typeof(Color), typeof(ExtendedTableView), Color.FromHex("d2d6de")); + public bool EnableScrolling { get { return (bool)GetValue(EnableScrollingProperty); } @@ -23,6 +26,12 @@ namespace Bit.App.Controls set { SetValue(EnableSelectionProperty, value); } } + public Color SeparatorColor + { + get { return (Color)GetValue(SeparatorColorProperty); } + set { SetValue(SeparatorColorProperty, value); } + } + public int EstimatedRowHeight { get; set; } } } diff --git a/src/App/Controls/LabeledValueCell.cs b/src/App/Controls/LabeledValueCell.cs index 5d1fb11a8..8df2ccc76 100644 --- a/src/App/Controls/LabeledValueCell.cs +++ b/src/App/Controls/LabeledValueCell.cs @@ -9,20 +9,13 @@ namespace Bit.App.Controls { public class LabeledValueCell : ViewCell { - private readonly IUserDialogs _userDialogs; - private readonly IClipboardService _clipboardService; - public LabeledValueCell( - string labelText, + string labelText = null, string valueText = null, - bool copyValue = false, - bool password = false, - bool launch = false) + string button1Text = null, + string button2Text = null) { - _userDialogs = Resolver.Resolve(); - _clipboardService = Resolver.Resolve(); - - var stackLayout = new StackLayout + StackLayout = new StackLayout { Padding = new Thickness(15, 15, 15, 0), BackgroundColor = Color.White @@ -37,7 +30,7 @@ namespace Bit.App.Controls TextColor = Color.FromHex("777777") }; - stackLayout.Children.Add(Label); + StackLayout.Children.Add(Label); } Value = new Label @@ -52,46 +45,42 @@ namespace Bit.App.Controls { Orientation = StackOrientation.Horizontal }; + valueStackLayout.Children.Add(Value); - if(copyValue) + if(button1Text != null) { - var copyButton = new Button + Button1 = new Button { - Text = AppResources.Copy, + Text = button1Text, HorizontalOptions = LayoutOptions.End, - VerticalOptions = LayoutOptions.Center, - Command = new Command(() => Copy()) + VerticalOptions = LayoutOptions.Center }; - valueStackLayout.Children.Add(copyButton); + valueStackLayout.Children.Add(Button1); } - if(launch) + if(button2Text != null) { - var launchButton = new Button + Button2 = new Button { - Text = AppResources.Launch, + Text = button2Text, HorizontalOptions = LayoutOptions.End, - VerticalOptions = LayoutOptions.Center, - Command = new Command(() => Device.OpenUri(new Uri(Value.Text))) + VerticalOptions = LayoutOptions.Center }; - valueStackLayout.Children.Add(launchButton); + valueStackLayout.Children.Add(Button2); } - stackLayout.Children.Add(valueStackLayout); + StackLayout.Children.Add(valueStackLayout); - View = stackLayout; + View = StackLayout; } + public StackLayout StackLayout { get; private set; } public Label Label { get; private set; } public Label Value { get; private set; } - - private void Copy() - { - _clipboardService.CopyToClipboard(Value.Text); - _userDialogs.SuccessToast(string.Format(AppResources.ValueHasBeenCopied, Label.Text)); - } + public Button Button1 { get; private set; } + public Button Button2 { get; private set; } } } diff --git a/src/App/Models/Page/VaultViewSitePageModel.cs b/src/App/Models/Page/VaultViewSitePageModel.cs index 130ffef5a..2e86414ae 100644 --- a/src/App/Models/Page/VaultViewSitePageModel.cs +++ b/src/App/Models/Page/VaultViewSitePageModel.cs @@ -27,6 +27,7 @@ namespace Bit.App.Models.Page PropertyChanged(this, new PropertyChangedEventArgs(nameof(PageTitle))); } } + public string PageTitle => Name ?? AppResources.SiteNoName; public string Username { get { return _username; } @@ -34,8 +35,10 @@ namespace Bit.App.Models.Page { _username = value; PropertyChanged(this, new PropertyChangedEventArgs(nameof(Username))); + PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowUsername))); } } + public bool ShowUsername => !string.IsNullOrWhiteSpace(Username); public string Password { get { return _password; } @@ -53,8 +56,31 @@ namespace Bit.App.Models.Page { _uri = value; PropertyChanged(this, new PropertyChangedEventArgs(nameof(Uri))); + PropertyChanged(this, new PropertyChangedEventArgs(nameof(UriHost))); + PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowUri))); } } + public string UriHost + { + get + { + if(ShowUri) + { + try + { + return new Uri(Uri).Host; + } + catch + { + return Uri; + } + } + + return null; + } + } + + public bool ShowUri => !string.IsNullOrWhiteSpace(Uri); public string Notes { get { return _notes; } @@ -65,7 +91,7 @@ namespace Bit.App.Models.Page PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowNotes))); } } - public string PageTitle => Name ?? AppResources.SiteNoName; + public bool ShowNotes => !string.IsNullOrWhiteSpace(Notes); public bool ShowPassword { get { return _showPassword; } @@ -79,7 +105,6 @@ namespace Bit.App.Models.Page } public string MaskedPassword => ShowPassword ? Password : Password == null ? null : new string('●', Password.Length); public string ShowHideText => ShowPassword ? AppResources.Hide : AppResources.Show; - public bool ShowNotes => !string.IsNullOrWhiteSpace(Notes); public void Update(Site site) { diff --git a/src/App/Pages/VaultAddSitePage.cs b/src/App/Pages/VaultAddSitePage.cs index 351d61eec..313950e7d 100644 --- a/src/App/Pages/VaultAddSitePage.cs +++ b/src/App/Pages/VaultAddSitePage.cs @@ -44,7 +44,7 @@ namespace Bit.App.Pages } var folderCell = new FormPickerCell(AppResources.Folder, folderOptions.ToArray()); - var notesCell = new FormEditorCell(height:90); + var notesCell = new FormEditorCell(height: 90); var mainTable = new ExtendedTableView { @@ -89,9 +89,9 @@ namespace Bit.App.Pages return; } - if(string.IsNullOrWhiteSpace(uriCell.Entry.Text)) + if(string.IsNullOrWhiteSpace(passwordCell.Entry.Text)) { - await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.URI), AppResources.Ok); + await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.Password), AppResources.Ok); return; } @@ -127,7 +127,10 @@ namespace Bit.App.Pages Title = AppResources.AddSite; Content = scrollView; ToolbarItems.Add(saveToolBarItem); - ToolbarItems.Add(new DismissModalToolBarItem(this, "Cancel")); + if(Device.OS == TargetPlatform.iOS) + { + ToolbarItems.Add(new DismissModalToolBarItem(this, "Cancel")); + } if(!_connectivity.IsConnected) { diff --git a/src/App/Pages/VaultEditSitePage.cs b/src/App/Pages/VaultEditSitePage.cs index e1363811e..81215e5fb 100644 --- a/src/App/Pages/VaultEditSitePage.cs +++ b/src/App/Pages/VaultEditSitePage.cs @@ -111,9 +111,9 @@ namespace Bit.App.Pages return; } - if(string.IsNullOrWhiteSpace(uriCell.Entry.Text)) + if(string.IsNullOrWhiteSpace(passwordCell.Entry.Text)) { - await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.URI), AppResources.Ok); + await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.Password), AppResources.Ok); return; } @@ -150,7 +150,10 @@ namespace Bit.App.Pages Title = "Edit Site"; Content = scrollView; ToolbarItems.Add(saveToolBarItem); - ToolbarItems.Add(new DismissModalToolBarItem(this, "Cancel")); + if(Device.OS == TargetPlatform.iOS) + { + ToolbarItems.Add(new DismissModalToolBarItem(this, "Cancel")); + } if(!_connectivity.IsConnected) { diff --git a/src/App/Pages/VaultListPage.cs b/src/App/Pages/VaultListPage.cs index c976a69b2..ac686d6d9 100644 --- a/src/App/Pages/VaultListPage.cs +++ b/src/App/Pages/VaultListPage.cs @@ -35,8 +35,15 @@ namespace Bit.App.Pages { ToolbarItems.Add(new AddSiteToolBarItem(this)); - var listView = new ListView { IsGroupingEnabled = true, ItemsSource = Folders }; + var listView = new ListView + { + IsGroupingEnabled = true, + ItemsSource = Folders, + HasUnevenRows = true, + SeparatorColor = Color.FromHex("E0E0E0") + }; listView.GroupDisplayBinding = new Binding("Name"); + listView.GroupHeaderTemplate = new DataTemplate(() => new VaultListHeaderViewCell(this)); listView.ItemSelected += SiteSelected; listView.ItemTemplate = new DataTemplate(() => new VaultListViewCell(this)); @@ -171,6 +178,53 @@ namespace Bit.App.Pages this.SetBinding(DetailProperty, s => s.Username); ContextActions.Add(moreAction); ContextActions.Add(deleteAction); + + TextColor = Color.FromHex("333333"); + DetailColor = Color.FromHex("777777"); + } + } + + private class VaultListHeaderViewCell : ViewCell + { + public VaultListHeaderViewCell(VaultListPage page) + { + var image = new Image + { + Source = ImageSource.FromFile("fa-folder-open.png"), + Margin = new Thickness(16, 8, 0, 8) + }; + + var label = new Label + { + FontSize = 14, + TextColor = Color.FromHex("777777"), + VerticalTextAlignment = TextAlignment.Center + }; + + label.SetBinding(Label.TextProperty, s => s.Name); + + var stackLayout = new StackLayout + { + Orientation = StackOrientation.Horizontal, + BackgroundColor = Color.FromHex("ecf0f5") + }; + + stackLayout.Children.Add(image); + stackLayout.Children.Add(label); + + var borderStackLayout = new StackLayout + { + Spacing = 0 + }; + + var borderBoxTop = new BoxView { BackgroundColor = Color.FromHex("d2d6de"), HeightRequest = 0.5 }; + var borderBoxBottom = new BoxView { BackgroundColor = Color.FromHex("d2d6de"), HeightRequest = 0.5 }; + borderStackLayout.Children.Add(borderBoxTop); + borderStackLayout.Children.Add(stackLayout); + borderStackLayout.Children.Add(borderBoxBottom); + + View = borderStackLayout; + Height = 30; } } } diff --git a/src/App/Pages/VaultViewSitePage.cs b/src/App/Pages/VaultViewSitePage.cs index f5a5e5f06..d55c01805 100644 --- a/src/App/Pages/VaultViewSitePage.cs +++ b/src/App/Pages/VaultViewSitePage.cs @@ -32,26 +32,34 @@ namespace Bit.App.Pages private void Init() { ToolbarItems.Add(new EditSiteToolBarItem(this, _siteId)); - ToolbarItems.Add(new DismissModalToolBarItem(this)); + if(Device.OS == TargetPlatform.iOS) + { + ToolbarItems.Add(new DismissModalToolBarItem(this)); + } // Username var nameCell = new LabeledValueCell(AppResources.Name); nameCell.Value.SetBinding(Label.TextProperty, s => s.Name); // Username - var usernameCell = new LabeledValueCell(AppResources.Username, copyValue: true); + var usernameCell = new LabeledValueCell(AppResources.Username, button1Text: AppResources.Copy); usernameCell.Value.SetBinding(Label.TextProperty, s => s.Username); + usernameCell.Button1.Command = new Command(() => Copy(Model.Username, AppResources.Username)); // Password - var passwordCell = new LabeledValueCell(AppResources.Password, copyValue: true); - passwordCell.Value.SetBinding(Label.TextProperty, s => s.Password); + var passwordCell = new LabeledValueCell(AppResources.Password, button1Text: AppResources.Show, button2Text: AppResources.Copy); + passwordCell.Value.SetBinding(Label.TextProperty, s => s.MaskedPassword); + passwordCell.Button1.SetBinding(Button.TextProperty, s => s.ShowHideText); + passwordCell.Button1.Command = new Command(() => Model.ShowPassword = !Model.ShowPassword); + passwordCell.Button2.Command = new Command(() => Copy(Model.Password, AppResources.Password)); // URI - var uriCell = new LabeledValueCell(AppResources.URI, launch: true); - uriCell.Value.SetBinding(Label.TextProperty, s => s.Uri); + var uriCell = new LabeledValueCell(AppResources.Website, button1Text: AppResources.Launch); + uriCell.Value.SetBinding(Label.TextProperty, s => s.UriHost); + uriCell.Button1.Command = new Command(() => Device.OpenUri(new Uri(uriCell.Value.Text))); // Notes - var notesCell = new LabeledValueCell(AppResources.Notes); + var notesCell = new LabeledValueCell(); notesCell.Value.SetBinding(Label.TextProperty, s => s.Notes); Table = new ExtendedTableView diff --git a/src/iOS/Controls/ExtendedTableViewRenderer.cs b/src/iOS/Controls/ExtendedTableViewRenderer.cs index 1bb045d75..e5a908567 100644 --- a/src/iOS/Controls/ExtendedTableViewRenderer.cs +++ b/src/iOS/Controls/ExtendedTableViewRenderer.cs @@ -23,6 +23,7 @@ namespace Bit.iOS.Controls SetSelection(view); UpdateRowHeight(view); UpdateEstimatedRowHeight(view); + UpdateSeparatorColor(view); } } @@ -87,5 +88,10 @@ namespace Bit.iOS.Controls Control.EstimatedRowHeight = 0; } } + + private void UpdateSeparatorColor(ExtendedTableView view) + { + Control.SeparatorColor = view.SeparatorColor.ToUIColor(UIColor.Gray); + } } } diff --git a/src/iOS/Resources/fa-folder-open.png b/src/iOS/Resources/fa-folder-open.png new file mode 100644 index 0000000000000000000000000000000000000000..52583578f0e28f0cd37aadcf6330ecab40afae6a GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh3?wzC-F*zCasqrpT!A#*K#9`-RY1#>OM?7@ z85o&ZSlKwZc?6_nRWB+Qj-(2`L-;Z_+3w-E~}KysPb`Vz1`=fJWXXQ5;Q>};OXk;vd$@? F2>@2=Npb)H literal 0 HcmV?d00001 diff --git a/src/iOS/Resources/fa-folder-open@2x.png b/src/iOS/Resources/fa-folder-open@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..38c3cbeee563f9290095c84a887125c2a8f386c0 GIT binary patch literal 456 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s3?yAI>n{URivoN?T!Hi;2MYvMt$vMBBx5PEM~Wi$b^;ga|s-zW;x%M_R&t-`~>( zeBr_CmhGIuU>=evl(^@`8{y=on-@Qx^l#5suD311tU1ymB9km_Snod8)HoU((50UL z|6jnNOY19{JgXGho~HFZo8H4UX_{bdWb%YfT)L6nLK*)({%R!4GFLszQ%(+7y{`Cc u+Siun%Qo#2VcQgEDJlCU{#)SVvO0$PGVeG4;`K5>@!{#}=d#Wzp$P!fAael# literal 0 HcmV?d00001 diff --git a/src/iOS/Resources/fa-folder-open@3x.png b/src/iOS/Resources/fa-folder-open@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..34c69f4c2b7733ea12d586aaa8c42ad1886166b7 GIT binary patch literal 623 zcmeAS@N?(olHy`uVBq!ia0vp^S|H593?x6vT4n;NCjmYou0VR&1F=J&l!2b~E(!7r zW?*DuW?^Mx=iuVz;pO8O5Ec;?6PJ=#P}b7cHM6jHaB}twi-<|g$S&^dpEzaejCqR| zZ`!(R&%T4l&t1KF=iY-y&tANK`|ZUp##U(Af8$E{-7*l6MbY4?7ef;(Bo^ zLs@IY#)QL7vZ5l@j;uHT|F>uJ=rC|QSDWs4Y`VGp7u_E>PU#-4^RM9%|F!*i>c|rlR~J84r6R756PgN2%Nsg` z^4YuX*pBY|RuJ&S%v)nNf6$qxU#sLcga+>lzEb@D@SSFz&?{f97`c5T_oWBCQ0Lz% zJ~Pa5p;ATZ%x#RGyARCt5p@b;wV3p>OD~p5b*7YEY`NT;l9bB%OVrsf`$pbkO`7RG w(@bK=#LV`_)W~^VDn{3HmsZ%_{~}Rde`h~Kr~k(lM?uNP)78&qol`;+0K9IWeE + + + + + + + + +