1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-04 09:33:16 +00:00

add/edit/delete custom fields. remove field page.

This commit is contained in:
Kyle Spearrin
2018-03-05 15:15:20 -05:00
parent c3f4d56d1e
commit 1f21a2ecc7
14 changed files with 459 additions and 304 deletions

View File

@@ -71,9 +71,12 @@ namespace Bit.App.Pages
SliderCell = new SliderViewCell(this, _passwordGenerationService, _settings);
var buttonColor = Color.FromHex("3c8dbc");
RegenerateCell = new ExtendedTextCell { Text = AppResources.RegeneratePassword, TextColor = buttonColor };
CopyCell = new ExtendedTextCell { Text = AppResources.CopyPassword, TextColor = buttonColor };
RegenerateCell = new ExtendedTextCell
{
Text = AppResources.RegeneratePassword,
TextColor = Colors.Primary
};
CopyCell = new ExtendedTextCell { Text = AppResources.CopyPassword, TextColor = Colors.Primary };
UppercaseCell = new ExtendedSwitchCell
{

View File

@@ -86,12 +86,14 @@ namespace Bit.App.Pages
public TableRoot TableRoot { get; set; }
public TableSection TopSection { get; set; }
public TableSection MiddleSection { get; set; }
public TableSection FieldsSection { get; set; }
public ExtendedTableView Table { get; set; }
public FormEntryCell NameCell { get; private set; }
public FormEditorCell NotesCell { get; private set; }
public FormPickerCell FolderCell { get; private set; }
public ExtendedSwitchCell FavoriteCell { get; set; }
public ExtendedTextCell AddFieldCell { get; private set; }
// Login
public FormEntryCell LoginPasswordCell { get; private set; }
@@ -184,6 +186,11 @@ namespace Bit.App.Pages
NotesCell.InitEvents();
FolderCell.InitEvents();
if(AddFieldCell != null)
{
AddFieldCell.Tapped += AddFieldCell_Tapped;
}
switch(_type)
{
case CipherType.Login:
@@ -256,6 +263,11 @@ namespace Bit.App.Pages
NotesCell.Dispose();
FolderCell.Dispose();
if(AddFieldCell != null)
{
AddFieldCell.Tapped -= AddFieldCell_Tapped;
}
switch(_type)
{
case CipherType.Login:
@@ -301,6 +313,17 @@ namespace Bit.App.Pages
default:
break;
}
if(FieldsSection != null && FieldsSection.Count > 0)
{
foreach(var cell in FieldsSection)
{
if(cell is FormEntryCell entrycell)
{
entrycell.Dispose();
}
}
}
}
protected override bool OnBackButtonPressed()
@@ -540,6 +563,14 @@ namespace Bit.App.Pages
NameCell.NextElement = NotesCell.Editor;
}
FieldsSection = new TableSection(AppResources.CustomFields);
AddFieldCell = new ExtendedTextCell
{
Text = AppResources.NewCustomField,
TextColor = Colors.Primary
};
FieldsSection.Add(AddFieldCell);
// Make table
TableRoot = new TableRoot
{
@@ -548,7 +579,8 @@ namespace Bit.App.Pages
new TableSection(AppResources.Notes)
{
NotesCell
}
},
FieldsSection
};
Table = new ExtendedTableView
@@ -744,6 +776,8 @@ namespace Bit.App.Pages
cipher.FolderId = Folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id;
}
Helpers.ProcessFieldsSectionForSave(FieldsSection, cipher);
_deviceActionService.ShowLoading(AppResources.Saving);
var saveTask = await _cipherService.SaveAsync(cipher);
_deviceActionService.HideLoading();
@@ -782,6 +816,10 @@ namespace Bit.App.Pages
ToolbarItems.Add(saveToolBarItem);
}
private async void AddFieldCell_Tapped(object sender, EventArgs e)
{
await Helpers.AddField(this, FieldsSection);
}
}
}

View File

