mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 10:28:28 +03:00
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)
This commit is contained in:
parent
1f2fb3f796
commit
2d2a883b96
3 changed files with 118 additions and 143 deletions
|
@ -2,18 +2,13 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Controls;
|
using Bit.App.Controls;
|
||||||
using Bit.App.Pages.Accounts;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public partial class SettingsPage : BaseContentPage
|
public partial class SettingsPage : BaseContentPage
|
||||||
{
|
{
|
||||||
private readonly IDeviceActionService _deviceActionService;
|
|
||||||
private readonly TabsPage _tabsPage;
|
private readonly TabsPage _tabsPage;
|
||||||
private SettingsPageViewModel _vm;
|
private SettingsPageViewModel _vm;
|
||||||
|
|
||||||
|
@ -21,7 +16,6 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
_tabsPage = tabsPage;
|
_tabsPage = tabsPage;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
_vm = BindingContext as SettingsPageViewModel;
|
_vm = BindingContext as SettingsPageViewModel;
|
||||||
_vm.Page = this;
|
_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;
|
((ExtendedCollectionView)sender).SelectedItem = null;
|
||||||
if (!DoOnce())
|
if (e.CurrentSelection?.FirstOrDefault() is SettingsPageListItem item)
|
||||||
{
|
{
|
||||||
return;
|
_vm?.ExecuteSettingItemCommand.Execute(item);
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
@ -12,6 +13,8 @@ namespace Bit.App.Pages
|
||||||
public string SubLabel { get; set; }
|
public string SubLabel { get; set; }
|
||||||
public TimeSpan? Time { get; set; }
|
public TimeSpan? Time { get; set; }
|
||||||
public bool UseFrame { get; set; }
|
public bool UseFrame { get; set; }
|
||||||
|
public Func<Task> ExecuteAsync { get; set; }
|
||||||
|
|
||||||
public bool SubLabelTextEnabled => SubLabel == AppResources.Enabled;
|
public bool SubLabelTextEnabled => SubLabel == AppResources.Enabled;
|
||||||
public string LineBreakMode => SubLabel == null ? "TailTruncation" : "";
|
public string LineBreakMode => SubLabel == null ? "TailTruncation" : "";
|
||||||
public bool ShowSubLabel => SubLabel.Length != 0;
|
public bool ShowSubLabel => SubLabel.Length != 0;
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Pages.Accounts;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
@ -84,10 +85,14 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
GroupedItems = new ObservableRangeCollection<ISettingsPageListItem>();
|
GroupedItems = new ObservableRangeCollection<ISettingsPageListItem>();
|
||||||
PageTitle = AppResources.Settings;
|
PageTitle = AppResources.Settings;
|
||||||
|
|
||||||
|
ExecuteSettingItemCommand = new AsyncCommand<SettingsPageListItem>(item => item.ExecuteAsync(), onException: _loggerService.Exception, allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableRangeCollection<ISettingsPageListItem> GroupedItems { get; set; }
|
public ObservableRangeCollection<ISettingsPageListItem> GroupedItems { get; set; }
|
||||||
|
|
||||||
|
public IAsyncCommand<SettingsPageListItem> ExecuteSettingItemCommand { get; }
|
||||||
|
|
||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
{
|
{
|
||||||
_supportsBiometric = await _platformUtilsService.SupportsBiometricAsync();
|
_supportsBiometric = await _platformUtilsService.SupportsBiometricAsync();
|
||||||
|
@ -434,6 +439,8 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
public void BuildList()
|
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 doUpper = Device.RuntimePlatform != Device.Android;
|
||||||
var autofillItems = new List<SettingsPageListItem>();
|
var autofillItems = new List<SettingsPageListItem>();
|
||||||
if (Device.RuntimePlatform == Device.Android)
|
if (Device.RuntimePlatform == Device.Android)
|
||||||
|
@ -441,38 +448,69 @@ namespace Bit.App.Pages
|
||||||
autofillItems.Add(new SettingsPageListItem
|
autofillItems.Add(new SettingsPageListItem
|
||||||
{
|
{
|
||||||
Name = AppResources.AutofillServices,
|
Name = AppResources.AutofillServices,
|
||||||
SubLabel = _deviceActionService.AutofillServicesEnabled() ?
|
SubLabel = _deviceActionService.AutofillServicesEnabled() ? AppResources.Enabled : AppResources.Disabled,
|
||||||
AppResources.Enabled : AppResources.Disabled
|
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillServicesPage(Page as SettingsPage)))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_deviceActionService.SystemMajorVersion() >= 12)
|
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<SettingsPageListItem>
|
var manageItems = new List<SettingsPageListItem>
|
||||||
{
|
{
|
||||||
new SettingsPageListItem { Name = AppResources.Folders },
|
new SettingsPageListItem
|
||||||
new SettingsPageListItem { Name = AppResources.Sync, SubLabel = _lastSyncDate }
|
{
|
||||||
|
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<SettingsPageListItem>
|
var securityItems = new List<SettingsPageListItem>
|
||||||
{
|
{
|
||||||
new SettingsPageListItem { Name = AppResources.VaultTimeout, SubLabel = _vaultTimeoutDisplayValue },
|
new SettingsPageListItem
|
||||||
|
{
|
||||||
|
Name = AppResources.VaultTimeout,
|
||||||
|
SubLabel = _vaultTimeoutDisplayValue,
|
||||||
|
ExecuteAsync = () => VaultTimeoutAsync() },
|
||||||
new SettingsPageListItem
|
new SettingsPageListItem
|
||||||
{
|
{
|
||||||
Name = AppResources.VaultTimeoutAction,
|
Name = AppResources.VaultTimeoutAction,
|
||||||
SubLabel = _vaultTimeoutActionDisplayValue
|
SubLabel = _vaultTimeoutActionDisplayValue,
|
||||||
|
ExecuteAsync = () => VaultTimeoutActionAsync()
|
||||||
},
|
},
|
||||||
new SettingsPageListItem
|
new SettingsPageListItem
|
||||||
{
|
{
|
||||||
Name = AppResources.UnlockWithPIN,
|
Name = AppResources.UnlockWithPIN,
|
||||||
SubLabel = _pin ? AppResources.Enabled : AppResources.Disabled
|
SubLabel = _pin ? AppResources.Enabled : AppResources.Disabled,
|
||||||
|
ExecuteAsync = () => UpdatePinAsync()
|
||||||
},
|
},
|
||||||
new SettingsPageListItem { Name = AppResources.LockNow },
|
new SettingsPageListItem
|
||||||
new SettingsPageListItem { Name = AppResources.TwoStepLogin }
|
{
|
||||||
|
Name = AppResources.LockNow,
|
||||||
|
ExecuteAsync = () => LockAsync()
|
||||||
|
},
|
||||||
|
new SettingsPageListItem
|
||||||
|
{
|
||||||
|
Name = AppResources.TwoStepLogin,
|
||||||
|
ExecuteAsync = () => TwoStepAsync()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if (_supportsBiometric || _biometric)
|
if (_supportsBiometric || _biometric)
|
||||||
{
|
{
|
||||||
|
@ -485,7 +523,8 @@ namespace Bit.App.Pages
|
||||||
var item = new SettingsPageListItem
|
var item = new SettingsPageListItem
|
||||||
{
|
{
|
||||||
Name = string.Format(AppResources.UnlockWith, biometricName),
|
Name = string.Format(AppResources.UnlockWith, biometricName),
|
||||||
SubLabel = _biometric ? AppResources.Enabled : AppResources.Disabled
|
SubLabel = _biometric ? AppResources.Enabled : AppResources.Disabled,
|
||||||
|
ExecuteAsync = () => UpdateBiometricAsync()
|
||||||
};
|
};
|
||||||
securityItems.Insert(2, item);
|
securityItems.Insert(2, item);
|
||||||
}
|
}
|
||||||
|
@ -510,38 +549,87 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
var accountItems = new List<SettingsPageListItem>
|
var accountItems = new List<SettingsPageListItem>
|
||||||
{
|
{
|
||||||
new SettingsPageListItem { Name = AppResources.FingerprintPhrase },
|
new SettingsPageListItem
|
||||||
new SettingsPageListItem { Name = AppResources.LogOut }
|
{
|
||||||
|
Name = AppResources.FingerprintPhrase,
|
||||||
|
ExecuteAsync = () => FingerprintAsync()
|
||||||
|
},
|
||||||
|
new SettingsPageListItem
|
||||||
|
{
|
||||||
|
Name = AppResources.LogOut,
|
||||||
|
ExecuteAsync = () => LogOutAsync()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if (_showChangeMasterPassword)
|
if (_showChangeMasterPassword)
|
||||||
{
|
{
|
||||||
accountItems.Insert(0, new SettingsPageListItem { Name = AppResources.ChangeMasterPassword });
|
accountItems.Insert(0, new SettingsPageListItem
|
||||||
|
{
|
||||||
|
Name = AppResources.ChangeMasterPassword,
|
||||||
|
ExecuteAsync = () => ChangePasswordAsync()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
var toolsItems = new List<SettingsPageListItem>
|
var toolsItems = new List<SettingsPageListItem>
|
||||||
{
|
{
|
||||||
new SettingsPageListItem { Name = AppResources.ImportItems },
|
new SettingsPageListItem
|
||||||
new SettingsPageListItem { Name = AppResources.ExportVault }
|
{
|
||||||
|
Name = AppResources.ImportItems,
|
||||||
|
ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => Import())
|
||||||
|
},
|
||||||
|
new SettingsPageListItem
|
||||||
|
{
|
||||||
|
Name = AppResources.ExportVault,
|
||||||
|
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new ExportVaultPage()))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if (IncludeLinksWithSubscriptionInfo())
|
if (IncludeLinksWithSubscriptionInfo())
|
||||||
{
|
{
|
||||||
toolsItems.Add(new SettingsPageListItem { Name = AppResources.LearnOrg });
|
toolsItems.Add(new SettingsPageListItem
|
||||||
toolsItems.Add(new SettingsPageListItem { Name = AppResources.WebVault });
|
{
|
||||||
|
Name = AppResources.LearnOrg,
|
||||||
|
ExecuteAsync = () => ShareAsync()
|
||||||
|
});
|
||||||
|
toolsItems.Add(new SettingsPageListItem
|
||||||
|
{
|
||||||
|
Name = AppResources.WebVault,
|
||||||
|
ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => WebVault())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var otherItems = new List<SettingsPageListItem>
|
var otherItems = new List<SettingsPageListItem>
|
||||||
{
|
{
|
||||||
new SettingsPageListItem { Name = AppResources.Options },
|
new SettingsPageListItem
|
||||||
new SettingsPageListItem { Name = AppResources.About },
|
{
|
||||||
new SettingsPageListItem { Name = AppResources.HelpAndFeedback },
|
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
|
#if !FDROID
|
||||||
new SettingsPageListItem
|
new SettingsPageListItem
|
||||||
{
|
{
|
||||||
Name = AppResources.SubmitCrashLogs,
|
Name = AppResources.SubmitCrashLogs,
|
||||||
SubLabel = _reportLoggingEnabled ? AppResources.Enabled : AppResources.Disabled,
|
SubLabel = _reportLoggingEnabled ? AppResources.Enabled : AppResources.Disabled,
|
||||||
|
ExecuteAsync = () => LoggerReportingAsync()
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
new SettingsPageListItem { Name = AppResources.RateTheApp },
|
new SettingsPageListItem
|
||||||
new SettingsPageListItem { Name = AppResources.DeleteAccount }
|
{
|
||||||
|
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.
|
// TODO: improve this. Leaving this as is to reduce error possibility on the hotfix.
|
||||||
|
|
Loading…
Reference in a new issue