From 2d2a883b963adb7506bdf5c1c548ad5ff46b2279 Mon Sep 17 00:00:00 2001 From: Federico Maccaroni Date: Thu, 14 Jul 2022 19:04:13 -0300 Subject: [PATCH] EC-306 Fix crash happening on vietnamise when trying to go to Password Autofill on iOS given that the string was the same as Autofill Services and the comparison was misleading. Also refactored so that the action is on each item instead of having to compare to act (#1989) --- .../SettingsPage/SettingsPage.xaml.cs | 122 +--------------- .../SettingsPage/SettingsPageListItem.cs | 3 + .../SettingsPage/SettingsPageViewModel.cs | 136 ++++++++++++++---- 3 files changed, 118 insertions(+), 143 deletions(-) diff --git a/src/App/Pages/Settings/SettingsPage/SettingsPage.xaml.cs b/src/App/Pages/Settings/SettingsPage/SettingsPage.xaml.cs index ac0cfdf04..47a8a22c4 100644 --- a/src/App/Pages/Settings/SettingsPage/SettingsPage.xaml.cs +++ b/src/App/Pages/Settings/SettingsPage/SettingsPage.xaml.cs @@ -2,18 +2,13 @@ using System.ComponentModel; using System.Linq; using System.Threading.Tasks; -using Bit.App.Abstractions; using Bit.App.Controls; -using Bit.App.Pages.Accounts; -using Bit.App.Resources; -using Bit.Core.Utilities; using Xamarin.Forms; namespace Bit.App.Pages { public partial class SettingsPage : BaseContentPage { - private readonly IDeviceActionService _deviceActionService; private readonly TabsPage _tabsPage; private SettingsPageViewModel _vm; @@ -21,7 +16,6 @@ namespace Bit.App.Pages { _tabsPage = tabsPage; InitializeComponent(); - _deviceActionService = ServiceContainer.Resolve("deviceActionService"); _vm = BindingContext as SettingsPageViewModel; _vm.Page = this; } @@ -67,122 +61,12 @@ namespace Bit.App.Pages } } - private async void RowSelected(object sender, SelectionChangedEventArgs e) + private void RowSelected(object sender, SelectionChangedEventArgs e) { ((ExtendedCollectionView)sender).SelectedItem = null; - if (!DoOnce()) + if (e.CurrentSelection?.FirstOrDefault() is SettingsPageListItem item) { - return; - } - if (!(e.CurrentSelection?.FirstOrDefault() is SettingsPageListItem item)) - { - return; - } - - if (item.Name == AppResources.Sync) - { - await Navigation.PushModalAsync(new NavigationPage(new SyncPage())); - } - else if (item.Name == AppResources.AutofillServices) - { - await Navigation.PushModalAsync(new NavigationPage(new AutofillServicesPage(this))); - } - else if (item.Name == AppResources.PasswordAutofill) - { - await Navigation.PushModalAsync(new NavigationPage(new AutofillPage())); - } - else if (item.Name == AppResources.AppExtension) - { - await Navigation.PushModalAsync(new NavigationPage(new ExtensionPage())); - } - else if (item.Name == AppResources.Options) - { - await Navigation.PushModalAsync(new NavigationPage(new OptionsPage())); - } - else if (item.Name == AppResources.Folders) - { - await Navigation.PushModalAsync(new NavigationPage(new FoldersPage())); - } - else if (item.Name == AppResources.About) - { - await _vm.AboutAsync(); - } - else if (item.Name == AppResources.HelpAndFeedback) - { - _vm.Help(); - } - else if (item.Name == AppResources.FingerprintPhrase) - { - await _vm.FingerprintAsync(); - } - else if (item.Name == AppResources.RateTheApp) - { - _vm.Rate(); - } - else if (item.Name == AppResources.ImportItems) - { - _vm.Import(); - } - else if (item.Name == AppResources.ExportVault) - { - await Navigation.PushModalAsync(new NavigationPage(new ExportVaultPage())); - } - else if (item.Name == AppResources.LearnOrg) - { - await _vm.ShareAsync(); - } - else if (item.Name == AppResources.WebVault) - { - _vm.WebVault(); - } - else if (item.Name == AppResources.ChangeMasterPassword) - { - await _vm.ChangePasswordAsync(); - } - else if (item.Name == AppResources.TwoStepLogin) - { - await _vm.TwoStepAsync(); - } - else if (item.Name == AppResources.LogOut) - { - await _vm.LogOutAsync(); - } - else if (item.Name == AppResources.DeleteAccount) - { - await Navigation.PushModalAsync(new NavigationPage(new DeleteAccountPage())); - } - else if (item.Name == AppResources.LockNow) - { - await _vm.LockAsync(); - } - else if (item.Name == AppResources.VaultTimeout) - { - await _vm.VaultTimeoutAsync(); - } - else if (item.Name == AppResources.VaultTimeoutAction) - { - await _vm.VaultTimeoutActionAsync(); - } - else if (item.Name == AppResources.UnlockWithPIN) - { - await _vm.UpdatePinAsync(); - } - else if (item.Name == AppResources.SubmitCrashLogs) - { - await _vm.LoggerReportingAsync(); - } - else - { - var biometricName = AppResources.Biometrics; - if (Device.RuntimePlatform == Device.iOS) - { - var supportsFace = await _deviceActionService.SupportsFaceBiometricAsync(); - biometricName = supportsFace ? AppResources.FaceID : AppResources.TouchID; - } - if (item.Name == string.Format(AppResources.UnlockWith, biometricName)) - { - await _vm.UpdateBiometricAsync(); - } + _vm?.ExecuteSettingItemCommand.Execute(item); } } } diff --git a/src/App/Pages/Settings/SettingsPage/SettingsPageListItem.cs b/src/App/Pages/Settings/SettingsPage/SettingsPageListItem.cs index c1e8878f4..a4d3e926d 100644 --- a/src/App/Pages/Settings/SettingsPage/SettingsPageListItem.cs +++ b/src/App/Pages/Settings/SettingsPage/SettingsPageListItem.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Bit.App.Resources; using Bit.App.Utilities; using Xamarin.Forms; @@ -12,6 +13,8 @@ namespace Bit.App.Pages public string SubLabel { get; set; } public TimeSpan? Time { get; set; } public bool UseFrame { get; set; } + public Func ExecuteAsync { get; set; } + public bool SubLabelTextEnabled => SubLabel == AppResources.Enabled; public string LineBreakMode => SubLabel == null ? "TailTruncation" : ""; public bool ShowSubLabel => SubLabel.Length != 0; diff --git a/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs b/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs index 831be4979..59d76f762 100644 --- a/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs +++ b/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Bit.App.Abstractions; +using Bit.App.Pages.Accounts; using Bit.App.Resources; using Bit.Core.Abstractions; using Bit.Core.Enums; @@ -84,10 +85,14 @@ namespace Bit.App.Pages GroupedItems = new ObservableRangeCollection(); PageTitle = AppResources.Settings; + + ExecuteSettingItemCommand = new AsyncCommand(item => item.ExecuteAsync(), onException: _loggerService.Exception, allowsMultipleExecutions: false); } public ObservableRangeCollection GroupedItems { get; set; } + public IAsyncCommand ExecuteSettingItemCommand { get; } + public async Task InitAsync() { _supportsBiometric = await _platformUtilsService.SupportsBiometricAsync(); @@ -434,6 +439,8 @@ namespace Bit.App.Pages public void BuildList() { + //TODO: Refactor this once navigation is abstracted so that it doesn't depend on Page, e.g. Page.Navigation.PushModalAsync... + var doUpper = Device.RuntimePlatform != Device.Android; var autofillItems = new List(); if (Device.RuntimePlatform == Device.Android) @@ -441,38 +448,69 @@ namespace Bit.App.Pages autofillItems.Add(new SettingsPageListItem { Name = AppResources.AutofillServices, - SubLabel = _deviceActionService.AutofillServicesEnabled() ? - AppResources.Enabled : AppResources.Disabled + SubLabel = _deviceActionService.AutofillServicesEnabled() ? AppResources.Enabled : AppResources.Disabled, + ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillServicesPage(Page as SettingsPage))) }); } else { if (_deviceActionService.SystemMajorVersion() >= 12) { - autofillItems.Add(new SettingsPageListItem { Name = AppResources.PasswordAutofill }); + autofillItems.Add(new SettingsPageListItem + { + Name = AppResources.PasswordAutofill, + ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillPage())) + }); } - autofillItems.Add(new SettingsPageListItem { Name = AppResources.AppExtension }); + autofillItems.Add(new SettingsPageListItem + { + Name = AppResources.AppExtension, + ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new ExtensionPage())) + }); } var manageItems = new List { - new SettingsPageListItem { Name = AppResources.Folders }, - new SettingsPageListItem { Name = AppResources.Sync, SubLabel = _lastSyncDate } + new SettingsPageListItem + { + Name = AppResources.Folders, + ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new FoldersPage())) + }, + new SettingsPageListItem + { + Name = AppResources.Sync, + SubLabel = _lastSyncDate, + ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new SyncPage())) + } }; var securityItems = new List { - new SettingsPageListItem { Name = AppResources.VaultTimeout, SubLabel = _vaultTimeoutDisplayValue }, + new SettingsPageListItem + { + Name = AppResources.VaultTimeout, + SubLabel = _vaultTimeoutDisplayValue, + ExecuteAsync = () => VaultTimeoutAsync() }, new SettingsPageListItem { Name = AppResources.VaultTimeoutAction, - SubLabel = _vaultTimeoutActionDisplayValue + SubLabel = _vaultTimeoutActionDisplayValue, + ExecuteAsync = () => VaultTimeoutActionAsync() }, new SettingsPageListItem { Name = AppResources.UnlockWithPIN, - SubLabel = _pin ? AppResources.Enabled : AppResources.Disabled + SubLabel = _pin ? AppResources.Enabled : AppResources.Disabled, + ExecuteAsync = () => UpdatePinAsync() }, - new SettingsPageListItem { Name = AppResources.LockNow }, - new SettingsPageListItem { Name = AppResources.TwoStepLogin } + new SettingsPageListItem + { + Name = AppResources.LockNow, + ExecuteAsync = () => LockAsync() + }, + new SettingsPageListItem + { + Name = AppResources.TwoStepLogin, + ExecuteAsync = () => TwoStepAsync() + } }; if (_supportsBiometric || _biometric) { @@ -485,7 +523,8 @@ namespace Bit.App.Pages var item = new SettingsPageListItem { Name = string.Format(AppResources.UnlockWith, biometricName), - SubLabel = _biometric ? AppResources.Enabled : AppResources.Disabled + SubLabel = _biometric ? AppResources.Enabled : AppResources.Disabled, + ExecuteAsync = () => UpdateBiometricAsync() }; securityItems.Insert(2, item); } @@ -510,38 +549,87 @@ namespace Bit.App.Pages } var accountItems = new List { - new SettingsPageListItem { Name = AppResources.FingerprintPhrase }, - new SettingsPageListItem { Name = AppResources.LogOut } + new SettingsPageListItem + { + Name = AppResources.FingerprintPhrase, + ExecuteAsync = () => FingerprintAsync() + }, + new SettingsPageListItem + { + Name = AppResources.LogOut, + ExecuteAsync = () => LogOutAsync() + } }; if (_showChangeMasterPassword) { - accountItems.Insert(0, new SettingsPageListItem { Name = AppResources.ChangeMasterPassword }); + accountItems.Insert(0, new SettingsPageListItem + { + Name = AppResources.ChangeMasterPassword, + ExecuteAsync = () => ChangePasswordAsync() + }); } var toolsItems = new List { - new SettingsPageListItem { Name = AppResources.ImportItems }, - new SettingsPageListItem { Name = AppResources.ExportVault } + new SettingsPageListItem + { + Name = AppResources.ImportItems, + ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => Import()) + }, + new SettingsPageListItem + { + Name = AppResources.ExportVault, + ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new ExportVaultPage())) + } }; if (IncludeLinksWithSubscriptionInfo()) { - toolsItems.Add(new SettingsPageListItem { Name = AppResources.LearnOrg }); - toolsItems.Add(new SettingsPageListItem { Name = AppResources.WebVault }); + toolsItems.Add(new SettingsPageListItem + { + Name = AppResources.LearnOrg, + ExecuteAsync = () => ShareAsync() + }); + toolsItems.Add(new SettingsPageListItem + { + Name = AppResources.WebVault, + ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => WebVault()) + }); } var otherItems = new List { - new SettingsPageListItem { Name = AppResources.Options }, - new SettingsPageListItem { Name = AppResources.About }, - new SettingsPageListItem { Name = AppResources.HelpAndFeedback }, + new SettingsPageListItem + { + Name = AppResources.Options, + ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new OptionsPage())) + }, + new SettingsPageListItem + { + Name = AppResources.About, + ExecuteAsync = () => AboutAsync() + }, + new SettingsPageListItem + { + Name = AppResources.HelpAndFeedback, + ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => Help()) + }, #if !FDROID new SettingsPageListItem { Name = AppResources.SubmitCrashLogs, SubLabel = _reportLoggingEnabled ? AppResources.Enabled : AppResources.Disabled, + ExecuteAsync = () => LoggerReportingAsync() }, #endif - new SettingsPageListItem { Name = AppResources.RateTheApp }, - new SettingsPageListItem { Name = AppResources.DeleteAccount } + new SettingsPageListItem + { + Name = AppResources.RateTheApp, + ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => Rate()) + }, + new SettingsPageListItem + { + Name = AppResources.DeleteAccount, + ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new DeleteAccountPage())) + } }; // TODO: improve this. Leaving this as is to reduce error possibility on the hotfix.