From 3e633dc38e900d423a6c2f181bb9d7bda4d9b8c7 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Fri, 17 May 2019 13:14:26 -0400 Subject: [PATCH] stub out autofill ciphers listing page --- src/App/App.csproj | 3 + src/App/App.xaml.cs | 4 + src/App/Pages/Vault/AutofillCiphersPage.xaml | 96 ++++++++++++++++ .../Pages/Vault/AutofillCiphersPage.xaml.cs | 53 +++++++++ .../Vault/AutofillCiphersPageViewModel.cs | 105 ++++++++++++++++++ .../Vault/GroupingsPage/GroupingsPage.xaml | 2 +- .../GroupingsPage/GroupingsPageViewModel.cs | 2 - 7 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 src/App/Pages/Vault/AutofillCiphersPage.xaml create mode 100644 src/App/Pages/Vault/AutofillCiphersPage.xaml.cs create mode 100644 src/App/Pages/Vault/AutofillCiphersPageViewModel.cs diff --git a/src/App/App.csproj b/src/App/App.csproj index 3683ae922..bb33b6b15 100644 --- a/src/App/App.csproj +++ b/src/App/App.csproj @@ -57,6 +57,9 @@ AttachmentsPage.xaml + + AutofillCiphersPage.xaml + CollectionsPage.xaml diff --git a/src/App/App.xaml.cs b/src/App/App.xaml.cs index cb12d7adb..3184a024e 100644 --- a/src/App/App.xaml.cs +++ b/src/App/App.xaml.cs @@ -180,6 +180,10 @@ namespace Bit.App { Current.MainPage = new NavigationPage(new AddEditPage(appOptions: _appOptions)); } + else if(_appOptions.Uri != null) + { + Current.MainPage = new NavigationPage(new AutofillCiphersPage(_appOptions)); + } else { Current.MainPage = new TabsPage(); diff --git a/src/App/Pages/Vault/AutofillCiphersPage.xaml b/src/App/Pages/Vault/AutofillCiphersPage.xaml new file mode 100644 index 000000000..d195664da --- /dev/null +++ b/src/App/Pages/Vault/AutofillCiphersPage.xaml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + RecycleElement + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs b/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs new file mode 100644 index 000000000..9f9b2bbb7 --- /dev/null +++ b/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs @@ -0,0 +1,53 @@ +using Bit.App.Models; +using Xamarin.Forms; + +namespace Bit.App.Pages +{ + public partial class AutofillCiphersPage : BaseContentPage + { + private AutofillCiphersPageViewModel _vm; + private readonly AppOptions _appOptions; + + public AutofillCiphersPage(AppOptions appOptions) + { + _appOptions = appOptions; + InitializeComponent(); + _vm = BindingContext as AutofillCiphersPageViewModel; + _vm.Page = this; + _vm.Init(appOptions); + } + + protected async override void OnAppearing() + { + base.OnAppearing(); + await LoadOnAppearedAsync(_mainLayout, false, async () => + { + await _vm.LoadAsync(); + }, _mainContent); + } + + private async void RowSelected(object sender, SelectedItemChangedEventArgs e) + { + ((ListView)sender).SelectedItem = null; + if(!DoOnce()) + { + return; + } + + if(e.SelectedItem is GroupingsPageListItem item && item.Cipher != null) + { + // TODO + } + } + + private void AddButton_Clicked(object sender, System.EventArgs e) + { + + } + + private void Search_Clicked(object sender, System.EventArgs e) + { + + } + } +} diff --git a/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs b/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs new file mode 100644 index 000000000..9fad79d8e --- /dev/null +++ b/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs @@ -0,0 +1,105 @@ +using Bit.App.Models; +using Bit.App.Resources; +using Bit.Core; +using Bit.Core.Abstractions; +using Bit.Core.Models.View; +using Bit.Core.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Xamarin.Forms; + +namespace Bit.App.Pages +{ + public class AutofillCiphersPageViewModel : BaseViewModel + { + private readonly IPlatformUtilsService _platformUtilsService; + private readonly ICipherService _cipherService; + private readonly ISearchService _searchService; + private CancellationTokenSource _searchCancellationTokenSource; + + private AppOptions _appOptions; + private string _name; + private string _uri; + private bool _showNoData; + private bool _showList; + + public AutofillCiphersPageViewModel() + { + _platformUtilsService = ServiceContainer.Resolve("platformUtilsService"); + _cipherService = ServiceContainer.Resolve("cipherService"); + _searchService = ServiceContainer.Resolve("searchService"); + + GroupedItems = new ExtendedObservableCollection(); + CipherOptionsCommand = new Command(CipherOptionsAsync); + } + + public Command CipherOptionsCommand { get; set; } + public ExtendedObservableCollection GroupedItems { get; set; } + + public bool ShowNoData + { + get => _showNoData; + set => SetProperty(ref _showNoData, value); + } + + public bool ShowList + { + get => _showList; + set => SetProperty(ref _showList, value); + } + + public void Init(AppOptions appOptions) + { + _appOptions = appOptions; + _uri = appOptions.Uri; + if(_uri.StartsWith(Constants.AndroidAppProtocol)) + { + _name = _uri.Substring(Constants.AndroidAppProtocol.Length); + } + else if(!Uri.TryCreate(_uri, UriKind.Absolute, out Uri uri) || + !DomainName.TryParseBaseDomain(uri.Host, out _name)) + { + _name = "--"; + } + PageTitle = string.Format(AppResources.ItemsForUri, _name ?? "--"); + } + + public async Task LoadAsync() + { + ShowNoData = false; + ShowList = false; + + var ciphers = await _cipherService.GetAllDecryptedByUrlAsync(_uri, null); + var matching = ciphers.Item1?.Select(c => new GroupingsPageListItem { Cipher = c }).ToList(); + var matchingGroup = new GroupingsPageListGroup(matching, AppResources.MatchingItems, matching.Count, false); + var fuzzy = ciphers.Item2?.Select(c => new GroupingsPageListItem { Cipher = c }).ToList(); + var fuzzyGroup = new GroupingsPageListGroup(fuzzy, AppResources.PossibleMatchingItems, fuzzy.Count, false); + GroupedItems.ResetWithRange(new List { matchingGroup, fuzzyGroup }); + + ShowNoData = !matching.Any() && !fuzzy.Any(); + ShowList = !ShowNoData; + } + + public async Task SelectCipherAsync(CipherView cipher) + { + // TODO + } + + private async void CipherOptionsAsync(CipherView cipher) + { + if(!(Page as BaseContentPage).DoOnce()) + { + return; + } + var option = await Page.DisplayActionSheet(cipher.Name, AppResources.Cancel, null, "1", "2"); + if(option == AppResources.Cancel) + { + return; + } + // TODO: process options + } + } +} diff --git a/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml b/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml index 79bd4d400..202ff8cf5 100644 --- a/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml +++ b/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml @@ -64,7 +64,7 @@ HorizontalTextAlignment="Center"> diff --git a/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs b/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs index 72774d208..9eb810017 100644 --- a/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs +++ b/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs @@ -46,7 +46,6 @@ namespace Bit.App.Pages Refreshing = true; await LoadAsync(); }); - AddCipherCommand = new Command(() => { /* TODO */ }); CipherOptionsCommand = new Command(CipherOptionsAsync); } @@ -104,7 +103,6 @@ namespace Bit.App.Pages } public ExtendedObservableCollection GroupedItems { get; set; } public Command RefreshCommand { get; set; } - public Command AddCipherCommand { get; set; } public Command CipherOptionsCommand { get; set; } public async Task LoadAsync()