diff --git a/src/App/App.csproj b/src/App/App.csproj
index 679143e3b..d1cb1ead4 100644
--- a/src/App/App.csproj
+++ b/src/App/App.csproj
@@ -38,6 +38,9 @@
GeneratorPage.xaml
+
+ CollectionsPage.xaml
+
SharePage.xaml
diff --git a/src/App/Pages/Vault/AddEditPage.xaml.cs b/src/App/Pages/Vault/AddEditPage.xaml.cs
index 6c51a4ec7..2b8075d37 100644
--- a/src/App/Pages/Vault/AddEditPage.xaml.cs
+++ b/src/App/Pages/Vault/AddEditPage.xaml.cs
@@ -124,11 +124,12 @@ namespace Bit.App.Pages
}
}
- private void Collections_Clicked(object sender, System.EventArgs e)
+ private async void Collections_Clicked(object sender, System.EventArgs e)
{
if(DoOnce())
{
- // TODO
+ var page = new CollectionsPage(_vm.CipherId);
+ await Navigation.PushModalAsync(new NavigationPage(page));
}
}
}
diff --git a/src/App/Pages/Vault/CollectionsPage.xaml b/src/App/Pages/Vault/CollectionsPage.xaml
new file mode 100644
index 000000000..6f8031af0
--- /dev/null
+++ b/src/App/Pages/Vault/CollectionsPage.xaml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/App/Pages/Vault/CollectionsPage.xaml.cs b/src/App/Pages/Vault/CollectionsPage.xaml.cs
new file mode 100644
index 000000000..13d08385f
--- /dev/null
+++ b/src/App/Pages/Vault/CollectionsPage.xaml.cs
@@ -0,0 +1,37 @@
+using Xamarin.Forms;
+
+namespace Bit.App.Pages
+{
+ public partial class CollectionsPage : BaseContentPage
+ {
+ private CollectionsPageViewModel _vm;
+
+ public CollectionsPage(string cipherId)
+ {
+ InitializeComponent();
+ _vm = BindingContext as CollectionsPageViewModel;
+ _vm.Page = this;
+ _vm.CipherId = cipherId;
+ SetActivityIndicator();
+ }
+
+ protected override async void OnAppearing()
+ {
+ base.OnAppearing();
+ await LoadOnAppearedAsync(_scrollView, true, () => _vm.LoadAsync());
+ }
+
+ protected override void OnDisappearing()
+ {
+ base.OnDisappearing();
+ }
+
+ private async void Save_Clicked(object sender, System.EventArgs e)
+ {
+ if(DoOnce())
+ {
+ await _vm.SubmitAsync();
+ }
+ }
+ }
+}
diff --git a/src/App/Pages/Vault/CollectionsPageViewModel.cs b/src/App/Pages/Vault/CollectionsPageViewModel.cs
new file mode 100644
index 000000000..b854a6402
--- /dev/null
+++ b/src/App/Pages/Vault/CollectionsPageViewModel.cs
@@ -0,0 +1,87 @@
+using Bit.App.Abstractions;
+using Bit.App.Resources;
+using Bit.Core.Abstractions;
+using Bit.Core.Exceptions;
+using Bit.Core.Models.Domain;
+using Bit.Core.Models.View;
+using Bit.Core.Utilities;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Bit.App.Pages
+{
+ public class CollectionsPageViewModel : BaseViewModel
+ {
+ private readonly IDeviceActionService _deviceActionService;
+ private readonly ICipherService _cipherService;
+ private readonly ICollectionService _collectionService;
+ private readonly IPlatformUtilsService _platformUtilsService;
+ private CipherView _cipher;
+ private Cipher _cipherDomain;
+ private bool _hasCollections;
+
+ public CollectionsPageViewModel()
+ {
+ _deviceActionService = ServiceContainer.Resolve("deviceActionService");
+ _cipherService = ServiceContainer.Resolve("cipherService");
+ _platformUtilsService = ServiceContainer.Resolve("platformUtilsService");
+ _collectionService = ServiceContainer.Resolve("collectionService");
+ Collections = new ExtendedObservableCollection();
+ PageTitle = AppResources.Collections;
+ }
+
+ public string CipherId { get; set; }
+ public ExtendedObservableCollection Collections { get; set; }
+ public bool HasCollections
+ {
+ get => _hasCollections;
+ set => SetProperty(ref _hasCollections, value);
+ }
+
+ public async Task LoadAsync()
+ {
+ _cipherDomain = await _cipherService.GetAsync(CipherId);
+ var collectionIds = _cipherDomain.CollectionIds;
+ _cipher = await _cipherDomain.DecryptAsync();
+ var allCollections = await _collectionService.GetAllDecryptedAsync();
+ var collections = allCollections
+ .Where(c => !c.ReadOnly && c.OrganizationId == _cipher.OrganizationId)
+ .Select(c => new CollectionViewModel
+ {
+ Collection = c,
+ Checked = collectionIds.Contains(c.Id)
+ }).ToList();
+ Collections.ResetWithRange(collections);
+ HasCollections = Collections.Any();
+ }
+
+ public async Task SubmitAsync()
+ {
+ if(!Collections.Any(c => c.Checked))
+ {
+ await Page.DisplayAlert(AppResources.AnErrorHasOccurred, AppResources.SelectOneCollection,
+ AppResources.Ok);
+ return false;
+ }
+
+ _cipherDomain.CollectionIds = new HashSet(
+ Collections.Where(c => c.Checked).Select(c => c.Collection.Id));
+ try
+ {
+ await _deviceActionService.ShowLoadingAsync(AppResources.Saving);
+ await _cipherService.SaveCollectionsWithServerAsync(_cipherDomain);
+ await _deviceActionService.HideLoadingAsync();
+ _platformUtilsService.ShowToast("success", null, AppResources.ItemUpdated);
+ await Page.Navigation.PopModalAsync();
+ return true;
+ }
+ catch(ApiException e)
+ {
+ await _deviceActionService.HideLoadingAsync();
+ await Page.DisplayAlert(AppResources.AnErrorHasOccurred, e.Error.GetSingleMessage(), AppResources.Ok);
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/App/Pages/Vault/SharePage.xaml.cs b/src/App/Pages/Vault/SharePage.xaml.cs
index ca29240e3..37b4be847 100644
--- a/src/App/Pages/Vault/SharePage.xaml.cs
+++ b/src/App/Pages/Vault/SharePage.xaml.cs
@@ -6,7 +6,7 @@ namespace Bit.App.Pages
{
private SharePageViewModel _vm;
- public SharePage(string cipherId = null)
+ public SharePage(string cipherId)
{
InitializeComponent();
_vm = BindingContext as SharePageViewModel;
diff --git a/src/App/Pages/Vault/ViewPage.xaml.cs b/src/App/Pages/Vault/ViewPage.xaml.cs
index 9e63fe94e..92930ecf6 100644
--- a/src/App/Pages/Vault/ViewPage.xaml.cs
+++ b/src/App/Pages/Vault/ViewPage.xaml.cs
@@ -130,11 +130,12 @@ namespace Bit.App.Pages
}
}
- private void Collections_Clicked(object sender, System.EventArgs e)
+ private async void Collections_Clicked(object sender, System.EventArgs e)
{
if(DoOnce())
{
- // TODO
+ var page = new CollectionsPage(_vm.CipherId);
+ await Navigation.PushModalAsync(new NavigationPage(page));
}
}
}