diff --git a/src/App/Controls/Settings/BaseSettingControlView.cs b/src/App/Controls/Settings/BaseSettingControlView.cs
index 714ebb143..b7cd718b0 100644
--- a/src/App/Controls/Settings/BaseSettingControlView.cs
+++ b/src/App/Controls/Settings/BaseSettingControlView.cs
@@ -1,14 +1,16 @@
-using Xamarin.Forms;
+using System.Runtime.CompilerServices;
+using Bit.App.Utilities;
+using Xamarin.Forms;
namespace Bit.App.Controls
{
public class BaseSettingItemView : ContentView
{
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(
- nameof(Subtitle), typeof(string), typeof(SwitchItemView), null, BindingMode.OneWay);
+ nameof(Subtitle), typeof(string), typeof(SwitchItemView), null);
public string Title
{
diff --git a/src/App/Controls/Settings/SettingChooserItemView.xaml.cs b/src/App/Controls/Settings/SettingChooserItemView.xaml.cs
index 3ab7dadf5..51df928b1 100644
--- a/src/App/Controls/Settings/SettingChooserItemView.xaml.cs
+++ b/src/App/Controls/Settings/SettingChooserItemView.xaml.cs
@@ -6,7 +6,7 @@ namespace Bit.App.Controls
public partial class SettingChooserItemView : BaseSettingItemView
{
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(
nameof(ChooseCommand), typeof(ICommand), typeof(ExternalLinkItemView));
diff --git a/src/App/Pages/Settings/SecuritySettingsPage.xaml b/src/App/Pages/Settings/SecuritySettingsPage.xaml
index c3f16753e..ac7fb3397 100644
--- a/src/App/Pages/Settings/SecuritySettingsPage.xaml
+++ b/src/App/Pages/Settings/SecuritySettingsPage.xaml
@@ -67,7 +67,7 @@
-
+
@@ -148,6 +150,7 @@
diff --git a/src/App/Pages/Settings/SecuritySettingsPageViewModel.cs b/src/App/Pages/Settings/SecuritySettingsPageViewModel.cs
index 8e98aa1fe..a33ae27ae 100644
--- a/src/App/Pages/Settings/SecuritySettingsPageViewModel.cs
+++ b/src/App/Pages/Settings/SecuritySettingsPageViewModel.cs
@@ -76,7 +76,7 @@ namespace Bit.App.Pages
_logger,
OnVaultTimeoutActionChangingAsync,
AppResources.SessionTimeoutAction,
- _ => _inited && !HasVaultTimeoutActionPolicy,
+ _ => _inited && !HasVaultTimeoutActionPolicy && IsVaultTimeoutActionLockAllowed,
ex => HandleException(ex));
ToggleUseThisDeviceToApproveLoginRequestsCommand = CreateDefaultAsyncCommnad(ToggleUseThisDeviceToApproveLoginRequestsAsync, _ => _inited);
@@ -129,6 +129,7 @@ namespace Bit.App.Pages
get => _canUnlockWithBiometrics;
set
{
+ TriggerVaultTimeoutActionLockAllowedPropertyChanged();
if (SetProperty(ref _canUnlockWithBiometrics, value))
{
((ICommand)ToggleCanUnlockWithBiometricsCommand).Execute(null);
@@ -141,6 +142,7 @@ namespace Bit.App.Pages
get => _canUnlockWithPin;
set
{
+ TriggerVaultTimeoutActionLockAllowedPropertyChanged();
if (SetProperty(ref _canUnlockWithPin, value))
{
((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
{
get => _customVaultTimeoutTime;
@@ -164,6 +170,7 @@ namespace Bit.App.Pages
MainThread.BeginInvokeOnMainThread(() => SetProperty(ref _customVaultTimeoutTime, oldValue));
});
}
+ TriggerVaultTimeoutActionLockAllowedPropertyChanged();
}
}
@@ -203,8 +210,6 @@ namespace Bit.App.Pages
public bool ShowChangeMasterPassword { get; private set; }
- private bool IsVaultTimeoutActionLockAllowed => _hasMasterPassword || _canUnlockWithBiometrics || _canUnlockWithPin;
-
private int? CurrentVaultTimeout => GetRawVaultTimeoutFrom(VaultTimeoutPickerViewModel.SelectedKey);
private bool IncludeLinksWithSubscriptionInfo => Device.RuntimePlatform != Device.iOS;
@@ -253,6 +258,7 @@ namespace Bit.App.Pages
TriggerPropertyChanged(nameof(VaultTimeoutPolicyDescription));
TriggerPropertyChanged(nameof(ShowChangeMasterPassword));
TriggerUpdateCustomVaultTimeoutPicker();
+ TriggerVaultTimeoutActionLockAllowedPropertyChanged();
ToggleUseThisDeviceToApproveLoginRequestsCommand.RaiseCanExecuteChanged();
ToggleCanUnlockWithBiometricsCommand.RaiseCanExecuteChanged();
ToggleCanUnlockWithPinCommand.RaiseCanExecuteChanged();
@@ -305,6 +311,7 @@ namespace Bit.App.Pages
{
_customVaultTimeoutTime = TimeSpan.FromMinutes(vaultTimeout);
}
+ TriggerVaultTimeoutActionLockAllowedPropertyChanged();
}
private async Task InitVaultTimeoutActionPickerAsync()
@@ -324,6 +331,7 @@ namespace Bit.App.Pages
}
VaultTimeoutActionPickerViewModel.Init(options, timeoutAction, IsVaultTimeoutActionLockAllowed ? VaultTimeoutAction.Lock : VaultTimeoutAction.Logout);
+ TriggerVaultTimeoutActionLockAllowedPropertyChanged();
}
private async Task ToggleUseThisDeviceToApproveLoginRequestsAsync()
@@ -360,6 +368,7 @@ namespace Bit.App.Pages
{
if (!_canUnlockWithBiometrics)
{
+ MainThread.BeginInvokeOnMainThread(() => TriggerPropertyChanged(nameof(CanUnlockWithBiometrics)));
await UpdateVaultTimeoutActionIfNeededAsync();
await _biometricsService.SetCanUnlockWithBiometricsAsync(CanUnlockWithBiometrics);
return;
@@ -375,11 +384,12 @@ namespace Bit.App.Pages
}
await _biometricsService.SetCanUnlockWithBiometricsAsync(CanUnlockWithBiometrics);
+ await InitVaultTimeoutActionPickerAsync();
}
public async Task ToggleCanUnlockWithPinAsync()
{
- if (!CanUnlockWithPin)
+ if (!_canUnlockWithPin)
{
await _vaultTimeoutService.ClearAsync();
await UpdateVaultTimeoutActionIfNeededAsync();
@@ -403,10 +413,12 @@ namespace Bit.App.Pages
AppResources.No);
await _userPinService.SetupPinAsync(newPin, requireMasterPasswordOnRestart);
+ await InitVaultTimeoutActionPickerAsync();
}
private async Task UpdateVaultTimeoutActionIfNeededAsync()
{
+ TriggerVaultTimeoutActionLockAllowedPropertyChanged();
if (IsVaultTimeoutActionLockAllowed)
{
return;
@@ -467,6 +479,16 @@ namespace Bit.App.Pages
TriggerPropertyChanged(nameof(CustomVaultTimeoutTime));
}
+ private void TriggerVaultTimeoutActionLockAllowedPropertyChanged()
+ {
+ MainThread.BeginInvokeOnMainThread(() =>
+ {
+ TriggerPropertyChanged(nameof(IsVaultTimeoutActionLockAllowed));
+ TriggerPropertyChanged(nameof(SetUpUnlockMethodLabel));
+ VaultTimeoutActionPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
+ });
+ }
+
private int? GetRawVaultTimeoutFrom(int vaultTimeoutPickerKey)
{
if (vaultTimeoutPickerKey == NEVER_SESSION_TIMEOUT_VALUE)
@@ -501,7 +523,7 @@ namespace Bit.App.Pages
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(CurrentVaultTimeout, timeoutActionKey);
_messagingService.Send(AppHelpers.VAULT_TIMEOUT_ACTION_CHANGED_MESSAGE_COMMAND);
-
+ TriggerVaultTimeoutActionLockAllowedPropertyChanged();
return true;
}
diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs
index bdb644256..859bd87b9 100644
--- a/src/App/Resources/AppResources.Designer.cs
+++ b/src/App/Resources/AppResources.Designer.cs
@@ -6227,6 +6227,15 @@ namespace Bit.App.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Set up an unlock option to change your vault timeout action..
+ ///
+ public static string SetUpAnUnlockOptionToChangeYourVaultTimeoutAction {
+ get {
+ return ResourceManager.GetString("SetUpAnUnlockOptionToChangeYourVaultTimeoutAction", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Set up TOTP.
///
diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx
index 0709e6934..6cd5fad9d 100644
--- a/src/App/Resources/AppResources.resx
+++ b/src/App/Resources/AppResources.resx
@@ -2862,4 +2862,7 @@ Do you want to switch to this account?
Account logged out.
+
+ Set up an unlock option to change your vault timeout action.
+
diff --git a/src/App/Styles/ControlTemplates.xaml b/src/App/Styles/ControlTemplates.xaml
index e61b80eda..6d75dddf9 100644
--- a/src/App/Styles/ControlTemplates.xaml
+++ b/src/App/Styles/ControlTemplates.xaml
@@ -6,6 +6,7 @@
x:Class="Bit.App.Styles.ControlTemplates">
+
diff --git a/src/App/Utilities/BoolToColorConverter.cs b/src/App/Utilities/BoolToColorConverter.cs
new file mode 100644
index 000000000..7fb4ffc32
--- /dev/null
+++ b/src/App/Utilities/BoolToColorConverter.cs
@@ -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();
+ }
+ }
+}
+