Wired up view page functionality. Expanded LabeledValueCell. Created custom group template for vault list page.

This commit is contained in:
Kyle Spearrin 2016-05-14 01:34:42 -04:00
parent d288116b39
commit 4e906f9370
12 changed files with 155 additions and 49 deletions

View file

@ -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; }
}
}

View file

@ -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<IUserDialogs>();
_clipboardService = Resolver.Resolve<IClipboardService>();
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; }
}
}

View file

@ -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)
{

View file

@ -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)
{

View file

@ -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)
{

View file

@ -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<VaultListPageModel.Site>(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<VaultListPageModel.Folder>(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;
}
}
}

View file

@ -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<VaultViewSitePageModel>(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<VaultViewSitePageModel>(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<VaultViewSitePageModel>(Label.TextProperty, s => s.Password);
var passwordCell = new LabeledValueCell(AppResources.Password, button1Text: AppResources.Show, button2Text: AppResources.Copy);
passwordCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.MaskedPassword);
passwordCell.Button1.SetBinding<VaultViewSitePageModel>(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<VaultViewSitePageModel>(Label.TextProperty, s => s.Uri);
var uriCell = new LabeledValueCell(AppResources.Website, button1Text: AppResources.Launch);
uriCell.Value.SetBinding<VaultViewSitePageModel>(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<VaultViewSitePageModel>(Label.TextProperty, s => s.Notes);
Table = new ExtendedTableView

View file

@ -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);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

View file

@ -330,6 +330,15 @@
<ItemGroup>
<ITunesArtwork Include="Resources\iTunesArtwork%402x.png" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\fa-folder-open.png" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\fa-folder-open%402x.png" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\fa-folder-open%403x.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>