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 @@
-
+
@@ -658,4 +658,4 @@
-
+
\ 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}}" />