@@ -1,251 +0,0 @@
using System;
using System.Linq;
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Resources;
using Xamarin.Forms;
using XLabs.Ioc;
using Bit.App.Utilities;
using Plugin.Connectivity.Abstractions;
using Bit.App.Models;
using Bit.App.Enums;
using System.Collections.Generic;
namespace Bit.App.Pages
{
public class VaultCustomFieldsPage : ExtendedContentPage
{
private readonly ICipherService _cipherService;
private readonly IDeviceActionService _deviceActionService;
private readonly IConnectivity _connectivity;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly string _cipherId;
private Cipher _cipher;
private DateTime? _lastAction;
public VaultCustomFieldsPage(string cipherId)
: base(true)
{
_cipherId = cipherId;
_cipherService = Resolver.Resolve<ICipherService>();
_connectivity = Resolver.Resolve<IConnectivity>();
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
}
public ToolbarItem SaveToolbarItem { get; set; }
public ToolbarItem CloseToolbarItem { get; set; }
public Label NoDataLabel { get; set; }
public TableSection FieldsSection { get; set; }
public ExtendedTableView Table { get; set; }
private void Init()
{
FieldsSection = new TableSection(Helpers.GetEmptyTableSectionTitle());
Table = new ExtendedTableView
{
Intent = TableIntent.Settings,
EnableScrolling = true,
HasUnevenRows = true,
Root = new TableRoot
{
FieldsSection
}
};
NoDataLabel = new Label
{
Text = AppResources.NoCustomFields,
HorizontalTextAlignment = TextAlignment.Center,
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
Margin = new Thickness(10, 40, 10, 0)
};
SaveToolbarItem = new ToolbarItem(AppResources.Save, Helpers.ToolbarImage("envelope.png"), async () =>
{
if(_lastAction.LastActionWasRecent() || _cipher == null)
{
return;
}
_lastAction = DateTime.UtcNow;
if(!_connectivity.IsConnected)
{
AlertNoConnection();
return;
}
if(FieldsSection.Count > 0)
{
var fields = new List<Field>();
foreach(var cell in FieldsSection)
{
if(cell is FormEntryCell entryCell)
{
fields.Add(new Field
{
Name = string.IsNullOrWhiteSpace(entryCell.Label.Text) ? null :
entryCell.Label.Text.Encrypt(_cipher.OrganizationId),
Value = string.IsNullOrWhiteSpace(entryCell.Entry.Text) ? null :
entryCell.Entry.Text.Encrypt(_cipher.OrganizationId),
Type = entryCell.Entry.IsPassword ? FieldType.Hidden : FieldType.Text
});
}
else if(cell is ExtendedSwitchCell switchCell)
{
var value = switchCell.On ? "true" : "false";
fields.Add(new Field
{
Name = string.IsNullOrWhiteSpace(switchCell.Text) ? null :
switchCell.Text.Encrypt(_cipher.OrganizationId),
Value = value.Encrypt(_cipher.OrganizationId),
Type = FieldType.Boolean
});
}
}
_cipher.Fields = fields;
}
else
{
_cipher.Fields = null;
}
_deviceActionService.ShowLoading(AppResources.Saving);
var saveTask = await _cipherService.SaveAsync(_cipher);
_deviceActionService.HideLoading();
if(saveTask.Succeeded)
{
_deviceActionService.Toast(AppResources.CustomFieldsUpdated);
_googleAnalyticsService.TrackAppEvent("UpdatedCustomFields");
await Navigation.PopForDeviceAsync();
}
else if(saveTask.Errors.Count() > 0)
{
await DisplayAlert(AppResources.AnErrorHasOccurred, saveTask.Errors.First().Message, AppResources.Ok);
}
else
{
await DisplayAlert(null, AppResources.AnErrorHasOccurred, AppResources.Ok);
}
}, ToolbarItemOrder.Default, 0);
ToolbarItems.Add(SaveToolbarItem);
Title = AppResources.CustomFields;
Content = Table;
if(Device.RuntimePlatform == Device.iOS)
{
CloseToolbarItem = new DismissModalToolBarItem(this, AppResources.Close);
ToolbarItems.Add(CloseToolbarItem);
Table.RowHeight = -1;
Table.EstimatedRowHeight = 44;
}
else if(Device.RuntimePlatform == Device.Android)
{
Table.BottomPadding = 50;
}
}
protected async override void OnAppearing()
{
base.OnAppearing();
_cipher = await _cipherService.GetByIdAsync(_cipherId);
if(_cipher == null)
{
await Navigation.PopForDeviceAsync();
return;
}
var hasFields = _cipher.Fields?.Any() ?? false;
if(hasFields)
{
Content = Table;
if(CloseToolbarItem != null)
{
CloseToolbarItem.Text = AppResources.Cancel;
}
foreach(var field in _cipher.Fields)
{
var label = field.Name?.Decrypt(_cipher.OrganizationId) ?? string.Empty;
var value = field.Value?.Decrypt(_cipher.OrganizationId);
switch(field.Type)
{
case FieldType.Text:
case FieldType.Hidden:
var hidden = field.Type == FieldType.Hidden;
var textFieldCell = new FormEntryCell(label, isPassword: hidden, useButton: hidden);
textFieldCell.Entry.Text = value;
textFieldCell.Entry.DisableAutocapitalize = true;
textFieldCell.Entry.Autocorrect = false;
if(hidden)
{
textFieldCell.Entry.FontFamily = Helpers.OnPlatform(
iOS: "Menlo-Regular", Android: "monospace", Windows: "Courier");
textFieldCell.Button.Image = "eye.png";
textFieldCell.Button.Command = new Command(() =>
{
textFieldCell.Entry.InvokeToggleIsPassword();
textFieldCell.Button.Image =
"eye" + (!textFieldCell.Entry.IsPasswordFromToggled ? "_slash" : string.Empty) + ".png";
});
}
textFieldCell.InitEvents();
FieldsSection.Add(textFieldCell);
break;
case FieldType.Boolean:
var switchFieldCell = new ExtendedSwitchCell
{
Text = label,
On = value == "true"
};
FieldsSection.Add(switchFieldCell);
break;
default:
continue;
}
}
}
else
{
Content = NoDataLabel;
if(ToolbarItems.Count > 0)
{
ToolbarItems.RemoveAt(0);
}
}
}
protected override void OnDisappearing()
{
base.OnDisappearing();
if(FieldsSection != null && FieldsSection.Count > 0)
{
foreach(var cell in FieldsSection)
{
if(cell is FormEntryCell entrycell)
{
entrycell.Dispose();
}
}
}
}
private void AlertNoConnection()
{
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage,
AppResources.Ok);
}
}
}

