From 003092a55b297bc85cbf6f4c38fd938405a0d684 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Wed, 24 Apr 2019 16:50:34 -0400 Subject: [PATCH] re-use groupings page for ciphers listing --- src/App/App.csproj | 3 - src/App/Pages/Vault/CiphersPage.xaml | 38 ----- src/App/Pages/Vault/CiphersPage.xaml.cs | 54 ------- src/App/Pages/Vault/CiphersPageViewModel.cs | 50 ------- .../Vault/GroupingsPage/GroupingsPage.xaml.cs | 22 ++- .../GroupingsPage/GroupingsPageViewModel.cs | 137 ++++++++++++++---- src/App/Resources/AppResources.Designer.cs | 47 +++++- src/App/Resources/AppResources.resx | 15 ++ src/Core/Utilities/ServiceContainer.cs | 3 +- 9 files changed, 190 insertions(+), 179 deletions(-) delete mode 100644 src/App/Pages/Vault/CiphersPage.xaml delete mode 100644 src/App/Pages/Vault/CiphersPage.xaml.cs delete mode 100644 src/App/Pages/Vault/CiphersPageViewModel.cs diff --git a/src/App/App.csproj b/src/App/App.csproj index 77ac609dc..ea6f7c8d8 100644 --- a/src/App/App.csproj +++ b/src/App/App.csproj @@ -28,9 +28,6 @@ GeneratorPage.xaml - - CiphersPage.xaml - ViewPage.xaml diff --git a/src/App/Pages/Vault/CiphersPage.xaml b/src/App/Pages/Vault/CiphersPage.xaml deleted file mode 100644 index bf8083c67..000000000 --- a/src/App/Pages/Vault/CiphersPage.xaml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/src/App/Pages/Vault/CiphersPage.xaml.cs b/src/App/Pages/Vault/CiphersPage.xaml.cs deleted file mode 100644 index 711cd4101..000000000 --- a/src/App/Pages/Vault/CiphersPage.xaml.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Bit.Core.Abstractions; -using Bit.Core.Utilities; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xamarin.Forms; -using Xamarin.Forms.Xaml; - -namespace Bit.App.Pages -{ - public partial class ViewPage : ContentPage - { - private readonly IBroadcasterService _broadcasterService; - private ViewPageViewModel _vm; - - public ViewPage(string cipherId) - { - InitializeComponent(); - _broadcasterService = ServiceContainer.Resolve("broadcasterService"); - _vm = BindingContext as ViewPageViewModel; - _vm.Page = this; - _vm.CipherId = cipherId; - } - - protected async override void OnAppearing() - { - base.OnAppearing(); - _broadcasterService.Subscribe(nameof(ViewPage), async (message) => - { - if(message.Command == "syncCompleted") - { - var data = message.Data as Dictionary; - if(data.ContainsKey("successfully")) - { - var success = data["successfully"] as bool?; - if(success.HasValue && success.Value) - { - await _vm.LoadAsync(); - } - } - } - }); - await _vm.LoadAsync(); - } - - protected override void OnDisappearing() - { - base.OnDisappearing(); - _broadcasterService.Unsubscribe(nameof(ViewPage)); - } - } -} diff --git a/src/App/Pages/Vault/CiphersPageViewModel.cs b/src/App/Pages/Vault/CiphersPageViewModel.cs deleted file mode 100644 index 18c59a216..000000000 --- a/src/App/Pages/Vault/CiphersPageViewModel.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Bit.App.Abstractions; -using Bit.App.Resources; -using Bit.Core.Abstractions; -using Bit.Core.Models.View; -using Bit.Core.Utilities; -using System.Threading.Tasks; - -namespace Bit.App.Pages -{ - public class CiphersPageViewModel : BaseViewModel - { - private readonly IDeviceActionService _deviceActionService; - private readonly ICipherService _cipherService; - private readonly IUserService _userService; - private CipherView _cipher; - private bool _canAccessPremium; - - public CiphersPageViewModel() - { - _deviceActionService = ServiceContainer.Resolve("deviceActionService"); - _cipherService = ServiceContainer.Resolve("cipherService"); - _userService = ServiceContainer.Resolve("userService"); - - PageTitle = AppResources.ViewItem; - } - - public string CipherId { get; set; } - public CipherView Cipher - { - get => _cipher; - set => SetProperty(ref _cipher, value); - } - public bool CanAccessPremium - { - get => _canAccessPremium; - set => SetProperty(ref _canAccessPremium, value); - } - - public async Task LoadAsync() - { - // TODO: Cleanup - - var cipher = await _cipherService.GetAsync(CipherId); - Cipher = await cipher.DecryptAsync(); - CanAccessPremium = await _userService.CanAccessPremiumAsync(); - - // TODO: Totp - } - } -} diff --git a/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml.cs b/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml.cs index d7455a2c3..ce355507f 100644 --- a/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml.cs +++ b/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml.cs @@ -1,4 +1,5 @@ using Bit.Core.Abstractions; +using Bit.Core.Enums; using Bit.Core.Utilities; using System; using System.Collections.Generic; @@ -17,12 +18,25 @@ namespace Bit.App.Pages private readonly GroupingsPageViewModel _viewModel; public GroupingsPage() + : this(true) + { } + + public GroupingsPage(bool mainPage, CipherType? type = null, string folderId = null, + string collectionId = null, string pageTitle = null) { InitializeComponent(); _broadcasterService = ServiceContainer.Resolve("broadcasterService"); _syncService = ServiceContainer.Resolve("syncService"); _viewModel = BindingContext as GroupingsPageViewModel; _viewModel.Page = this; + _viewModel.MainPage = mainPage; + _viewModel.Type = type; + _viewModel.FolderId = folderId; + _viewModel.CollectionId = collectionId; + if(pageTitle != null) + { + _viewModel.PageTitle = pageTitle; + } } protected async override void OnAppearing() @@ -68,9 +82,13 @@ namespace Bit.App.Pages { await _viewModel.SelectCipherAsync(item.Cipher); } - else if(item.Folder != null || item.Collection != null) + else if(item.Folder != null) { - // TODO + await _viewModel.SelectFolderAsync(item.Folder); + } + else if(item.Collection != null) + { + await _viewModel.SelectCollectionAsync(item.Collection); } } } diff --git a/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs b/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs index 4a8782a4b..705b3aa02 100644 --- a/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs +++ b/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs @@ -1,5 +1,6 @@ using Bit.App.Resources; using Bit.Core.Abstractions; +using Bit.Core.Enums; using Bit.Core.Models.Domain; using Bit.Core.Models.View; using Bit.Core.Utilities; @@ -28,7 +29,7 @@ namespace Bit.App.Pages _collectionService = ServiceContainer.Resolve("collectionService"); _syncService = ServiceContainer.Resolve("syncService"); - PageTitle = "My Vault"; + PageTitle = AppResources.MyVault; GroupedItems = new ExtendedObservableCollection(); LoadCommand = new Command(async () => await LoadAsync()); } @@ -36,6 +37,10 @@ namespace Bit.App.Pages public bool ShowFavorites { get; set; } = true; public bool ShowFolders { get; set; } = true; public bool ShowCollections { get; set; } = true; + public bool MainPage { get; set; } + public CipherType? Type { get; set; } + public string FolderId { get; set; } + public string CollectionId { get; set; } public List Ciphers { get; set; } public List FavoriteCiphers { get; set; } @@ -66,11 +71,10 @@ namespace Bit.App.Pages { try { - await LoadFoldersAsync(); - await LoadCollectionsAsync(); - await LoadCiphersAsync(); + await LoadDataAsync(); var favListItems = FavoriteCiphers?.Select(c => new GroupingsPageListItem { Cipher = c }).ToList(); + var ciphersListItems = Ciphers?.Select(c => new GroupingsPageListItem { Cipher = c }).ToList(); var folderListItems = NestedFolders?.Select(f => new GroupingsPageListItem { Folder = f.Node }).ToList(); var collectionListItems = NestedCollections?.Select(c => new GroupingsPageListItem { Collection = c.Node }).ToList(); @@ -91,6 +95,11 @@ namespace Bit.App.Pages groupedItems.Add(new GroupingsPageListGroup(collectionListItems, AppResources.Collections, Device.RuntimePlatform == Device.iOS)); } + if(ciphersListItems?.Any() ?? false) + { + groupedItems.Add(new GroupingsPageListGroup(ciphersListItems, AppResources.Items, + Device.RuntimePlatform == Device.iOS)); + } GroupedItems.ResetWithRange(groupedItems); } finally @@ -105,50 +114,118 @@ namespace Bit.App.Pages await Page.Navigation.PushModalAsync(new NavigationPage(page)); } - private async Task LoadFoldersAsync() + public async Task SelectFolderAsync(CipherType type) { - if(!ShowFolders) + string title = null; + switch(Type.Value) { - return; + case CipherType.Login: + title = AppResources.Logins; + break; + case CipherType.SecureNote: + title = AppResources.SecureNotes; + break; + case CipherType.Card: + title = AppResources.Cards; + break; + case CipherType.Identity: + title = AppResources.Identities; + break; + default: + break; } - Folders = await _folderService.GetAllDecryptedAsync(); - NestedFolders = await _folderService.GetAllNestedAsync(); + var page = new GroupingsPage(false, type, null, null, title); + await Page.Navigation.PushAsync(page); } - private async Task LoadCollectionsAsync() + public async Task SelectFolderAsync(FolderView folder) { - if(!ShowCollections) - { - return; - } - Collections = await _collectionService.GetAllDecryptedAsync(); - NestedCollections = await _collectionService.GetAllNestedAsync(Collections); + var page = new GroupingsPage(false, null, folder.Id ?? "none", null, folder.Name); + await Page.Navigation.PushAsync(page); } - private async Task LoadCiphersAsync() + public async Task SelectCollectionAsync(Core.Models.View.CollectionView collection) + { + var page = new GroupingsPage(false, null, null, collection.Id, collection.Name); + await Page.Navigation.PushAsync(page); + } + + private async Task LoadDataAsync() { _allCiphers = await _cipherService.GetAllDecryptedAsync(); - Ciphers = _allCiphers; - foreach(var c in _allCiphers) + if(MainPage) { - if(c.Favorite) + if(ShowFolders) { - if(FavoriteCiphers == null) - { - FavoriteCiphers = new List(); - } - FavoriteCiphers.Add(c); + Folders = await _folderService.GetAllDecryptedAsync(); + NestedFolders = await _folderService.GetAllNestedAsync(); } - if(c.FolderId == null) + if(ShowCollections) { - if(NoFolderCiphers == null) + Collections = await _collectionService.GetAllDecryptedAsync(); + NestedCollections = await _collectionService.GetAllNestedAsync(Collections); + } + + foreach(var c in _allCiphers) + { + if(c.Favorite) { - NoFolderCiphers = new List(); + if(FavoriteCiphers == null) + { + FavoriteCiphers = new List(); + } + FavoriteCiphers.Add(c); } - NoFolderCiphers.Add(c); + if(c.FolderId == null) + { + if(NoFolderCiphers == null) + { + NoFolderCiphers = new List(); + } + NoFolderCiphers.Add(c); + } + } + FavoriteCiphers = _allCiphers.Where(c => c.Favorite).ToList(); + } + else + { + if(Type != null) + { + Ciphers = _allCiphers.Where(c => c.Type == Type.Value).ToList(); + } + else if(FolderId != null) + { + FolderId = FolderId == "none" ? null : FolderId; + if(FolderId != null) + { + var folderNode = await _folderService.GetNestedAsync(FolderId); + if(folderNode?.Node != null) + { + PageTitle = folderNode.Node.Name; + NestedFolders = (folderNode.Children?.Count ?? 0) > 0 ? folderNode.Children : null; + } + } + else + { + PageTitle = AppResources.FolderNone; + } + Ciphers = _allCiphers.Where(c => c.FolderId == FolderId).ToList(); + } + else if(CollectionId != null) + { + var collectionNode = await _collectionService.GetNestedAsync(CollectionId); + if(collectionNode?.Node != null) + { + PageTitle = collectionNode.Node.Name; + } + Ciphers = _allCiphers.Where(c => c.CollectionIds?.Contains(CollectionId) ?? false).ToList(); + } + else + { + PageTitle = AppResources.AllItems; + Ciphers = _allCiphers; } } - FavoriteCiphers = _allCiphers.Where(c => c.Favorite).ToList(); } } } diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs index 60be79d0c..e70d9b87a 100644 --- a/src/App/Resources/AppResources.Designer.cs +++ b/src/App/Resources/AppResources.Designer.cs @@ -19,7 +19,7 @@ namespace Bit.App.Resources { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class AppResources { @@ -168,6 +168,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to All Items. + /// + internal static string AllItems { + get { + return ResourceManager.GetString("AllItems", resourceCulture); + } + } + /// /// Looks up a localized string similar to An error has occurred.. /// @@ -780,6 +789,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Cards. + /// + internal static string Cards { + get { + return ResourceManager.GetString("Cards", resourceCulture); + } + } + /// /// Looks up a localized string similar to Change Email. /// @@ -1734,6 +1752,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Identities. + /// + internal static string Identities { + get { + return ResourceManager.GetString("Identities", resourceCulture); + } + } + /// /// Looks up a localized string similar to Identity Server URL. /// @@ -2040,6 +2067,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Logins. + /// + internal static string Logins { + get { + return ResourceManager.GetString("Logins", resourceCulture); + } + } + /// /// Looks up a localized string similar to Login Unavailable. /// @@ -2760,6 +2796,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Secure Notes. + /// + internal static string SecureNotes { + get { + return ResourceManager.GetString("SecureNotes", resourceCulture); + } + } + /// /// Looks up a localized string similar to Security. /// diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx index 254471511..85b65c2eb 100644 --- a/src/App/Resources/AppResources.resx +++ b/src/App/Resources/AppResources.resx @@ -1349,4 +1349,19 @@ Invalid email address. + + Cards + + + Identities + + + Logins + + + Secure Notes + + + All Items + \ No newline at end of file diff --git a/src/Core/Utilities/ServiceContainer.cs b/src/Core/Utilities/ServiceContainer.cs index 17498fb70..c7c7f1e0f 100644 --- a/src/Core/Utilities/ServiceContainer.cs +++ b/src/Core/Utilities/ServiceContainer.cs @@ -25,7 +25,7 @@ namespace Bit.Core.Utilities var cryptoPrimitiveService = Resolve("cryptoPrimitiveService"); var i18nService = Resolve("i18nService"); var messagingService = Resolve("messagingService"); - ISearchService searchService = null; + SearchService searchService = null; var stateService = new StateService(); var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService); @@ -65,6 +65,7 @@ namespace Bit.Core.Utilities Register("cipherService", cipherService); Register("folderService", folderService); Register("collectionService", collectionService); + Register("searchService", searchService); Register("syncService", syncService); Register("passwordGenerationService", passwordGenerationService); Register("totpService", totpService);