diff --git a/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs b/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs index 153ea59d1..17d7b5764 100644 --- a/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs +++ b/src/App/Pages/Vault/AutofillCiphersPage.xaml.cs @@ -1,13 +1,18 @@ using Bit.App.Models; +using Bit.App.Resources; +using Bit.Core.Abstractions; using Bit.Core.Enums; +using Bit.Core.Utilities; using Xamarin.Forms; namespace Bit.App.Pages { public partial class AutofillCiphersPage : BaseContentPage { - private AutofillCiphersPageViewModel _vm; private readonly AppOptions _appOptions; + private readonly IPlatformUtilsService _platformUtilsService; + + private AutofillCiphersPageViewModel _vm; public AutofillCiphersPage(AppOptions appOptions) { @@ -17,6 +22,8 @@ namespace Bit.App.Pages _vm.Page = this; _fab.Clicked = AddButton_Clicked; _vm.Init(appOptions); + + _platformUtilsService = ServiceContainer.Resolve("platformUtilsService"); } protected async override void OnAppearing() @@ -60,7 +67,14 @@ namespace Bit.App.Pages private void Search_Clicked(object sender, System.EventArgs e) { - + var page = new CiphersPage(null, autofillUrl: _vm.Uri); + Application.Current.MainPage = new NavigationPage(page); + _platformUtilsService.ShowToast("info", null, + string.Format(AppResources.BitwardenAutofillServiceSearch, _vm.Name), + new System.Collections.Generic.Dictionary + { + ["longDuration"] = true + }); } } } diff --git a/src/App/Pages/Vault/CiphersPage.xaml.cs b/src/App/Pages/Vault/CiphersPage.xaml.cs index baa3881e9..55bf634e1 100644 --- a/src/App/Pages/Vault/CiphersPage.xaml.cs +++ b/src/App/Pages/Vault/CiphersPage.xaml.cs @@ -1,5 +1,7 @@ -using Bit.App.Resources; +using Bit.App.Abstractions; +using Bit.App.Resources; using Bit.Core.Models.View; +using Bit.Core.Utilities; using System; using Xamarin.Forms; @@ -7,16 +9,20 @@ namespace Bit.App.Pages { public partial class CiphersPage : BaseContentPage { + private readonly string _autofillUrl; + private readonly IDeviceActionService _deviceActionService; + private CiphersPageViewModel _vm; private bool _hasFocused; public CiphersPage(Func filter, bool folder = false, bool collection = false, - bool type = false) + bool type = false, string autofillUrl = null) { InitializeComponent(); _vm = BindingContext as CiphersPageViewModel; _vm.Page = this; _vm.Filter = filter; + _vm.AutofillUrl = _autofillUrl = autofillUrl; if(folder) { _vm.PageTitle = AppResources.SearchFolder; @@ -33,6 +39,8 @@ namespace Bit.App.Pages { _vm.PageTitle = AppResources.SearchVault; } + + _deviceActionService = ServiceContainer.Resolve("deviceActionService"); } public SearchBar SearchBar => _searchBar; @@ -43,7 +51,10 @@ namespace Bit.App.Pages if(!_hasFocused) { _hasFocused = true; - RequestFocus(_searchBar); + if(string.IsNullOrWhiteSpace(_autofillUrl)) + { + RequestFocus(_searchBar); + } } } @@ -70,6 +81,10 @@ namespace Bit.App.Pages protected override bool OnBackButtonPressed() { + if(string.IsNullOrWhiteSpace(_autofillUrl)) + { + return false; + } GoBack(); return true; } @@ -80,7 +95,14 @@ namespace Bit.App.Pages { return; } - Navigation.PopModalAsync(false); + if(string.IsNullOrWhiteSpace(_autofillUrl)) + { + Navigation.PopModalAsync(false); + } + else + { + _deviceActionService.CloseAutofill(); + } } private async void RowSelected(object sender, SelectedItemChangedEventArgs e) diff --git a/src/App/Pages/Vault/CiphersPageViewModel.cs b/src/App/Pages/Vault/CiphersPageViewModel.cs index 724d62ca0..8d1972054 100644 --- a/src/App/Pages/Vault/CiphersPageViewModel.cs +++ b/src/App/Pages/Vault/CiphersPageViewModel.cs @@ -1,9 +1,13 @@ -using Bit.App.Resources; +using Bit.App.Abstractions; +using Bit.App.Resources; using Bit.Core.Abstractions; +using Bit.Core.Enums; +using Bit.Core.Exceptions; 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; @@ -15,6 +19,7 @@ namespace Bit.App.Pages private readonly IPlatformUtilsService _platformUtilsService; private readonly ICipherService _cipherService; private readonly ISearchService _searchService; + private readonly IDeviceActionService _deviceActionService; private CancellationTokenSource _searchCancellationTokenSource; private string _searchText; @@ -26,7 +31,8 @@ namespace Bit.App.Pages _platformUtilsService = ServiceContainer.Resolve("platformUtilsService"); _cipherService = ServiceContainer.Resolve("cipherService"); _searchService = ServiceContainer.Resolve("searchService"); - + _deviceActionService = ServiceContainer.Resolve("deviceActionService"); + Ciphers = new ExtendedObservableCollection(); CipherOptionsCommand = new Command(CipherOptionsAsync); } @@ -34,6 +40,7 @@ namespace Bit.App.Pages public Command CipherOptionsCommand { get; set; } public ExtendedObservableCollection Ciphers { get; set; } public Func Filter { get; set; } + public string AutofillUrl { get; set; } public string SearchText { @@ -100,8 +107,60 @@ namespace Bit.App.Pages public async Task SelectCipherAsync(CipherView cipher) { - var page = new ViewPage(cipher.Id); - await Page.Navigation.PushModalAsync(new NavigationPage(page)); + string selection = null; + if(!string.IsNullOrWhiteSpace(AutofillUrl)) + { + var options = new List { AppResources.Autofill }; + if(cipher.Type == CipherType.Login) + { + options.Add(AppResources.AutofillAndSave); + } + options.Add(AppResources.View); + selection = await Page.DisplayActionSheet(AppResources.AutofillOrView, AppResources.Cancel, null, + options.ToArray()); + } + if(selection == AppResources.View || string.IsNullOrWhiteSpace(AutofillUrl)) + { + var page = new ViewPage(cipher.Id); + await Page.Navigation.PushModalAsync(new NavigationPage(page)); + } + else if(selection == AppResources.Autofill || selection == AppResources.AutofillAndSave) + { + if(selection == AppResources.AutofillAndSave) + { + var uris = cipher.Login?.Uris?.ToList(); + if(uris == null) + { + uris = new List(); + } + uris.Add(new LoginUriView + { + Uri = AutofillUrl, + Match = null + }); + cipher.Login.Uris = uris; + try + { + await _deviceActionService.ShowLoadingAsync(AppResources.Saving); + await _cipherService.SaveWithServerAsync(await _cipherService.EncryptAsync(cipher)); + await _deviceActionService.HideLoadingAsync(); + } + catch(ApiException e) + { + await _deviceActionService.HideLoadingAsync(); + await Page.DisplayAlert(AppResources.AnErrorHasOccurred, e.Error.GetSingleMessage(), + AppResources.Ok); + } + } + if(_deviceActionService.SystemMajorVersion() < 21) + { + // TODO + } + else + { + _deviceActionService.Autofill(cipher); + } + } } private async void CipherOptionsAsync(CipherView cipher)