diff --git a/src/App/Pages/Vault/AddEditPage.xaml b/src/App/Pages/Vault/AddEditPage.xaml index 3ebccdbe9..59d21590d 100644 --- a/src/App/Pages/Vault/AddEditPage.xaml +++ b/src/App/Pages/Vault/AddEditPage.xaml @@ -348,37 +348,35 @@ - - - - - - - - - - - - + + + + + + + + + + @@ -397,6 +395,84 @@ HeightRequest="200" /> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App/Pages/Vault/AddEditPage.xaml.cs b/src/App/Pages/Vault/AddEditPage.xaml.cs index 8c0e614d7..0af305ed6 100644 --- a/src/App/Pages/Vault/AddEditPage.xaml.cs +++ b/src/App/Pages/Vault/AddEditPage.xaml.cs @@ -61,5 +61,10 @@ namespace Bit.App.Pages { _vm.AddUri(); } + + private void NewField_Clicked(object sender, System.EventArgs e) + { + _vm.AddField(); + } } } diff --git a/src/App/Pages/Vault/AddEditPageViewModel.cs b/src/App/Pages/Vault/AddEditPageViewModel.cs index 04a493d6c..a3189b06f 100644 --- a/src/App/Pages/Vault/AddEditPageViewModel.cs +++ b/src/App/Pages/Vault/AddEditPageViewModel.cs @@ -21,7 +21,6 @@ namespace Bit.App.Pages private readonly IAuditService _auditService; private readonly IMessagingService _messagingService; private CipherView _cipher; - private List _fields; private bool _showPassword; private bool _showCardCode; private int _typeSelectedIndex; @@ -47,7 +46,14 @@ namespace Bit.App.Pages new KeyValuePair(UriMatchType.StartsWith, AppResources.StartsWith), new KeyValuePair(UriMatchType.RegularExpression, AppResources.RegEx), new KeyValuePair(UriMatchType.Exact, AppResources.Exact), - new KeyValuePair(UriMatchType.Never, AppResources.Never), + new KeyValuePair(UriMatchType.Never, AppResources.Never) + }; + private List> _fieldTypeOptions = + new List> + { + new KeyValuePair(FieldType.Text, AppResources.FieldTypeText), + new KeyValuePair(FieldType.Hidden, AppResources.FieldTypeHidden), + new KeyValuePair(FieldType.Boolean, AppResources.FieldTypeBoolean) }; public AddEditPageViewModel() @@ -63,7 +69,9 @@ namespace Bit.App.Pages ToggleCardCodeCommand = new Command(ToggleCardCode); CheckPasswordCommand = new Command(CheckPasswordAsync); UriOptionsCommand = new Command(UriOptions); + FieldOptionsCommand = new Command(FieldOptions); Uris = new ExtendedObservableCollection(); + Fields = new ExtendedObservableCollection(); TypeOptions = new List> { @@ -116,6 +124,7 @@ namespace Bit.App.Pages public Command ToggleCardCodeCommand { get; set; } public Command CheckPasswordCommand { get; set; } public Command UriOptionsCommand { get; set; } + public Command FieldOptionsCommand { get; set; } public string CipherId { get; set; } public string OrganizationId { get; set; } public string FolderId { get; set; } @@ -126,6 +135,7 @@ namespace Bit.App.Pages public List> CardExpMonthOptions { get; set; } public List> IdentityTitleOptions { get; set; } public ExtendedObservableCollection Uris { get; set; } + public ExtendedObservableCollection Fields { get; set; } public int TypeSelectedIndex { get => _typeSelectedIndex; @@ -167,11 +177,6 @@ namespace Bit.App.Pages get => _cipher; set => SetProperty(ref _cipher, value, additionalPropertyNames: _additionalCipherProperties); } - public List Fields - { - get => _fields; - set => SetProperty(ref _fields, value); - } public bool ShowPassword { get => _showPassword; @@ -217,7 +222,6 @@ namespace Bit.App.Pages { var cipher = await _cipherService.GetAsync(CipherId); Cipher = await cipher.DecryptAsync(); - Fields = Cipher.Fields?.Select(f => new AddEditPageFieldViewModel(f)).ToList(); if(Cipher.Card != null) { @@ -244,7 +248,7 @@ namespace Bit.App.Pages Identity = new IdentityView(), SecureNote = new SecureNoteView() }; - Cipher.Login.Uris = new List(); + Cipher.Login.Uris = new List { new LoginUriView() }; Cipher.SecureNote.Type = SecureNoteType.Generic; TypeSelectedIndex = TypeOptions.FindIndex(k => k.Value == Cipher.Type); @@ -258,6 +262,10 @@ namespace Bit.App.Pages { Uris.ResetWithRange(Cipher.Login.Uris); } + if(Cipher.Fields != null) + { + Fields.ResetWithRange(Cipher.Fields?.Select(f => new AddEditPageFieldViewModel(f))); + } } public async Task SubmitAsync() @@ -270,6 +278,7 @@ namespace Bit.App.Pages return false; } + Cipher.Fields = Fields.Any() ? Fields.Select(f => f.Field).ToList() : null; Cipher.Login.Uris = Uris.ToList(); if(!EditMode && Cipher.Type == CipherType.Login && (Cipher.Login.Uris?.Count ?? 0) == 1 && string.IsNullOrWhiteSpace(Cipher.Login.Uris.First().Uri)) @@ -371,6 +380,61 @@ namespace Bit.App.Pages Uris.Add(new LoginUriView()); } + public async void FieldOptions(AddEditPageFieldViewModel field) + { + if(!(Page as AddEditPage).DoOnce()) + { + return; + } + var selection = await Page.DisplayActionSheet(AppResources.Options, AppResources.Cancel, null, + AppResources.Edit, AppResources.MoveUp, AppResources.MoveDown, AppResources.Remove); + if(selection == AppResources.Remove) + { + Fields.Remove(field); + } + else if(selection == AppResources.Edit) + { + var name = "new name"; + // TODO: prompt for name + field.Field.Name = name; + field.TriggerFieldChanged(); + } + else if(selection == AppResources.MoveUp) + { + var currentIndex = Fields.IndexOf(field); + if(currentIndex > 0) + { + Fields.Move(currentIndex, currentIndex - 1); + } + } + else if(selection == AppResources.MoveDown) + { + var currentIndex = Fields.IndexOf(field); + if(currentIndex < Fields.Count - 1) + { + Fields.Move(currentIndex, currentIndex + 1); + } + } + } + + public async void AddField() + { + var typeSelection = await Page.DisplayActionSheet(AppResources.SelectTypeField, AppResources.Cancel, null, + _fieldTypeOptions.Select(f => f.Value).ToArray()); + if(typeSelection != null && typeSelection != AppResources.Cancel) + { + var name = "new field name"; + // TODO: prompt for name + + if(Fields == null) + { + Fields = new ExtendedObservableCollection(); + } + var type = _fieldTypeOptions.FirstOrDefault(f => f.Value == typeSelection).Key; + Fields.Add(new AddEditPageFieldViewModel(new FieldView { Type = type, Name = name })); + } + } + public void TogglePassword() { ShowPassword = !ShowPassword; @@ -448,25 +512,25 @@ namespace Bit.App.Pages { private FieldView _field; private bool _showHiddenValue; + private bool _booleanValue; + private string[] _additionalFieldProperties = new string[] + { + nameof(IsBooleanType), + nameof(IsHiddenType), + nameof(IsTextType), + }; public AddEditPageFieldViewModel(FieldView field) { Field = field; ToggleHiddenValueCommand = new Command(ToggleHiddenValue); + BooleanValue = IsBooleanType && field.Value == "true"; } public FieldView Field { get => _field; - set => SetProperty(ref _field, value, - additionalPropertyNames: new string[] - { - nameof(ValueText), - nameof(IsBooleanType), - nameof(IsHiddenType), - nameof(IsTextType), - nameof(ShowCopyButton), - }); + set => SetProperty(ref _field, value, additionalPropertyNames: _additionalFieldProperties); } public bool ShowHiddenValue @@ -479,19 +543,31 @@ namespace Bit.App.Pages }); } - public Command ToggleHiddenValueCommand { get; set; } + public bool BooleanValue + { + get => _booleanValue; + set + { + SetProperty(ref _booleanValue, value); + Field.Value = value ? "true" : "false"; + } + } - public string ValueText => IsBooleanType ? (_field.Value == "true" ? "" : "") : _field.Value; + public Command ToggleHiddenValueCommand { get; set; } + public string ShowHiddenValueIcon => _showHiddenValue ? "" : ""; - public bool IsTextType => _field.Type == Core.Enums.FieldType.Text; - public bool IsBooleanType => _field.Type == Core.Enums.FieldType.Boolean; - public bool IsHiddenType => _field.Type == Core.Enums.FieldType.Hidden; - public bool ShowCopyButton => _field.Type != Core.Enums.FieldType.Boolean && - !string.IsNullOrWhiteSpace(_field.Value); + public bool IsTextType => _field.Type == FieldType.Text; + public bool IsBooleanType => _field.Type == FieldType.Boolean; + public bool IsHiddenType => _field.Type == FieldType.Hidden; public void ToggleHiddenValue() { ShowHiddenValue = !ShowHiddenValue; } + + public void TriggerFieldChanged() + { + TriggerPropertyChanged(nameof(Field), _additionalFieldProperties); + } } } diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs index 27305fecd..013fff196 100644 --- a/src/App/Resources/AppResources.Designer.cs +++ b/src/App/Resources/AppResources.Designer.cs @@ -2292,6 +2292,24 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Move Down. + /// + public static string MoveDown { + get { + return ResourceManager.GetString("MoveDown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move Up. + /// + public static string MoveUp { + get { + return ResourceManager.GetString("MoveUp", resourceCulture); + } + } + /// /// Looks up a localized string similar to Mr. /// diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx index be7a43a00..9f1a16291 100644 --- a/src/App/Resources/AppResources.resx +++ b/src/App/Resources/AppResources.resx @@ -1411,4 +1411,10 @@ Type + + Move Down + + + Move Up + \ No newline at end of file