Vault add/edit/view site updates to table section/cell display.

This commit is contained in:
Kyle Spearrin 2016-06-13 20:03:16 -04:00
parent baeee00a8d
commit 8108f4023a
9 changed files with 101 additions and 49 deletions

View file

@ -20,7 +20,7 @@ namespace Bit.App.Controls
var stackLayout = new StackLayout var stackLayout = new StackLayout
{ {
Padding = new Thickness(15) Padding = new Thickness(15, 10)
}; };
stackLayout.Children.Add(Editor); stackLayout.Children.Add(Editor);

View file

@ -32,7 +32,7 @@ namespace Bit.App.Controls
var stackLayout = new StackLayout var stackLayout = new StackLayout
{ {
Padding = new Thickness(15) Padding = new Thickness(15, 10)
}; };
stackLayout.Children.Add(Label); stackLayout.Children.Add(Label);

View file

@ -30,7 +30,7 @@ namespace Bit.App.Controls
var stackLayout = new StackLayout var stackLayout = new StackLayout
{ {
Padding = new Thickness(15) Padding = new Thickness(15, 10)
}; };
stackLayout.Children.Add(Label); stackLayout.Children.Add(Label);

View file

@ -12,7 +12,7 @@ namespace Bit.App.Controls
{ {
var containerStackLayout = new StackLayout var containerStackLayout = new StackLayout
{ {
Padding = new Thickness(15), Padding = new Thickness(15, 10),
Orientation = StackOrientation.Horizontal Orientation = StackOrientation.Horizontal
}; };
@ -58,7 +58,8 @@ namespace Bit.App.Controls
{ {
Text = button1Text, Text = button1Text,
HorizontalOptions = LayoutOptions.End, HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.Center VerticalOptions = LayoutOptions.Center,
Margin = new Thickness(0)
}; };
buttonStackLayout.Children.Add(Button1); buttonStackLayout.Children.Add(Button1);
@ -70,7 +71,8 @@ namespace Bit.App.Controls
{ {
Text = button2Text, Text = button2Text,
HorizontalOptions = LayoutOptions.End, HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.Center VerticalOptions = LayoutOptions.Center,
Margin = new Thickness(0)
}; };
buttonStackLayout.Children.Add(Button2); buttonStackLayout.Children.Add(Button2);

View file

@ -11,7 +11,7 @@ namespace Bit.App.Models.Page
private string _password; private string _password;
private string _uri; private string _uri;
private string _notes; private string _notes;
private bool _showPassword; private bool _revealPassword;
public VaultViewSitePageModel() { } public VaultViewSitePageModel() { }
@ -37,6 +37,7 @@ namespace Bit.App.Models.Page
} }
} }
public bool ShowUsername => !string.IsNullOrWhiteSpace(Username); public bool ShowUsername => !string.IsNullOrWhiteSpace(Username);
public string Password public string Password
{ {
get { return _password; } get { return _password; }
@ -47,6 +48,8 @@ namespace Bit.App.Models.Page
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword))); PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
} }
} }
public bool ShowPassword => !string.IsNullOrWhiteSpace(Password);
public string Uri public string Uri
{ {
get { return _uri; } get { return _uri; }
@ -58,6 +61,8 @@ namespace Bit.App.Models.Page
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowUri))); PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowUri)));
} }
} }
public bool ShowUri => !string.IsNullOrWhiteSpace(Uri);
public string UriHost public string UriHost
{ {
get get
@ -78,7 +83,6 @@ namespace Bit.App.Models.Page
} }
} }
public bool ShowUri => !string.IsNullOrWhiteSpace(Uri);
public string Notes public string Notes
{ {
get { return _notes; } get { return _notes; }
@ -90,19 +94,19 @@ namespace Bit.App.Models.Page
} }
} }
public bool ShowNotes => !string.IsNullOrWhiteSpace(Notes); public bool ShowNotes => !string.IsNullOrWhiteSpace(Notes);
public bool ShowPassword public bool RevealPassword
{ {
get { return _showPassword; } get { return _revealPassword; }
set set
{ {
_showPassword = value; _revealPassword = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowPassword))); PropertyChanged(this, new PropertyChangedEventArgs(nameof(RevealPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword))); PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideText))); PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideText)));
} }
} }
public string MaskedPassword => ShowPassword ? Password : Password == null ? null : new string('●', Password.Length); public string MaskedPassword => RevealPassword ? Password : Password == null ? null : new string('●', Password.Length);
public string ShowHideText => ShowPassword ? AppResources.Hide : AppResources.Show; public string ShowHideText => RevealPassword ? AppResources.Hide : AppResources.Show;
public void Update(Site site) public void Update(Site site)
{ {

View file

@ -36,6 +36,9 @@ namespace Bit.App.Pages
var usernameCell = new FormEntryCell(AppResources.Username, nextElement: passwordCell.Entry); var usernameCell = new FormEntryCell(AppResources.Username, nextElement: passwordCell.Entry);
usernameCell.Entry.DisableAutocapitalize = true; usernameCell.Entry.DisableAutocapitalize = true;
usernameCell.Entry.Autocorrect = false; usernameCell.Entry.Autocorrect = false;
usernameCell.Entry.FontFamily = passwordCell.Entry.FontFamily = "Courier";
var uriCell = new FormEntryCell(AppResources.URI, Keyboard.Url, nextElement: usernameCell.Entry); var uriCell = new FormEntryCell(AppResources.URI, Keyboard.Url, nextElement: usernameCell.Entry);
var nameCell = new FormEntryCell(AppResources.Name, nextElement: uriCell.Entry); var nameCell = new FormEntryCell(AppResources.Name, nextElement: uriCell.Entry);

View file

@ -47,6 +47,9 @@ namespace Bit.App.Pages
usernameCell.Entry.Text = site.Username?.Decrypt(); usernameCell.Entry.Text = site.Username?.Decrypt();
usernameCell.Entry.DisableAutocapitalize = true; usernameCell.Entry.DisableAutocapitalize = true;
usernameCell.Entry.Autocorrect = false; usernameCell.Entry.Autocorrect = false;
usernameCell.Entry.FontFamily = passwordCell.Entry.FontFamily = "Courier";
var uriCell = new FormEntryCell(AppResources.URI, Keyboard.Url, nextElement: usernameCell.Entry); var uriCell = new FormEntryCell(AppResources.URI, Keyboard.Url, nextElement: usernameCell.Entry);
uriCell.Entry.Text = site.Uri?.Decrypt(); uriCell.Entry.Text = site.Uri?.Decrypt();
var nameCell = new FormEntryCell(AppResources.Name, nextElement: uriCell.Entry); var nameCell = new FormEntryCell(AppResources.Name, nextElement: uriCell.Entry);

View file

@ -28,6 +28,11 @@ namespace Bit.App.Pages
private VaultViewSitePageModel Model { get; set; } = new VaultViewSitePageModel(); private VaultViewSitePageModel Model { get; set; } = new VaultViewSitePageModel();
private ExtendedTableView Table { get; set; } private ExtendedTableView Table { get; set; }
private TableSection SiteInformationSection { get; set; }
private TableSection NotesSection { get; set; }
public LabeledValueCell UsernameCell { get; set; }
public LabeledValueCell PasswordCell { get; set; }
public LabeledValueCell UriCell { get; set; }
private void Init() private void Init()
{ {
@ -42,30 +47,39 @@ namespace Bit.App.Pages
nameCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.Name); nameCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.Name);
// Username // Username
var usernameCell = new LabeledValueCell(AppResources.Username, button1Text: AppResources.Copy); UsernameCell = new LabeledValueCell(AppResources.Username, button1Text: AppResources.Copy);
usernameCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.Username); UsernameCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.Username);
usernameCell.Button1.Command = new Command(() => Copy(Model.Username, AppResources.Username)); UsernameCell.Button1.Command = new Command(() => Copy(Model.Username, AppResources.Username));
usernameCell.View.SetBinding<VaultViewSitePageModel>(IsVisibleProperty, s => s.ShowUsername);
// Password // Password
var passwordCell = new LabeledValueCell(AppResources.Password, button1Text: AppResources.Show, button2Text: AppResources.Copy); PasswordCell = new LabeledValueCell(AppResources.Password, button1Text: AppResources.Show, button2Text: AppResources.Copy);
passwordCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.MaskedPassword); PasswordCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.MaskedPassword);
passwordCell.Button1.SetBinding<VaultViewSitePageModel>(Button.TextProperty, s => s.ShowHideText); PasswordCell.Button1.SetBinding<VaultViewSitePageModel>(Button.TextProperty, s => s.ShowHideText);
passwordCell.Button1.Command = new Command(() => Model.ShowPassword = !Model.ShowPassword); PasswordCell.Button1.Command = new Command(() => Model.RevealPassword = !Model.RevealPassword);
passwordCell.Button2.Command = new Command(() => Copy(Model.Password, AppResources.Password)); PasswordCell.Button2.Command = new Command(() => Copy(Model.Password, AppResources.Password));
UsernameCell.Value.FontFamily = PasswordCell.Value.FontFamily = "Courier";
// URI // URI
var uriCell = new LabeledValueCell(AppResources.Website, button1Text: AppResources.Launch); UriCell = new LabeledValueCell(AppResources.Website, button1Text: AppResources.Launch);
uriCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.UriHost); UriCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.UriHost);
uriCell.Button1.Command = new Command(() => Device.OpenUri(new Uri(Model.Uri))); UriCell.Button1.Command = new Command(() => Device.OpenUri(new Uri(Model.Uri)));
uriCell.View.SetBinding<VaultViewSitePageModel>(IsVisibleProperty, s => s.ShowUri);
// Notes // Notes
var notesCell = new LabeledValueCell(); var notesCell = new LabeledValueCell();
notesCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.Notes); notesCell.Value.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.Notes);
notesCell.View.SetBinding<VaultViewSitePageModel>(IsVisibleProperty, s => s.ShowNotes);
notesCell.Value.LineBreakMode = LineBreakMode.WordWrap; notesCell.Value.LineBreakMode = LineBreakMode.WordWrap;
SiteInformationSection = new TableSection("Site Information")
{
nameCell
};
NotesSection = new TableSection(AppResources.Notes)
{
notesCell
};
Table = new ExtendedTableView Table = new ExtendedTableView
{ {
Intent = TableIntent.Settings, Intent = TableIntent.Settings,
@ -74,17 +88,8 @@ namespace Bit.App.Pages
EnableSelection = false, EnableSelection = false,
Root = new TableRoot Root = new TableRoot
{ {
new TableSection("Site Information") SiteInformationSection,
{ NotesSection
nameCell,
uriCell,
usernameCell,
passwordCell
},
new TableSection(AppResources.Notes)
{
notesCell
}
} }
}; };
@ -110,11 +115,43 @@ namespace Bit.App.Pages
Model.Update(site); Model.Update(site);
base.OnAppearing(); if(!Model.ShowUri)
{
SiteInformationSection.Remove(UriCell);
}
else if(!SiteInformationSection.Contains(UriCell))
{
SiteInformationSection.Add(UriCell);
}
// Hack to get table row height binding to update. Better way to do this probably? if(!Model.ShowUsername)
Table.Root.Add(new TableSection { new TextCell() }); {
Table.Root.RemoveAt(Table.Root.Count - 1); SiteInformationSection.Remove(UsernameCell);
}
else if(!SiteInformationSection.Contains(UsernameCell))
{
SiteInformationSection.Add(UsernameCell);
}
if(!Model.ShowPassword)
{
SiteInformationSection.Remove(PasswordCell);
}
else if(!SiteInformationSection.Contains(PasswordCell))
{
SiteInformationSection.Add(PasswordCell);
}
if(!Model.ShowNotes)
{
Table.Root.Remove(NotesSection);
}
else if(!Table.Root.Contains(NotesSection))
{
Table.Root.Add(NotesSection);
}
base.OnAppearing();
} }
private void Copy(string copyText, string alertLabel) private void Copy(string copyText, string alertLabel)

View file

@ -26,11 +26,13 @@ namespace Bit.App.Repositories
public async Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response) public async Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response)
{ {
try try
{
var errors = new List<ApiError>();
if(response.StatusCode == System.Net.HttpStatusCode.BadRequest)
{ {
var responseContent = await response.Content.ReadAsStringAsync(); var responseContent = await response.Content.ReadAsStringAsync();
var errorResponseModel = JsonConvert.DeserializeObject<ErrorResponse>(responseContent); var errorResponseModel = JsonConvert.DeserializeObject<ErrorResponse>(responseContent);
var errors = new List<ApiError>();
foreach(var valError in errorResponseModel.ValidationErrors) foreach(var valError in errorResponseModel.ValidationErrors)
{ {
foreach(var errorMessage in valError.Value) foreach(var errorMessage in valError.Value)
@ -38,6 +40,7 @@ namespace Bit.App.Repositories
errors.Add(new ApiError { Message = errorMessage }); errors.Add(new ApiError { Message = errorMessage });
} }
} }
}
return ApiResult<T>.Failed(response.StatusCode, errors.ToArray()); return ApiResult<T>.Failed(response.StatusCode, errors.ToArray());
} }