View File

@@ -42,6 +42,7 @@ namespace Bit.App.Pages
public TableRoot TableRoot { get; set; }
public TableSection TopSection { get; set; }
public TableSection MiddleSection { get; set; }
public TableSection FieldsSection { get; set; }
public ExtendedTableView Table { get; set; }
public FormEntryCell NameCell { get; private set; }
@@ -49,8 +50,8 @@ namespace Bit.App.Pages
public FormPickerCell FolderCell { get; private set; }
public ExtendedSwitchCell FavoriteCell { get; set; }
public ExtendedTextCell AttachmentsCell { get; private set; }
public ExtendedTextCell CustomFieldsCell { get; private set; }
public ExtendedTextCell DeleteCell { get; private set; }
public ExtendedTextCell AddFieldCell { get; private set; }
// Login
public FormEntryCell LoginPasswordCell { get; private set; }
@@ -152,12 +153,6 @@ namespace Bit.App.Pages
ShowDisclousure = true
};
CustomFieldsCell = new ExtendedTextCell
{
Text = AppResources.CustomFields,
ShowDisclousure = true
};
// Sections
TopSection = new TableSection(AppResources.ItemInformation)
{
@@ -168,8 +163,7 @@ namespace Bit.App.Pages
{
FolderCell,
FavoriteCell,
AttachmentsCell,
CustomFieldsCell
AttachmentsCell
};
// Types
@@ -405,6 +399,27 @@ namespace Bit.App.Pages
NameCell.NextElement = NotesCell.Editor;
}
FieldsSection = new TableSection(AppResources.CustomFields);
if(Cipher.Fields != null)
{
foreach(var field in Cipher.Fields)
{
var label = field.Name?.Decrypt(Cipher.OrganizationId) ?? string.Empty;
var value = field.Value?.Decrypt(Cipher.OrganizationId);
var cell = Helpers.MakeFieldCell(field.Type, label, value, FieldsSection);
if(cell != null)
{
FieldsSection.Add(cell);
}
}
}
AddFieldCell = new ExtendedTextCell
{
Text = AppResources.NewCustomField,
TextColor = Colors.Primary
};
FieldsSection.Add(AddFieldCell);
// Make table
TableRoot = new TableRoot
{
@@ -414,6 +429,7 @@ namespace Bit.App.Pages
{
NotesCell
},
FieldsSection,
new TableSection(Helpers.GetEmptyTableSectionTitle())
{
DeleteCell
@@ -614,6 +630,8 @@ namespace Bit.App.Pages
Cipher.FolderId = null;
}
Helpers.ProcessFieldsSectionForSave(FieldsSection, Cipher);
_deviceActionService.ShowLoading(AppResources.Saving);
var saveTask = await _cipherService.SaveAsync(Cipher);
_deviceActionService.HideLoading();
@@ -653,14 +671,14 @@ namespace Bit.App.Pages
{
AttachmentsCell.Tapped += AttachmentsCell_Tapped;
}
if(CustomFieldsCell != null)
{
CustomFieldsCell.Tapped += CustomFieldsCell_Tapped;
}
if(DeleteCell != null)
{
DeleteCell.Tapped += DeleteCell_Tapped;
}
if(AddFieldCell != null)
{
AddFieldCell.Tapped += AddFieldCell_Tapped;
}
switch(Cipher.Type)
{
@@ -713,6 +731,17 @@ namespace Bit.App.Pages
default:
break;
}
if(FieldsSection != null && FieldsSection.Count > 0)
{
foreach(var cell in FieldsSection)
{
if(cell is FormEntryCell entrycell)
{
entrycell.InitEvents();
}
}
}
}
protected override void OnDisappearing()
@@ -727,14 +756,14 @@ namespace Bit.App.Pages
{
AttachmentsCell.Tapped -= AttachmentsCell_Tapped;
}
if(CustomFieldsCell != null)
{
CustomFieldsCell.Tapped -= CustomFieldsCell_Tapped;
}
if(DeleteCell != null)
{
DeleteCell.Tapped -= DeleteCell_Tapped;
}
if(AddFieldCell != null)
{
AddFieldCell.Tapped -= AddFieldCell_Tapped;
}
switch(Cipher.Type)
{
@@ -787,6 +816,17 @@ namespace Bit.App.Pages
default:
break;
}
if(FieldsSection != null && FieldsSection.Count > 0)
{
foreach(var cell in FieldsSection)
{
if(cell is FormEntryCell entrycell)
{
entrycell.Dispose();
}
}
}
}
private void PasswordButton_Clicked(object sender, EventArgs e)
@@ -840,12 +880,6 @@ namespace Bit.App.Pages
await Navigation.PushModalAsync(page);
}
private async void CustomFieldsCell_Tapped(object sender, EventArgs e)
{
var page = new ExtendedNavigationPage(new VaultCustomFieldsPage(_cipherId));
await Navigation.PushModalAsync(page);
}
private async void DeleteCell_Tapped(object sender, EventArgs e)
{
if(!_connectivity.IsConnected)
@@ -881,6 +915,11 @@ namespace Bit.App.Pages
}
}
private async void AddFieldCell_Tapped(object sender, EventArgs e)
{
await Helpers.AddField(this, FieldsSection);
}
private void AlertNoConnection()
{
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage,