mirror of
https://github.com/bitwarden/android.git
synced 2024-12-26 10:58:29 +03:00
[PM-3340] Update timeout action for users without master password. (#2818)
* [PM-3340] Update timeout action for users without master password. * [PM-3340] PR fixes and refactor * [PM-3340] Raise command can execute. * [PM-3340] Fix converter name * [PM-3340] Fix variable naming --------- Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
This commit is contained in:
parent
d0ce89fedb
commit
7a65bf7fd7
8 changed files with 77 additions and 10 deletions
|
@ -1,14 +1,16 @@
|
||||||
using Xamarin.Forms;
|
using System.Runtime.CompilerServices;
|
||||||
|
using Bit.App.Utilities;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
namespace Bit.App.Controls
|
||||||
{
|
{
|
||||||
public class BaseSettingItemView : ContentView
|
public class BaseSettingItemView : ContentView
|
||||||
{
|
{
|
||||||
public static readonly BindableProperty TitleProperty = BindableProperty.Create(
|
public static readonly BindableProperty TitleProperty = BindableProperty.Create(
|
||||||
nameof(Title), typeof(string), typeof(SwitchItemView), null, BindingMode.OneWay);
|
nameof(Title), typeof(string), typeof(SwitchItemView), null);
|
||||||
|
|
||||||
public static readonly BindableProperty SubtitleProperty = BindableProperty.Create(
|
public static readonly BindableProperty SubtitleProperty = BindableProperty.Create(
|
||||||
nameof(Subtitle), typeof(string), typeof(SwitchItemView), null, BindingMode.OneWay);
|
nameof(Subtitle), typeof(string), typeof(SwitchItemView), null);
|
||||||
|
|
||||||
public string Title
|
public string Title
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace Bit.App.Controls
|
||||||
public partial class SettingChooserItemView : BaseSettingItemView
|
public partial class SettingChooserItemView : BaseSettingItemView
|
||||||
{
|
{
|
||||||
public static readonly BindableProperty DisplayValueProperty = BindableProperty.Create(
|
public static readonly BindableProperty DisplayValueProperty = BindableProperty.Create(
|
||||||
nameof(DisplayValue), typeof(string), typeof(SettingChooserItemView), null, BindingMode.OneWay);
|
nameof(DisplayValue), typeof(string), typeof(SettingChooserItemView), null);
|
||||||
|
|
||||||
public static readonly BindableProperty ChooseCommandProperty = BindableProperty.Create(
|
public static readonly BindableProperty ChooseCommandProperty = BindableProperty.Create(
|
||||||
nameof(ChooseCommand), typeof(ICommand), typeof(ExternalLinkItemView));
|
nameof(ChooseCommand), typeof(ICommand), typeof(ExternalLinkItemView));
|
||||||
|
|
|
@ -110,8 +110,10 @@
|
||||||
|
|
||||||
<controls:SettingChooserItemView
|
<controls:SettingChooserItemView
|
||||||
Title="{u:I18n SessionTimeoutAction}"
|
Title="{u:I18n SessionTimeoutAction}"
|
||||||
|
Subtitle="{Binding SetUpUnlockMethodLabel}"
|
||||||
DisplayValue="{Binding VaultTimeoutActionPickerViewModel.SelectedValue}"
|
DisplayValue="{Binding VaultTimeoutActionPickerViewModel.SelectedValue}"
|
||||||
ChooseCommand="{Binding VaultTimeoutActionPickerViewModel.SelectOptionCommand}"
|
ChooseCommand="{Binding VaultTimeoutActionPickerViewModel.SelectOptionCommand}"
|
||||||
|
IsEnabled="{Binding IsVaultTimeoutActionLockAllowed}"
|
||||||
AutomationId="VaultTimeoutActionChooser"
|
AutomationId="VaultTimeoutActionChooser"
|
||||||
StyleClass="settings-item-view"
|
StyleClass="settings-item-view"
|
||||||
HorizontalOptions="FillAndExpand"/>
|
HorizontalOptions="FillAndExpand"/>
|
||||||
|
@ -148,6 +150,7 @@
|
||||||
|
|
||||||
<controls:CustomLabel
|
<controls:CustomLabel
|
||||||
Text="{u:I18n LockNow}"
|
Text="{u:I18n LockNow}"
|
||||||
|
IsVisible="{Binding IsVaultTimeoutActionLockAllowed}"
|
||||||
StyleClass="settings-navigatable-label"
|
StyleClass="settings-navigatable-label"
|
||||||
AutomationId="LockNowLabel">
|
AutomationId="LockNowLabel">
|
||||||
<Label.GestureRecognizers>
|
<Label.GestureRecognizers>
|
||||||
|
|
|
@ -76,7 +76,7 @@ namespace Bit.App.Pages
|
||||||
_logger,
|
_logger,
|
||||||
OnVaultTimeoutActionChangingAsync,
|
OnVaultTimeoutActionChangingAsync,
|
||||||
AppResources.SessionTimeoutAction,
|
AppResources.SessionTimeoutAction,
|
||||||
_ => _inited && !HasVaultTimeoutActionPolicy,
|
_ => _inited && !HasVaultTimeoutActionPolicy && IsVaultTimeoutActionLockAllowed,
|
||||||
ex => HandleException(ex));
|
ex => HandleException(ex));
|
||||||
|
|
||||||
ToggleUseThisDeviceToApproveLoginRequestsCommand = CreateDefaultAsyncCommnad(ToggleUseThisDeviceToApproveLoginRequestsAsync, _ => _inited);
|
ToggleUseThisDeviceToApproveLoginRequestsCommand = CreateDefaultAsyncCommnad(ToggleUseThisDeviceToApproveLoginRequestsAsync, _ => _inited);
|
||||||
|
@ -129,6 +129,7 @@ namespace Bit.App.Pages
|
||||||
get => _canUnlockWithBiometrics;
|
get => _canUnlockWithBiometrics;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
TriggerVaultTimeoutActionLockAllowedPropertyChanged();
|
||||||
if (SetProperty(ref _canUnlockWithBiometrics, value))
|
if (SetProperty(ref _canUnlockWithBiometrics, value))
|
||||||
{
|
{
|
||||||
((ICommand)ToggleCanUnlockWithBiometricsCommand).Execute(null);
|
((ICommand)ToggleCanUnlockWithBiometricsCommand).Execute(null);
|
||||||
|
@ -141,6 +142,7 @@ namespace Bit.App.Pages
|
||||||
get => _canUnlockWithPin;
|
get => _canUnlockWithPin;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
TriggerVaultTimeoutActionLockAllowedPropertyChanged();
|
||||||
if (SetProperty(ref _canUnlockWithPin, value))
|
if (SetProperty(ref _canUnlockWithPin, value))
|
||||||
{
|
{
|
||||||
((ICommand)ToggleCanUnlockWithPinCommand).Execute(null);
|
((ICommand)ToggleCanUnlockWithPinCommand).Execute(null);
|
||||||
|
@ -148,6 +150,10 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsVaultTimeoutActionLockAllowed => _hasMasterPassword || _canUnlockWithBiometrics || _canUnlockWithPin;
|
||||||
|
|
||||||
|
public string SetUpUnlockMethodLabel => IsVaultTimeoutActionLockAllowed ? null : AppResources.SetUpAnUnlockOptionToChangeYourVaultTimeoutAction;
|
||||||
|
|
||||||
public TimeSpan? CustomVaultTimeoutTime
|
public TimeSpan? CustomVaultTimeoutTime
|
||||||
{
|
{
|
||||||
get => _customVaultTimeoutTime;
|
get => _customVaultTimeoutTime;
|
||||||
|
@ -164,6 +170,7 @@ namespace Bit.App.Pages
|
||||||
MainThread.BeginInvokeOnMainThread(() => SetProperty(ref _customVaultTimeoutTime, oldValue));
|
MainThread.BeginInvokeOnMainThread(() => SetProperty(ref _customVaultTimeoutTime, oldValue));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
TriggerVaultTimeoutActionLockAllowedPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,8 +210,6 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
public bool ShowChangeMasterPassword { get; private set; }
|
public bool ShowChangeMasterPassword { get; private set; }
|
||||||
|
|
||||||
private bool IsVaultTimeoutActionLockAllowed => _hasMasterPassword || _canUnlockWithBiometrics || _canUnlockWithPin;
|
|
||||||
|
|
||||||
private int? CurrentVaultTimeout => GetRawVaultTimeoutFrom(VaultTimeoutPickerViewModel.SelectedKey);
|
private int? CurrentVaultTimeout => GetRawVaultTimeoutFrom(VaultTimeoutPickerViewModel.SelectedKey);
|
||||||
|
|
||||||
private bool IncludeLinksWithSubscriptionInfo => Device.RuntimePlatform != Device.iOS;
|
private bool IncludeLinksWithSubscriptionInfo => Device.RuntimePlatform != Device.iOS;
|
||||||
|
@ -253,6 +258,7 @@ namespace Bit.App.Pages
|
||||||
TriggerPropertyChanged(nameof(VaultTimeoutPolicyDescription));
|
TriggerPropertyChanged(nameof(VaultTimeoutPolicyDescription));
|
||||||
TriggerPropertyChanged(nameof(ShowChangeMasterPassword));
|
TriggerPropertyChanged(nameof(ShowChangeMasterPassword));
|
||||||
TriggerUpdateCustomVaultTimeoutPicker();
|
TriggerUpdateCustomVaultTimeoutPicker();
|
||||||
|
TriggerVaultTimeoutActionLockAllowedPropertyChanged();
|
||||||
ToggleUseThisDeviceToApproveLoginRequestsCommand.RaiseCanExecuteChanged();
|
ToggleUseThisDeviceToApproveLoginRequestsCommand.RaiseCanExecuteChanged();
|
||||||
ToggleCanUnlockWithBiometricsCommand.RaiseCanExecuteChanged();
|
ToggleCanUnlockWithBiometricsCommand.RaiseCanExecuteChanged();
|
||||||
ToggleCanUnlockWithPinCommand.RaiseCanExecuteChanged();
|
ToggleCanUnlockWithPinCommand.RaiseCanExecuteChanged();
|
||||||
|
@ -305,6 +311,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
_customVaultTimeoutTime = TimeSpan.FromMinutes(vaultTimeout);
|
_customVaultTimeoutTime = TimeSpan.FromMinutes(vaultTimeout);
|
||||||
}
|
}
|
||||||
|
TriggerVaultTimeoutActionLockAllowedPropertyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InitVaultTimeoutActionPickerAsync()
|
private async Task InitVaultTimeoutActionPickerAsync()
|
||||||
|
@ -324,6 +331,7 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
VaultTimeoutActionPickerViewModel.Init(options, timeoutAction, IsVaultTimeoutActionLockAllowed ? VaultTimeoutAction.Lock : VaultTimeoutAction.Logout);
|
VaultTimeoutActionPickerViewModel.Init(options, timeoutAction, IsVaultTimeoutActionLockAllowed ? VaultTimeoutAction.Lock : VaultTimeoutAction.Logout);
|
||||||
|
TriggerVaultTimeoutActionLockAllowedPropertyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ToggleUseThisDeviceToApproveLoginRequestsAsync()
|
private async Task ToggleUseThisDeviceToApproveLoginRequestsAsync()
|
||||||
|
@ -360,6 +368,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
if (!_canUnlockWithBiometrics)
|
if (!_canUnlockWithBiometrics)
|
||||||
{
|
{
|
||||||
|
MainThread.BeginInvokeOnMainThread(() => TriggerPropertyChanged(nameof(CanUnlockWithBiometrics)));
|
||||||
await UpdateVaultTimeoutActionIfNeededAsync();
|
await UpdateVaultTimeoutActionIfNeededAsync();
|
||||||
await _biometricsService.SetCanUnlockWithBiometricsAsync(CanUnlockWithBiometrics);
|
await _biometricsService.SetCanUnlockWithBiometricsAsync(CanUnlockWithBiometrics);
|
||||||
return;
|
return;
|
||||||
|
@ -375,11 +384,12 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
await _biometricsService.SetCanUnlockWithBiometricsAsync(CanUnlockWithBiometrics);
|
await _biometricsService.SetCanUnlockWithBiometricsAsync(CanUnlockWithBiometrics);
|
||||||
|
await InitVaultTimeoutActionPickerAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ToggleCanUnlockWithPinAsync()
|
public async Task ToggleCanUnlockWithPinAsync()
|
||||||
{
|
{
|
||||||
if (!CanUnlockWithPin)
|
if (!_canUnlockWithPin)
|
||||||
{
|
{
|
||||||
await _vaultTimeoutService.ClearAsync();
|
await _vaultTimeoutService.ClearAsync();
|
||||||
await UpdateVaultTimeoutActionIfNeededAsync();
|
await UpdateVaultTimeoutActionIfNeededAsync();
|
||||||
|
@ -403,10 +413,12 @@ namespace Bit.App.Pages
|
||||||
AppResources.No);
|
AppResources.No);
|
||||||
|
|
||||||
await _userPinService.SetupPinAsync(newPin, requireMasterPasswordOnRestart);
|
await _userPinService.SetupPinAsync(newPin, requireMasterPasswordOnRestart);
|
||||||
|
await InitVaultTimeoutActionPickerAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateVaultTimeoutActionIfNeededAsync()
|
private async Task UpdateVaultTimeoutActionIfNeededAsync()
|
||||||
{
|
{
|
||||||
|
TriggerVaultTimeoutActionLockAllowedPropertyChanged();
|
||||||
if (IsVaultTimeoutActionLockAllowed)
|
if (IsVaultTimeoutActionLockAllowed)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -467,6 +479,16 @@ namespace Bit.App.Pages
|
||||||
TriggerPropertyChanged(nameof(CustomVaultTimeoutTime));
|
TriggerPropertyChanged(nameof(CustomVaultTimeoutTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TriggerVaultTimeoutActionLockAllowedPropertyChanged()
|
||||||
|
{
|
||||||
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
|
{
|
||||||
|
TriggerPropertyChanged(nameof(IsVaultTimeoutActionLockAllowed));
|
||||||
|
TriggerPropertyChanged(nameof(SetUpUnlockMethodLabel));
|
||||||
|
VaultTimeoutActionPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private int? GetRawVaultTimeoutFrom(int vaultTimeoutPickerKey)
|
private int? GetRawVaultTimeoutFrom(int vaultTimeoutPickerKey)
|
||||||
{
|
{
|
||||||
if (vaultTimeoutPickerKey == NEVER_SESSION_TIMEOUT_VALUE)
|
if (vaultTimeoutPickerKey == NEVER_SESSION_TIMEOUT_VALUE)
|
||||||
|
@ -501,7 +523,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(CurrentVaultTimeout, timeoutActionKey);
|
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(CurrentVaultTimeout, timeoutActionKey);
|
||||||
_messagingService.Send(AppHelpers.VAULT_TIMEOUT_ACTION_CHANGED_MESSAGE_COMMAND);
|
_messagingService.Send(AppHelpers.VAULT_TIMEOUT_ACTION_CHANGED_MESSAGE_COMMAND);
|
||||||
|
TriggerVaultTimeoutActionLockAllowedPropertyChanged();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
src/App/Resources/AppResources.Designer.cs
generated
9
src/App/Resources/AppResources.Designer.cs
generated
|
@ -6227,6 +6227,15 @@ namespace Bit.App.Resources {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Set up an unlock option to change your vault timeout action..
|
||||||
|
/// </summary>
|
||||||
|
public static string SetUpAnUnlockOptionToChangeYourVaultTimeoutAction {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("SetUpAnUnlockOptionToChangeYourVaultTimeoutAction", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Set up TOTP.
|
/// Looks up a localized string similar to Set up TOTP.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -2862,4 +2862,7 @@ Do you want to switch to this account?</value>
|
||||||
<data name="AccountLoggedOutBiometricExceeded" xml:space="preserve">
|
<data name="AccountLoggedOutBiometricExceeded" xml:space="preserve">
|
||||||
<value>Account logged out.</value>
|
<value>Account logged out.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="SetUpAnUnlockOptionToChangeYourVaultTimeoutAction" xml:space="preserve">
|
||||||
|
<value>Set up an unlock option to change your vault timeout action.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
x:Class="Bit.App.Styles.ControlTemplates">
|
x:Class="Bit.App.Styles.ControlTemplates">
|
||||||
|
|
||||||
<u:StringHasValueConverter x:Key="stringHasValueConverter" />
|
<u:StringHasValueConverter x:Key="stringHasValueConverter" />
|
||||||
|
<u:BoolEnablementToTextColorConverter x:Key="boolEnablementToTextColorConverter" />
|
||||||
|
|
||||||
<ControlTemplate x:Key="SettingControlTemplate">
|
<ControlTemplate x:Key="SettingControlTemplate">
|
||||||
<Grid
|
<Grid
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
MaxLines="2"
|
MaxLines="2"
|
||||||
Text="{TemplateBinding Title}"
|
Text="{TemplateBinding Title}"
|
||||||
|
TextColor="{TemplateBinding IsEnabled, Converter={StaticResource boolEnablementToTextColorConverter}}"
|
||||||
HorizontalOptions="StartAndExpand"
|
HorizontalOptions="StartAndExpand"
|
||||||
LineBreakMode="TailTruncation" />
|
LineBreakMode="TailTruncation" />
|
||||||
|
|
||||||
|
|
26
src/App/Utilities/BoolToColorConverter.cs
Normal file
26
src/App/Utilities/BoolToColorConverter.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Utilities
|
||||||
|
{
|
||||||
|
public class BoolEnablementToTextColorConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter,
|
||||||
|
System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (targetType == typeof(Color) && value is bool valueBool)
|
||||||
|
{
|
||||||
|
return valueBool ? ThemeManager.GetResourceColor("TextColor") :
|
||||||
|
ThemeManager.GetResourceColor("MutedColor");
|
||||||
|
}
|
||||||
|
throw new InvalidOperationException("The value must be a boolean with a Color target.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter,
|
||||||
|
System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue