From 36fb23d4677ac984269b1639e074a2802077cab2 Mon Sep 17 00:00:00 2001 From: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com> Date: Tue, 18 Feb 2020 15:48:23 -0600 Subject: [PATCH] Add ability to clone personal vault items (#734) * Add clone ability to personal vault items * Fixed formatter * Made requested changes and removed some extra whitespace added by Rider formatter * Removed formatting on AppResources file * Fixed casing on UpdateCipherId method * Update calling method --- src/App/Pages/Vault/AddEditPage.xaml | 4 +- src/App/Pages/Vault/AddEditPage.xaml.cs | 16 +- src/App/Pages/Vault/AddEditPageViewModel.cs | 32 +- src/App/Pages/Vault/ViewPage.xaml | 12 +- src/App/Pages/Vault/ViewPage.xaml.cs | 43 +- src/App/Resources/AppResources.Designer.cs | 6038 +++++++------------ src/App/Resources/AppResources.resx | 4 + 7 files changed, 2415 insertions(+), 3734 deletions(-) diff --git a/src/App/Pages/Vault/AddEditPage.xaml b/src/App/Pages/Vault/AddEditPage.xaml index ac109add8..8d0f1c37e 100644 --- a/src/App/Pages/Vault/AddEditPage.xaml +++ b/src/App/Pages/Vault/AddEditPage.xaml @@ -607,7 +607,7 @@ - + - + \ No newline at end of file diff --git a/src/App/Pages/Vault/AddEditPage.xaml.cs b/src/App/Pages/Vault/AddEditPage.xaml.cs index ab2d3d821..77faf3f92 100644 --- a/src/App/Pages/Vault/AddEditPage.xaml.cs +++ b/src/App/Pages/Vault/AddEditPage.xaml.cs @@ -30,7 +30,9 @@ namespace Bit.App.Pages string name = null, string uri = null, bool fromAutofill = false, - AppOptions appOptions = null) + AppOptions appOptions = null, + bool cloneMode = false, + ViewPage viewPage = null) { _storageService = ServiceContainer.Resolve("storageService"); _deviceActionService = ServiceContainer.Resolve("deviceActionService"); @@ -46,9 +48,11 @@ namespace Bit.App.Pages _vm.Type = type; _vm.DefaultName = name ?? appOptions?.SaveName; _vm.DefaultUri = uri ?? appOptions?.Uri; + _vm.CloneMode = cloneMode; + _vm.ViewPage = viewPage; _vm.Init(); SetActivityIndicator(); - if(_vm.EditMode && Device.RuntimePlatform == Device.Android) + if(_vm.EditMode && !_vm.CloneMode && Device.RuntimePlatform == Device.Android) { ToolbarItems.Add(_attachmentsItem); ToolbarItems.Add(_deleteItem); @@ -56,7 +60,7 @@ namespace Bit.App.Pages if(Device.RuntimePlatform == Device.iOS) { ToolbarItems.Add(_closeItem); - if(_vm.EditMode) + if(_vm.EditMode && !_vm.CloneMode) { ToolbarItems.Add(_moreItem); } @@ -263,7 +267,7 @@ namespace Bit.App.Pages options.Add(_vm.Cipher.OrganizationId == null ? AppResources.Share : AppResources.Collections); } var selection = await DisplayActionSheet(AppResources.Options, AppResources.Cancel, - _vm.EditMode ? AppResources.Delete : null, options.ToArray()); + (_vm.EditMode && !_vm.CloneMode) ? AppResources.Delete : null, options.ToArray()); if(selection == AppResources.Delete) { if(await _vm.DeleteAsync()) @@ -334,7 +338,7 @@ namespace Bit.App.Pages private void AdjustToolbar() { - if(_vm.EditMode && Device.RuntimePlatform == Device.Android) + if((_vm.EditMode || _vm.CloneMode) && Device.RuntimePlatform == Device.Android) { if(_vm.Cipher == null) { @@ -346,7 +350,7 @@ namespace Bit.App.Pages { ToolbarItems.Remove(_collectionsItem); } - if(!ToolbarItems.Contains(_shareItem)) + if(!ToolbarItems.Contains(_shareItem) && !_vm.CloneMode) { ToolbarItems.Insert(2, _shareItem); } diff --git a/src/App/Pages/Vault/AddEditPageViewModel.cs b/src/App/Pages/Vault/AddEditPageViewModel.cs index 72a00ae76..eca05ce6c 100644 --- a/src/App/Pages/Vault/AddEditPageViewModel.cs +++ b/src/App/Pages/Vault/AddEditPageViewModel.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Xamarin.Forms; +using View = Xamarin.Forms.View; namespace Bit.App.Pages { @@ -260,8 +261,11 @@ namespace Bit.App.Pages nameof(ShowCollections) }); } - public bool ShowCollections => !EditMode && Cipher.OrganizationId != null; + public bool ShowCollections => (!EditMode || CloneMode) && Cipher.OrganizationId != null; public bool EditMode => !string.IsNullOrWhiteSpace(CipherId); + public bool ShowOwnershipOptions => !EditMode || CloneMode; + public bool CloneMode { get; set; } + public ViewPage ViewPage { get; set; } public bool IsLogin => Cipher?.Type == CipherType.Login; public bool IsIdentity => Cipher?.Type == CipherType.Identity; public bool IsCard => Cipher?.Type == CipherType.Card; @@ -273,7 +277,7 @@ namespace Bit.App.Pages public void Init() { - PageTitle = EditMode ? AppResources.EditItem : AppResources.AddItem; + PageTitle = EditMode && !CloneMode ? AppResources.EditItem : AppResources.AddItem; } public async Task LoadAsync(AppOptions appOptions = null) @@ -310,6 +314,10 @@ namespace Bit.App.Pages return false; } Cipher = await cipher.DecryptAsync(); + if(CloneMode) + { + Cipher.Name += " - " + AppResources.Clone; + } } else { @@ -355,7 +363,7 @@ namespace Bit.App.Pages OwnershipSelectedIndex = string.IsNullOrWhiteSpace(Cipher.OrganizationId) ? 0 : OwnershipOptions.FindIndex(k => k.Value == Cipher.OrganizationId); - if(!EditMode && (CollectionIds?.Any() ?? false)) + if((!EditMode || CloneMode) && (CollectionIds?.Any() ?? false)) { foreach(var col in Collections) { @@ -406,14 +414,14 @@ namespace Bit.App.Pages if(Cipher.Login != null) { Cipher.Login.Uris = Uris?.ToList(); - if(!EditMode && Cipher.Type == CipherType.Login && Cipher.Login.Uris != null && - Cipher.Login.Uris.Count == 1 && string.IsNullOrWhiteSpace(Cipher.Login.Uris[0].Uri)) + if((!EditMode || CloneMode) && Cipher.Type == CipherType.Login && Cipher.Login.Uris != null && + Cipher.Login.Uris.Count == 1 && string.IsNullOrWhiteSpace(Cipher.Login.Uris[0].Uri)) { Cipher.Login.Uris = null; } } - if(!EditMode && Cipher.OrganizationId != null) + if((!EditMode || CloneMode) && Cipher.OrganizationId != null) { if(Collections == null || !Collections.Any(c => c != null && c.Checked)) { @@ -427,6 +435,10 @@ namespace Bit.App.Pages .Select(c => c.Collection.Id)) : null; } + if(CloneMode) + { + Cipher.Id = null; + } var cipher = await _cipherService.EncryptAsync(Cipher); if(cipher == null) { @@ -439,8 +451,8 @@ namespace Bit.App.Pages Cipher.Id = cipher.Id; await _deviceActionService.HideLoadingAsync(); _platformUtilsService.ShowToast("success", null, - EditMode ? AppResources.ItemUpdated : AppResources.NewItemCreated); - _messagingService.Send(EditMode ? "editedCipher" : "addedCipher", Cipher.Id); + EditMode && !CloneMode ? AppResources.ItemUpdated : AppResources.NewItemCreated); + _messagingService.Send(EditMode && !CloneMode ? "editedCipher" : "addedCipher", Cipher.Id); if(Page is AddEditPage page && page.FromAutofillFramework) { @@ -449,6 +461,10 @@ namespace Bit.App.Pages } else { + if(CloneMode) + { + ViewPage?.UpdateCipherId(this.Cipher.Id); + } await Page.Navigation.PopModalAsync(); } return true; diff --git a/src/App/Pages/Vault/ViewPage.xaml b/src/App/Pages/Vault/ViewPage.xaml index d7fef2c5b..bcb8f91d7 100644 --- a/src/App/Pages/Vault/ViewPage.xaml +++ b/src/App/Pages/Vault/ViewPage.xaml @@ -32,7 +32,7 @@ Clicked="Share_Clicked" Order="Secondary" /> + x:Name="_closeItem" x:Key="closeItem" /> + @@ -185,7 +187,7 @@ Grid.RowSpan="2" HorizontalOptions="End" HorizontalTextAlignment="End" - VerticalOptions="CenterAndExpand"/> + VerticalOptions="CenterAndExpand" /> + IsVisible="{Binding Cipher.Card.CardholderName, Converter={StaticResource stringHasValue}}" /> @@ -361,7 +363,7 @@ StyleClass="box-value" /> + IsVisible="{Binding Cipher.Identity.SSN, Converter={StaticResource stringHasValue}}" />