mirror of
https://github.com/bitwarden/mobile
synced 2025-12-15 07:43:37 +00:00
PM-3349 PM-3350 Removed AsyncCommand "wrapper" and added AsyncRelayCommand directly in all ViewModels that were using the other one.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
namespace Bit.App.Controls
|
||||||
{
|
{
|
||||||
@@ -37,17 +37,14 @@ namespace Bit.App.Controls
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
ToggleVisibililtyCommand = new AsyncCommand(ToggleVisibilityAsync,
|
ToggleVisibililtyCommand = new AsyncRelayCommand(ToggleVisibilityAsync,
|
||||||
onException: ex => _logger.Value.Exception(ex),
|
AsyncRelayCommandOptions.None);
|
||||||
allowsMultipleExecutions: false);
|
|
||||||
|
|
||||||
SelectAccountCommand = new AsyncCommand<AccountViewCellViewModel>(SelectAccountAsync,
|
SelectAccountCommand = new AsyncRelayCommand<AccountViewCellViewModel>(SelectAccountAsync,
|
||||||
onException: ex => _logger.Value.Exception(ex),
|
AsyncRelayCommandOptions.None);
|
||||||
allowsMultipleExecutions: false);
|
|
||||||
|
|
||||||
LongPressAccountCommand = new AsyncCommand<AccountViewCellViewModel>(LongPressAccountAsync,
|
LongPressAccountCommand = new AsyncRelayCommand<AccountViewCellViewModel>(LongPressAccountAsync,
|
||||||
onException: ex => _logger.Value.Exception(ex),
|
AsyncRelayCommandOptions.None);
|
||||||
allowsMultipleExecutions: false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccountSwitchingOverlayViewModel ViewModel => BindingContext as AccountSwitchingOverlayViewModel;
|
public AccountSwitchingOverlayViewModel ViewModel => BindingContext as AccountSwitchingOverlayViewModel;
|
||||||
@@ -70,13 +67,20 @@ namespace Bit.App.Controls
|
|||||||
|
|
||||||
public async Task ToggleVisibilityAsync()
|
public async Task ToggleVisibilityAsync()
|
||||||
{
|
{
|
||||||
if (IsVisible)
|
try
|
||||||
{
|
{
|
||||||
await HideAsync();
|
if (IsVisible)
|
||||||
|
{
|
||||||
|
await HideAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ShowAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await ShowAsync();
|
_logger.Value.Exception(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,12 +176,13 @@ namespace Bit.App.Controls
|
|||||||
|
|
||||||
private async Task LongPressAccountAsync(AccountViewCellViewModel item)
|
private async Task LongPressAccountAsync(AccountViewCellViewModel item)
|
||||||
{
|
{
|
||||||
if (!LongPressAccountEnabled || item == null || !item.IsAccount)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (!LongPressAccountEnabled || item == null || !item.IsAccount)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
await HideAsync();
|
await HideAsync();
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ namespace Bit.App.Controls
|
|||||||
_stateService = stateService;
|
_stateService = stateService;
|
||||||
_messagingService = messagingService;
|
_messagingService = messagingService;
|
||||||
|
|
||||||
SelectAccountCommand = new AsyncCommand<AccountViewCellViewModel>(SelectAccountAsync,
|
SelectAccountCommand = CreateDefaultAsyncRelayCommand<AccountViewCellViewModel>(SelectAccountAsync,
|
||||||
onException: ex => logger.Exception(ex),
|
onException: ex => logger.Exception(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
LongPressAccountCommand = new AsyncCommand<Tuple<ContentPage, AccountViewCellViewModel>>(LongPressAccountAsync,
|
LongPressAccountCommand = CreateDefaultAsyncRelayCommand<Tuple<ContentPage, AccountViewCellViewModel>>(LongPressAccountAsync,
|
||||||
onException: ex => logger.Exception(ex),
|
onException: ex => logger.Exception(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace Bit.App.Lists.ItemViewModels.CustomFields
|
|||||||
_eventService = eventService;
|
_eventService = eventService;
|
||||||
|
|
||||||
CopyFieldCommand = new Command(() => copyFieldCommand?.Execute(Field));
|
CopyFieldCommand = new Command(() => copyFieldCommand?.Execute(Field));
|
||||||
ToggleHiddenValueCommand = new AsyncCommand(ToggleHiddenValueAsync, null, ex =>
|
ToggleHiddenValueCommand = CreateDefaultAsyncRelayCommand(ToggleHiddenValueAsync, null, ex =>
|
||||||
{
|
{
|
||||||
//#if !FDROID
|
//#if !FDROID
|
||||||
// Microsoft.AppCenter.Crashes.Crashes.TrackError(ex);
|
// Microsoft.AppCenter.Crashes.Crashes.TrackError(ex);
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
using System;
|
using System.Windows.Input;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Bit.App.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -26,7 +23,7 @@ namespace Bit.App.Pages
|
|||||||
IdentityUrl = _environmentService.IdentityUrl;
|
IdentityUrl = _environmentService.IdentityUrl;
|
||||||
IconsUrl = _environmentService.IconsUrl;
|
IconsUrl = _environmentService.IconsUrl;
|
||||||
NotificationsUrls = _environmentService.NotificationsUrl;
|
NotificationsUrls = _environmentService.NotificationsUrl;
|
||||||
SubmitCommand = new AsyncCommand(SubmitAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
SubmitCommand = CreateDefaultAsyncRelayCommand(SubmitAsync, onException: OnSubmitException, allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICommand SubmitCommand { get; }
|
public ICommand SubmitCommand { get; }
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Windows.Input;
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Bit.App.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -25,7 +23,7 @@ namespace Bit.App.Pages
|
|||||||
_logger = ServiceContainer.Resolve<ILogger>();
|
_logger = ServiceContainer.Resolve<ILogger>();
|
||||||
|
|
||||||
PageTitle = AppResources.PasswordHint;
|
PageTitle = AppResources.PasswordHint;
|
||||||
SubmitCommand = new AsyncCommand(SubmitAsync,
|
SubmitCommand = CreateDefaultAsyncRelayCommand(SubmitAsync,
|
||||||
onException: ex =>
|
onException: ex =>
|
||||||
{
|
{
|
||||||
_logger.Exception(ex);
|
_logger.Exception(ex);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Bit.Core.Utilities;
|
|||||||
|
|
||||||
using Microsoft.Maui.Controls;
|
using Microsoft.Maui.Controls;
|
||||||
using Microsoft.Maui;
|
using Microsoft.Maui;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -50,12 +51,12 @@ namespace Bit.App.Pages
|
|||||||
AllowActiveAccountSelection = true
|
AllowActiveAccountSelection = true
|
||||||
};
|
};
|
||||||
RememberEmailCommand = new Command(() => RememberEmail = !RememberEmail);
|
RememberEmailCommand = new Command(() => RememberEmail = !RememberEmail);
|
||||||
ContinueCommand = new AsyncCommand(ContinueToLoginStepAsync, allowsMultipleExecutions: false);
|
ContinueCommand = CreateDefaultAsyncRelayCommand(ContinueToLoginStepAsync, allowsMultipleExecutions: false);
|
||||||
CreateAccountCommand = new AsyncCommand(async () => Device.InvokeOnMainThreadAsync(StartRegisterAction),
|
CreateAccountCommand = CreateDefaultAsyncRelayCommand(async () => Device.InvokeOnMainThreadAsync(StartRegisterAction),
|
||||||
onException: _logger.Exception, allowsMultipleExecutions: false);
|
onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||||
CloseCommand = new AsyncCommand(async () => Device.InvokeOnMainThreadAsync(CloseAction),
|
CloseCommand = CreateDefaultAsyncRelayCommand(async () => Device.InvokeOnMainThreadAsync(CloseAction),
|
||||||
onException: _logger.Exception, allowsMultipleExecutions: false);
|
onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||||
ShowEnvironmentPickerCommand = new AsyncCommand(ShowEnvironmentPickerAsync,
|
ShowEnvironmentPickerCommand = CreateDefaultAsyncRelayCommand(ShowEnvironmentPickerAsync,
|
||||||
onException: _logger.Exception, allowsMultipleExecutions: false);
|
onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||||
InitAsync().FireAndForget();
|
InitAsync().FireAndForget();
|
||||||
}
|
}
|
||||||
@@ -113,10 +114,10 @@ namespace Bit.App.Pages
|
|||||||
public Action StartEnvironmentAction { get; set; }
|
public Action StartEnvironmentAction { get; set; }
|
||||||
public Action CloseAction { get; set; }
|
public Action CloseAction { get; set; }
|
||||||
public Command RememberEmailCommand { get; set; }
|
public Command RememberEmailCommand { get; set; }
|
||||||
public AsyncCommand ContinueCommand { get; }
|
public AsyncRelayCommand ContinueCommand { get; }
|
||||||
public AsyncCommand CloseCommand { get; }
|
public AsyncRelayCommand CloseCommand { get; }
|
||||||
public AsyncCommand CreateAccountCommand { get; }
|
public AsyncRelayCommand CreateAccountCommand { get; }
|
||||||
public AsyncCommand ShowEnvironmentPickerCommand { get; }
|
public AsyncRelayCommand ShowEnvironmentPickerCommand { get; }
|
||||||
|
|
||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -55,19 +55,19 @@ namespace Bit.App.Pages
|
|||||||
PageTitle = AppResources.LogInInitiated;
|
PageTitle = AppResources.LogInInitiated;
|
||||||
RememberThisDevice = true;
|
RememberThisDevice = true;
|
||||||
|
|
||||||
ApproveWithMyOtherDeviceCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithDeviceAction),
|
ApproveWithMyOtherDeviceCommand = CreateDefaultAsyncRelayCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithDeviceAction),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
RequestAdminApprovalCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(RequestAdminApprovalAction),
|
RequestAdminApprovalCommand = CreateDefaultAsyncRelayCommand(() => SetDeviceTrustAndInvokeAsync(RequestAdminApprovalAction),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
ApproveWithMasterPasswordCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithMasterPasswordAction),
|
ApproveWithMasterPasswordCommand = CreateDefaultAsyncRelayCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithMasterPasswordAction),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
ContinueCommand = new AsyncCommand(CreateNewSsoUserAsync,
|
ContinueCommand = CreateDefaultAsyncRelayCommand(CreateNewSsoUserAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ namespace Bit.App.Pages
|
|||||||
PageTitle = AppResources.Bitwarden;
|
PageTitle = AppResources.Bitwarden;
|
||||||
TogglePasswordCommand = new Command(TogglePassword);
|
TogglePasswordCommand = new Command(TogglePassword);
|
||||||
LogInCommand = new Command(async () => await LogInAsync());
|
LogInCommand = new Command(async () => await LogInAsync());
|
||||||
MoreCommand = new AsyncCommand(MoreAsync, onException: _logger.Exception, allowsMultipleExecutions: false);
|
MoreCommand = CreateDefaultAsyncRelayCommand(MoreAsync, onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||||
LogInWithDeviceCommand = new AsyncCommand(() => Device.InvokeOnMainThreadAsync(LogInWithDeviceAction), onException: _logger.Exception, allowsMultipleExecutions: false);
|
LogInWithDeviceCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(LogInWithDeviceAction), onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||||
|
|
||||||
AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger)
|
AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ namespace Bit.App.Pages
|
|||||||
_cryptoFunctionService = ServiceContainer.Resolve<ICryptoFunctionService>();
|
_cryptoFunctionService = ServiceContainer.Resolve<ICryptoFunctionService>();
|
||||||
_cryptoService = ServiceContainer.Resolve<ICryptoService>();
|
_cryptoService = ServiceContainer.Resolve<ICryptoService>();
|
||||||
|
|
||||||
CreatePasswordlessLoginCommand = new AsyncCommand(CreatePasswordlessLoginAsync,
|
CreatePasswordlessLoginCommand = CreateDefaultAsyncRelayCommand(CreatePasswordlessLoginAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
CloseCommand = new AsyncCommand(() => MainThread.InvokeOnMainThreadAsync(CloseAction),
|
CloseCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(CloseAction),
|
||||||
onException: _logger.Exception,
|
onException: _logger.Exception,
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
PageTitle = AppResources.LogInRequested;
|
PageTitle = AppResources.LogInRequested;
|
||||||
|
|
||||||
AcceptRequestCommand = new AsyncCommand(() => PasswordlessLoginAsync(true),
|
AcceptRequestCommand = CreateDefaultAsyncRelayCommand(() => PasswordlessLoginAsync(true),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
RejectRequestCommand = new AsyncCommand(() => PasswordlessLoginAsync(false),
|
RejectRequestCommand = CreateDefaultAsyncRelayCommand(() => PasswordlessLoginAsync(false),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace Bit.App.Pages
|
|||||||
_cryptoService = ServiceContainer.Resolve<ICryptoService>();
|
_cryptoService = ServiceContainer.Resolve<ICryptoService>();
|
||||||
|
|
||||||
PageTitle = AppResources.Bitwarden;
|
PageTitle = AppResources.Bitwarden;
|
||||||
LogInCommand = new AsyncCommand(LogInAsync, allowsMultipleExecutions: false);
|
LogInCommand = CreateDefaultAsyncRelayCommand(LogInAsync, allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string OrgIdentifier
|
public string OrgIdentifier
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
PageTitle = AppResources.TwoStepLogin;
|
PageTitle = AppResources.TwoStepLogin;
|
||||||
SubmitCommand = new Command(async () => await SubmitAsync());
|
SubmitCommand = new Command(async () => await SubmitAsync());
|
||||||
MoreCommand = new AsyncCommand(MoreAsync, onException: _logger.Exception, allowsMultipleExecutions: false);
|
MoreCommand = CreateDefaultAsyncRelayCommand(MoreAsync, onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string TotpInstruction
|
public string TotpInstruction
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Bit.Core.Utilities;
|
|||||||
using Microsoft.Maui.Controls;
|
using Microsoft.Maui.Controls;
|
||||||
using Microsoft.Maui;
|
using Microsoft.Maui;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -25,14 +26,14 @@ namespace Bit.App.Pages
|
|||||||
PageTitle = AppResources.UpdateMasterPassword;
|
PageTitle = AppResources.UpdateMasterPassword;
|
||||||
TogglePasswordCommand = new Command(TogglePassword);
|
TogglePasswordCommand = new Command(TogglePassword);
|
||||||
ToggleConfirmPasswordCommand = new Command(ToggleConfirmPassword);
|
ToggleConfirmPasswordCommand = new Command(ToggleConfirmPassword);
|
||||||
SubmitCommand = new AsyncCommand(SubmitAsync,
|
SubmitCommand = CreateDefaultAsyncRelayCommand(SubmitAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
_userVerificationService = ServiceContainer.Resolve<IUserVerificationService>();
|
_userVerificationService = ServiceContainer.Resolve<IUserVerificationService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncCommand SubmitCommand { get; }
|
public AsyncRelayCommand SubmitCommand { get; }
|
||||||
public Command TogglePasswordCommand { get; }
|
public Command TogglePasswordCommand { get; }
|
||||||
public Command ToggleConfirmPasswordCommand { get; }
|
public Command ToggleConfirmPasswordCommand { get; }
|
||||||
public Action UpdateTempPasswordSuccessAction { get; set; }
|
public Action UpdateTempPasswordSuccessAction { get; set; }
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ namespace Bit.App.Pages
|
|||||||
PageTitle = AppResources.VerificationCode;
|
PageTitle = AppResources.VerificationCode;
|
||||||
|
|
||||||
TogglePasswordCommand = new Command(TogglePassword);
|
TogglePasswordCommand = new Command(TogglePassword);
|
||||||
MainActionCommand = new AsyncCommand(MainActionAsync, allowsMultipleExecutions: false);
|
MainActionCommand = CreateDefaultAsyncRelayCommand(MainActionAsync, allowsMultipleExecutions: false);
|
||||||
RequestOTPCommand = new AsyncCommand(RequestOTPAsync, allowsMultipleExecutions: false);
|
RequestOTPCommand = CreateDefaultAsyncRelayCommand(RequestOTPAsync, allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShowPassword
|
public bool ShowPassword
|
||||||
|
|||||||
@@ -1,27 +1,13 @@
|
|||||||
using System;
|
using Bit.App.Controls;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Exceptions;
|
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
using Microsoft.Maui.Networking;
|
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public abstract class BaseViewModel : ExtendedViewModel
|
public abstract class BaseViewModel : ExtendedViewModel
|
||||||
{
|
{
|
||||||
private string _pageTitle = string.Empty;
|
private string _pageTitle = string.Empty;
|
||||||
private AvatarImageSource _avatar;
|
private AvatarImageSource _avatar;
|
||||||
private LazyResolve<IDeviceActionService> _deviceActionService = new LazyResolve<IDeviceActionService>();
|
|
||||||
private LazyResolve<IPlatformUtilsService> _platformUtilsService = new LazyResolve<IPlatformUtilsService>();
|
|
||||||
private LazyResolve<ILogger> _logger = new LazyResolve<ILogger>();
|
|
||||||
|
|
||||||
public string PageTitle
|
public string PageTitle
|
||||||
{
|
{
|
||||||
@@ -37,29 +23,6 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public ContentPage Page { get; set; }
|
public ContentPage Page { get; set; }
|
||||||
|
|
||||||
protected void HandleException(Exception ex, string message = null)
|
|
||||||
{
|
|
||||||
if (ex is ApiException apiException && apiException.Error != null)
|
|
||||||
{
|
|
||||||
message = apiException.Error.GetSingleMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
Microsoft.Maui.ApplicationModel.MainThread.InvokeOnMainThreadAsync(async () =>
|
|
||||||
{
|
|
||||||
await _deviceActionService.Value.HideLoadingAsync();
|
|
||||||
await _platformUtilsService.Value.ShowDialogAsync(message ?? AppResources.GenericErrorMessage);
|
|
||||||
}).FireAndForget();
|
|
||||||
_logger.Value.Exception(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AsyncCommand CreateDefaultAsyncCommnad(Func<Task> execute, Func<bool> canExecute = null)
|
|
||||||
{
|
|
||||||
return new AsyncCommand(execute,
|
|
||||||
canExecute,
|
|
||||||
ex => HandleException(ex),
|
|
||||||
allowsMultipleExecutions: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task<bool> HasConnectivityAsync()
|
protected async Task<bool> HasConnectivityAsync()
|
||||||
{
|
{
|
||||||
if (Connectivity.NetworkAccess == NetworkAccess.None)
|
if (Connectivity.NetworkAccess == NetworkAccess.None)
|
||||||
|
|||||||
@@ -89,11 +89,11 @@ namespace Bit.App.Pages
|
|||||||
};
|
};
|
||||||
|
|
||||||
UsernameTypePromptHelpCommand = new Command(UsernameTypePromptHelp);
|
UsernameTypePromptHelpCommand = new Command(UsernameTypePromptHelp);
|
||||||
RegenerateCommand = new AsyncCommand(RegenerateAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
RegenerateCommand = CreateDefaultAsyncRelayCommand(RegenerateAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
||||||
RegenerateUsernameCommand = new AsyncCommand(RegenerateUsernameAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
RegenerateUsernameCommand = CreateDefaultAsyncRelayCommand(RegenerateUsernameAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
||||||
ToggleForwardedEmailHiddenValueCommand = new Command(() => ShowForwardedEmailApiSecret = !ShowForwardedEmailApiSecret);
|
ToggleForwardedEmailHiddenValueCommand = new Command(() => ShowForwardedEmailApiSecret = !ShowForwardedEmailApiSecret);
|
||||||
CopyCommand = new AsyncCommand(CopyAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
|
CopyCommand = CreateDefaultAsyncRelayCommand(CopyAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
|
||||||
CloseCommand = new AsyncCommand(CloseAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
|
CloseCommand = CreateDefaultAsyncRelayCommand(CloseAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GeneratorType> GeneratorTypeOptions { get; set; }
|
public List<GeneratorType> GeneratorTypeOptions { get; set; }
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Bit.App.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -33,10 +32,10 @@ namespace Bit.App.Pages
|
|||||||
_onSelectionChangingAsync = onSelectionChangingAsync;
|
_onSelectionChangingAsync = onSelectionChangingAsync;
|
||||||
_title = title;
|
_title = title;
|
||||||
|
|
||||||
SelectOptionCommand = new AsyncCommand(SelectOptionAsync, canExecuteSelectOptionCommand, onSelectOptionCommandException, allowsMultipleExecutions: false);
|
SelectOptionCommand = CreateDefaultAsyncRelayCommand(SelectOptionAsync, canExecuteSelectOptionCommand, onSelectOptionCommandException, allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncCommand SelectOptionCommand { get; }
|
public AsyncRelayCommand SelectOptionCommand { get; }
|
||||||
|
|
||||||
public TKey SelectedKey => _selectedKey;
|
public TKey SelectedKey => _selectedKey;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
using System;
|
using System.Windows.Input;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.Maui.ApplicationModel;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Bit.App.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -29,32 +26,32 @@ namespace Bit.App.Pages
|
|||||||
var environmentService = ServiceContainer.Resolve<IEnvironmentService>();
|
var environmentService = ServiceContainer.Resolve<IEnvironmentService>();
|
||||||
var clipboardService = ServiceContainer.Resolve<IClipboardService>();
|
var clipboardService = ServiceContainer.Resolve<IClipboardService>();
|
||||||
|
|
||||||
ToggleSubmitCrashLogsCommand = CreateDefaultAsyncCommnad(ToggleSubmitCrashLogsAsync);
|
ToggleSubmitCrashLogsCommand = CreateDefaultAsyncRelayCommand(ToggleSubmitCrashLogsAsync, allowsMultipleExecutions: false);
|
||||||
|
|
||||||
GoToHelpCenterCommand = CreateDefaultAsyncCommnad(
|
GoToHelpCenterCommand = CreateDefaultAsyncRelayCommand(
|
||||||
() => LaunchUriAsync(AppResources.LearnMoreAboutHowToUseBitwardenOnTheHelpCenter,
|
() => LaunchUriAsync(AppResources.LearnMoreAboutHowToUseBitwardenOnTheHelpCenter,
|
||||||
AppResources.ContinueToHelpCenter,
|
AppResources.ContinueToHelpCenter,
|
||||||
ExternalLinksConstants.HELP_CENTER));
|
ExternalLinksConstants.HELP_CENTER), allowsMultipleExecutions: false);
|
||||||
|
|
||||||
ContactBitwardenSupportCommand = CreateDefaultAsyncCommnad(
|
ContactBitwardenSupportCommand = CreateDefaultAsyncRelayCommand(
|
||||||
() => LaunchUriAsync(AppResources.ContactSupportDescriptionLong,
|
() => LaunchUriAsync(AppResources.ContactSupportDescriptionLong,
|
||||||
AppResources.ContinueToContactSupport,
|
AppResources.ContinueToContactSupport,
|
||||||
ExternalLinksConstants.CONTACT_SUPPORT));
|
ExternalLinksConstants.CONTACT_SUPPORT), allowsMultipleExecutions: false);
|
||||||
|
|
||||||
GoToWebVaultCommand = CreateDefaultAsyncCommnad(
|
GoToWebVaultCommand = CreateDefaultAsyncRelayCommand(
|
||||||
() => LaunchUriAsync(AppResources.ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp,
|
() => LaunchUriAsync(AppResources.ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp,
|
||||||
AppResources.ContinueToWebApp,
|
AppResources.ContinueToWebApp,
|
||||||
environmentService.GetWebVaultUrl()));
|
environmentService.GetWebVaultUrl()), allowsMultipleExecutions: false);
|
||||||
|
|
||||||
GoToLearnAboutOrgsCommand = CreateDefaultAsyncCommnad(
|
GoToLearnAboutOrgsCommand = CreateDefaultAsyncRelayCommand(
|
||||||
() => LaunchUriAsync(AppResources.LearnAboutOrganizationsDescriptionLong,
|
() => LaunchUriAsync(AppResources.LearnAboutOrganizationsDescriptionLong,
|
||||||
string.Format(AppResources.ContinueToX, ExternalLinksConstants.BITWARDEN_WEBSITE),
|
string.Format(AppResources.ContinueToX, ExternalLinksConstants.BITWARDEN_WEBSITE),
|
||||||
ExternalLinksConstants.HELP_ABOUT_ORGANIZATIONS));
|
ExternalLinksConstants.HELP_ABOUT_ORGANIZATIONS), allowsMultipleExecutions: false);
|
||||||
|
|
||||||
RateTheAppCommand = CreateDefaultAsyncCommnad(RateAppAsync);
|
RateTheAppCommand = CreateDefaultAsyncRelayCommand(RateAppAsync, allowsMultipleExecutions: false);
|
||||||
|
|
||||||
CopyAppInfoCommand = CreateDefaultAsyncCommnad(
|
CopyAppInfoCommand = CreateDefaultAsyncRelayCommand(
|
||||||
() => clipboardService.CopyTextAsync(AppInfo));
|
() => clipboardService.CopyTextAsync(AppInfo), allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShouldSubmitCrashLogs
|
public bool ShouldSubmitCrashLogs
|
||||||
@@ -80,7 +77,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncCommand ToggleSubmitCrashLogsCommand { get; }
|
public AsyncRelayCommand ToggleSubmitCrashLogsCommand { get; }
|
||||||
public ICommand GoToHelpCenterCommand { get; }
|
public ICommand GoToHelpCenterCommand { get; }
|
||||||
public ICommand ContactBitwardenSupportCommand { get; }
|
public ICommand ContactBitwardenSupportCommand { get; }
|
||||||
public ICommand GoToWebVaultCommand { get; }
|
public ICommand GoToWebVaultCommand { get; }
|
||||||
@@ -97,7 +94,7 @@ namespace Bit.App.Pages
|
|||||||
MainThread.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
TriggerPropertyChanged(nameof(ShouldSubmitCrashLogs));
|
TriggerPropertyChanged(nameof(ShouldSubmitCrashLogs));
|
||||||
ToggleSubmitCrashLogsCommand.RaiseCanExecuteChanged();
|
ToggleSubmitCrashLogsCommand.NotifyCanExecuteChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
using System;
|
using System.Windows.Input;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.Maui.ApplicationModel;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -64,7 +58,7 @@ namespace Bit.App.Pages
|
|||||||
() => _inited,
|
() => _inited,
|
||||||
ex => HandleException(ex));
|
ex => HandleException(ex));
|
||||||
|
|
||||||
ToggleShowWebsiteIconsCommand = CreateDefaultAsyncCommnad(ToggleShowWebsiteIconsAsync, () => _inited);
|
ToggleShowWebsiteIconsCommand = CreateDefaultAsyncRelayCommand(ToggleShowWebsiteIconsAsync, () => _inited, allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PickerViewModel<string> LanguagePickerViewModel { get; }
|
public PickerViewModel<string> LanguagePickerViewModel { get; }
|
||||||
@@ -87,7 +81,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public bool IsShowWebsiteIconsEnabled => ToggleShowWebsiteIconsCommand.CanExecute(null);
|
public bool IsShowWebsiteIconsEnabled => ToggleShowWebsiteIconsCommand.CanExecute(null);
|
||||||
|
|
||||||
public AsyncCommand ToggleShowWebsiteIconsCommand { get; }
|
public AsyncRelayCommand ToggleShowWebsiteIconsCommand { get; }
|
||||||
|
|
||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
{
|
{
|
||||||
@@ -102,10 +96,10 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
MainThread.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
ToggleShowWebsiteIconsCommand.RaiseCanExecuteChanged();
|
ToggleShowWebsiteIconsCommand.NotifyCanExecuteChanged();
|
||||||
LanguagePickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
LanguagePickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||||
ThemePickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
ThemePickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||||
DefaultDarkThemePickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
DefaultDarkThemePickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Windows.Input;
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Microsoft.Maui.ApplicationModel;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -16,8 +12,7 @@ namespace Bit.App.Pages
|
|||||||
private bool _useDrawOver;
|
private bool _useDrawOver;
|
||||||
private bool _askToAddLogin;
|
private bool _askToAddLogin;
|
||||||
|
|
||||||
public bool SupportsAndroidAutofillServices => // TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
public bool SupportsAndroidAutofillServices => DeviceInfo.Platform == DevicePlatform.Android && _deviceActionService.SupportsAutofillServices();
|
||||||
Device.RuntimePlatform == Device.Android && _deviceActionService.SupportsAutofillServices();
|
|
||||||
|
|
||||||
public bool UseAutofillServices
|
public bool UseAutofillServices
|
||||||
{
|
{
|
||||||
@@ -45,8 +40,7 @@ Device.RuntimePlatform == Device.Android && _deviceActionService.SupportsAutofil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShowUseAccessibilityToggle => // TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
public bool ShowUseAccessibilityToggle => DeviceInfo.Platform == DevicePlatform.Android;
|
||||||
Device.RuntimePlatform == Device.Android;
|
|
||||||
|
|
||||||
public string UseAccessibilityDescription => _deviceActionService.GetAutofillAccessibilityDescription();
|
public string UseAccessibilityDescription => _deviceActionService.GetAutofillAccessibilityDescription();
|
||||||
|
|
||||||
@@ -90,21 +84,21 @@ Device.RuntimePlatform == Device.Android;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncCommand ToggleUseAutofillServicesCommand { get; private set; }
|
public AsyncRelayCommand ToggleUseAutofillServicesCommand { get; private set; }
|
||||||
public AsyncCommand ToggleUseInlineAutofillCommand { get; private set; }
|
public AsyncRelayCommand ToggleUseInlineAutofillCommand { get; private set; }
|
||||||
public AsyncCommand ToggleUseAccessibilityCommand { get; private set; }
|
public AsyncRelayCommand ToggleUseAccessibilityCommand { get; private set; }
|
||||||
public AsyncCommand ToggleUseDrawOverCommand { get; private set; }
|
public AsyncRelayCommand ToggleUseDrawOverCommand { get; private set; }
|
||||||
public AsyncCommand ToggleAskToAddLoginCommand { get; private set; }
|
public AsyncRelayCommand ToggleAskToAddLoginCommand { get; private set; }
|
||||||
public ICommand GoToBlockAutofillUrisCommand { get; private set; }
|
public ICommand GoToBlockAutofillUrisCommand { get; private set; }
|
||||||
|
|
||||||
private void InitAndroidCommands()
|
private void InitAndroidCommands()
|
||||||
{
|
{
|
||||||
ToggleUseAutofillServicesCommand = CreateDefaultAsyncCommnad(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseAutofillServices()), () => _inited);
|
ToggleUseAutofillServicesCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseAutofillServices()), () => _inited, allowsMultipleExecutions: false);
|
||||||
ToggleUseInlineAutofillCommand = CreateDefaultAsyncCommnad(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseInlineAutofillEnabledAsync()), () => _inited);
|
ToggleUseInlineAutofillCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseInlineAutofillEnabledAsync()), () => _inited, allowsMultipleExecutions: false);
|
||||||
ToggleUseAccessibilityCommand = CreateDefaultAsyncCommnad(ToggleUseAccessibilityAsync, () => _inited);
|
ToggleUseAccessibilityCommand = CreateDefaultAsyncRelayCommand(ToggleUseAccessibilityAsync, () => _inited, allowsMultipleExecutions: false);
|
||||||
ToggleUseDrawOverCommand = CreateDefaultAsyncCommnad(() => MainThread.InvokeOnMainThreadAsync(() => ToggleDrawOver()), () => _inited);
|
ToggleUseDrawOverCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => ToggleDrawOver()), () => _inited, allowsMultipleExecutions: false);
|
||||||
ToggleAskToAddLoginCommand = CreateDefaultAsyncCommnad(ToggleAskToAddLoginAsync, () => _inited);
|
ToggleAskToAddLoginCommand = CreateDefaultAsyncRelayCommand(ToggleAskToAddLoginAsync, () => _inited, allowsMultipleExecutions: false);
|
||||||
GoToBlockAutofillUrisCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushAsync(new BlockAutofillUrisPage()));
|
GoToBlockAutofillUrisCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushAsync(new BlockAutofillUrisPage()), allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InitAndroidAutofillSettingsAsync()
|
private async Task InitAndroidAutofillSettingsAsync()
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Windows.Input;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.Maui.ApplicationModel;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Bit.App.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -36,7 +33,7 @@ namespace Bit.App.Pages
|
|||||||
() => _inited,
|
() => _inited,
|
||||||
ex => HandleException(ex));
|
ex => HandleException(ex));
|
||||||
|
|
||||||
ToggleCopyTotpAutomaticallyCommand = CreateDefaultAsyncCommnad(ToggleCopyTotpAutomaticallyAsync, () => _inited);
|
ToggleCopyTotpAutomaticallyCommand = CreateDefaultAsyncRelayCommand(ToggleCopyTotpAutomaticallyAsync, () => _inited, allowsMultipleExecutions: false);
|
||||||
|
|
||||||
InitAndroidCommands();
|
InitAndroidCommands();
|
||||||
InitIOSCommands();
|
InitIOSCommands();
|
||||||
@@ -56,7 +53,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public PickerViewModel<UriMatchType> DefaultUriMatchDetectionPickerViewModel { get; }
|
public PickerViewModel<UriMatchType> DefaultUriMatchDetectionPickerViewModel { get; }
|
||||||
|
|
||||||
public AsyncCommand ToggleCopyTotpAutomaticallyCommand { get; private set; }
|
public AsyncRelayCommand ToggleCopyTotpAutomaticallyCommand { get; private set; }
|
||||||
|
|
||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
{
|
{
|
||||||
@@ -72,11 +69,11 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
TriggerPropertyChanged(nameof(CopyTotpAutomatically));
|
TriggerPropertyChanged(nameof(CopyTotpAutomatically));
|
||||||
|
|
||||||
ToggleUseAutofillServicesCommand.RaiseCanExecuteChanged();
|
ToggleUseAutofillServicesCommand.NotifyCanExecuteChanged();
|
||||||
ToggleUseInlineAutofillCommand.RaiseCanExecuteChanged();
|
ToggleUseInlineAutofillCommand.NotifyCanExecuteChanged();
|
||||||
ToggleUseAccessibilityCommand.RaiseCanExecuteChanged();
|
ToggleUseAccessibilityCommand.NotifyCanExecuteChanged();
|
||||||
ToggleUseDrawOverCommand.RaiseCanExecuteChanged();
|
ToggleUseDrawOverCommand.NotifyCanExecuteChanged();
|
||||||
DefaultUriMatchDetectionPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
DefaultUriMatchDetectionPickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,18 @@
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public partial class AutofillSettingsPageViewModel
|
public partial class AutofillSettingsPageViewModel
|
||||||
{
|
{
|
||||||
public bool SupportsiOSAutofill => // TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
public bool SupportsiOSAutofill => DeviceInfo.Platform == DevicePlatform.iOS && _deviceActionService.SupportsAutofillServices();
|
||||||
Device.RuntimePlatform == Device.iOS && _deviceActionService.SupportsAutofillServices();
|
|
||||||
|
|
||||||
public ICommand GoToPasswordAutofillCommand { get; private set; }
|
public ICommand GoToPasswordAutofillCommand { get; private set; }
|
||||||
public ICommand GoToAppExtensionCommand { get; private set; }
|
public ICommand GoToAppExtensionCommand { get; private set; }
|
||||||
|
|
||||||
private void InitIOSCommands()
|
private void InitIOSCommands()
|
||||||
{
|
{
|
||||||
GoToPasswordAutofillCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillPage())));
|
GoToPasswordAutofillCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillPage())), allowsMultipleExecutions: false);
|
||||||
GoToAppExtensionCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushModalAsync(new NavigationPage(new ExtensionPage())));
|
GoToAppExtensionCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new ExtensionPage())), allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ namespace Bit.App.Pages
|
|||||||
_stateService = ServiceContainer.Resolve<IStateService>();
|
_stateService = ServiceContainer.Resolve<IStateService>();
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>();
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>();
|
||||||
|
|
||||||
AddUriCommand = new AsyncCommand(AddUriAsync,
|
AddUriCommand = CreateDefaultAsyncRelayCommand(AddUriAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
EditUriCommand = new AsyncCommand<BlockAutofillUriItemViewModel>(EditUriAsync,
|
EditUriCommand = CreateDefaultAsyncRelayCommand<BlockAutofillUriItemViewModel>(EditUriAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using Microsoft.Maui.ApplicationModel;
|
|||||||
using Microsoft.Maui.Controls;
|
using Microsoft.Maui.Controls;
|
||||||
using Microsoft.Maui;
|
using Microsoft.Maui;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -34,11 +35,11 @@ namespace Bit.App.Pages
|
|||||||
PageTitle = AppResources.PendingLogInRequests;
|
PageTitle = AppResources.PendingLogInRequests;
|
||||||
LoginRequests = new ObservableRangeCollection<PasswordlessLoginResponse>();
|
LoginRequests = new ObservableRangeCollection<PasswordlessLoginResponse>();
|
||||||
|
|
||||||
AnswerRequestCommand = new AsyncCommand<PasswordlessLoginResponse>(PasswordlessLoginAsync,
|
AnswerRequestCommand = CreateDefaultAsyncRelayCommand<PasswordlessLoginResponse>(PasswordlessLoginAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
DeclineAllRequestsCommand = new AsyncCommand(DeclineAllRequestsAsync,
|
DeclineAllRequestsCommand = CreateDefaultAsyncRelayCommand(DeclineAllRequestsAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
@@ -47,9 +48,9 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public ICommand RefreshCommand { get; }
|
public ICommand RefreshCommand { get; }
|
||||||
|
|
||||||
public AsyncCommand<PasswordlessLoginResponse> AnswerRequestCommand { get; }
|
public AsyncRelayCommand<PasswordlessLoginResponse> AnswerRequestCommand { get; }
|
||||||
|
|
||||||
public AsyncCommand DeclineAllRequestsCommand { get; }
|
public AsyncRelayCommand DeclineAllRequestsCommand { get; }
|
||||||
|
|
||||||
public ObservableRangeCollection<PasswordlessLoginResponse> LoginRequests { get; }
|
public ObservableRangeCollection<PasswordlessLoginResponse> LoginRequests { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
using System;
|
using System.Windows.Input;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Microsoft.Maui.ApplicationModel;
|
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -42,19 +35,21 @@ namespace Bit.App.Pages
|
|||||||
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
||||||
_logger = ServiceContainer.Resolve<ILogger>();
|
_logger = ServiceContainer.Resolve<ILogger>();
|
||||||
|
|
||||||
SyncCommand = CreateDefaultAsyncCommnad(SyncAsync, () => _inited);
|
SyncCommand = CreateDefaultAsyncRelayCommand(SyncAsync, CanExecuteIfInited, allowsMultipleExecutions: false);
|
||||||
ToggleIsScreenCaptureAllowedCommand = CreateDefaultAsyncCommnad(ToggleIsScreenCaptureAllowedAsync, () => _inited);
|
ToggleIsScreenCaptureAllowedCommand = CreateDefaultAsyncRelayCommand(ToggleIsScreenCaptureAllowedAsync, CanExecuteIfInited, allowsMultipleExecutions: false);
|
||||||
ToggleShouldConnectToWatchCommand = CreateDefaultAsyncCommnad(ToggleShouldConnectToWatchAsync, () => _inited);
|
ToggleShouldConnectToWatchCommand = CreateDefaultAsyncRelayCommand(ToggleShouldConnectToWatchAsync, CanExecuteIfInited, allowsMultipleExecutions: false);
|
||||||
|
|
||||||
ClearClipboardPickerViewModel = new PickerViewModel<int>(
|
ClearClipboardPickerViewModel = new PickerViewModel<int>(
|
||||||
_deviceActionService,
|
_deviceActionService,
|
||||||
_logger,
|
_logger,
|
||||||
OnClearClipboardChangingAsync,
|
OnClearClipboardChangingAsync,
|
||||||
AppResources.ClearClipboard,
|
AppResources.ClearClipboard,
|
||||||
() => _inited,
|
CanExecuteIfInited,
|
||||||
ex => HandleException(ex));
|
ex => HandleException(ex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CanExecuteIfInited() => _inited;
|
||||||
|
|
||||||
public bool EnableSyncOnRefresh
|
public bool EnableSyncOnRefresh
|
||||||
{
|
{
|
||||||
get => _syncOnRefresh;
|
get => _syncOnRefresh;
|
||||||
@@ -103,9 +98,9 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public bool CanToggleShouldConnectToWatch => ToggleShouldConnectToWatchCommand.CanExecute(null);
|
public bool CanToggleShouldConnectToWatch => ToggleShouldConnectToWatchCommand.CanExecute(null);
|
||||||
|
|
||||||
public AsyncCommand SyncCommand { get; }
|
public AsyncRelayCommand SyncCommand { get; }
|
||||||
public AsyncCommand ToggleIsScreenCaptureAllowedCommand { get; }
|
public AsyncRelayCommand ToggleIsScreenCaptureAllowedCommand { get; }
|
||||||
public AsyncCommand ToggleShouldConnectToWatchCommand { get; }
|
public AsyncRelayCommand ToggleShouldConnectToWatchCommand { get; }
|
||||||
|
|
||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
{
|
{
|
||||||
@@ -124,10 +119,10 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
TriggerPropertyChanged(nameof(IsScreenCaptureAllowed));
|
TriggerPropertyChanged(nameof(IsScreenCaptureAllowed));
|
||||||
TriggerPropertyChanged(nameof(ShouldConnectToWatch));
|
TriggerPropertyChanged(nameof(ShouldConnectToWatch));
|
||||||
SyncCommand.RaiseCanExecuteChanged();
|
SyncCommand.NotifyCanExecuteChanged();
|
||||||
ClearClipboardPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
ClearClipboardPickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||||
ToggleIsScreenCaptureAllowedCommand.RaiseCanExecuteChanged();
|
ToggleIsScreenCaptureAllowedCommand.NotifyCanExecuteChanged();
|
||||||
ToggleShouldConnectToWatchCommand.RaiseCanExecuteChanged();
|
ToggleShouldConnectToWatchCommand.NotifyCanExecuteChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,8 +136,7 @@ namespace Bit.App.Pages
|
|||||||
[30] = AppResources.ThirtySeconds,
|
[30] = AppResources.ThirtySeconds,
|
||||||
[60] = AppResources.OneMinute
|
[60] = AppResources.OneMinute
|
||||||
};
|
};
|
||||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
if (DeviceInfo.Platform != DevicePlatform.iOS)
|
||||||
if (Device.RuntimePlatform != Device.iOS)
|
|
||||||
{
|
{
|
||||||
clearClipboardOptions.Add(120, AppResources.TwoMinutes);
|
clearClipboardOptions.Add(120, AppResources.TwoMinutes);
|
||||||
clearClipboardOptions.Add(300, AppResources.FiveMinutes);
|
clearClipboardOptions.Add(300, AppResources.FiveMinutes);
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System.Windows.Input;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Pages.Accounts;
|
using Bit.App.Pages.Accounts;
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
@@ -12,10 +8,7 @@ using Bit.Core.Abstractions;
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Domain;
|
using Bit.Core.Models.Domain;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Microsoft.Maui.ApplicationModel;
|
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -80,16 +73,16 @@ namespace Bit.App.Pages
|
|||||||
() => _inited && !HasVaultTimeoutActionPolicy,
|
() => _inited && !HasVaultTimeoutActionPolicy,
|
||||||
ex => HandleException(ex));
|
ex => HandleException(ex));
|
||||||
|
|
||||||
ToggleUseThisDeviceToApproveLoginRequestsCommand = CreateDefaultAsyncCommnad(ToggleUseThisDeviceToApproveLoginRequestsAsync, () => _inited);
|
ToggleUseThisDeviceToApproveLoginRequestsCommand = CreateDefaultAsyncRelayCommand(ToggleUseThisDeviceToApproveLoginRequestsAsync, () => _inited, allowsMultipleExecutions: false);
|
||||||
GoToPendingLogInRequestsCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushModalAsync(new NavigationPage(new LoginPasswordlessRequestsListPage())));
|
GoToPendingLogInRequestsCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new LoginPasswordlessRequestsListPage())), allowsMultipleExecutions: false);
|
||||||
ToggleCanUnlockWithBiometricsCommand = CreateDefaultAsyncCommnad(ToggleCanUnlockWithBiometricsAsync, () => _inited);
|
ToggleCanUnlockWithBiometricsCommand = CreateDefaultAsyncRelayCommand(ToggleCanUnlockWithBiometricsAsync, () => _inited, allowsMultipleExecutions: false);
|
||||||
ToggleCanUnlockWithPinCommand = CreateDefaultAsyncCommnad(ToggleCanUnlockWithPinAsync, () => _inited);
|
ToggleCanUnlockWithPinCommand = CreateDefaultAsyncRelayCommand(ToggleCanUnlockWithPinAsync, () => _inited, allowsMultipleExecutions: false);
|
||||||
ShowAccountFingerprintPhraseCommand = CreateDefaultAsyncCommnad(ShowAccountFingerprintPhraseAsync);
|
ShowAccountFingerprintPhraseCommand = CreateDefaultAsyncRelayCommand(ShowAccountFingerprintPhraseAsync, allowsMultipleExecutions: false);
|
||||||
GoToTwoStepLoginCommand = CreateDefaultAsyncCommnad(() => GoToWebVaultSettingsAsync(AppResources.TwoStepLoginDescriptionLong, AppResources.ContinueToWebApp));
|
GoToTwoStepLoginCommand = CreateDefaultAsyncRelayCommand(() => GoToWebVaultSettingsAsync(AppResources.TwoStepLoginDescriptionLong, AppResources.ContinueToWebApp), allowsMultipleExecutions: false);
|
||||||
GoToChangeMasterPasswordCommand = CreateDefaultAsyncCommnad(() => GoToWebVaultSettingsAsync(AppResources.ChangeMasterPasswordDescriptionLong, AppResources.ContinueToWebApp));
|
GoToChangeMasterPasswordCommand = CreateDefaultAsyncRelayCommand(() => GoToWebVaultSettingsAsync(AppResources.ChangeMasterPasswordDescriptionLong, AppResources.ContinueToWebApp), allowsMultipleExecutions: false);
|
||||||
LockCommand = CreateDefaultAsyncCommnad(() => _vaultTimeoutService.LockAsync(true, true));
|
LockCommand = CreateDefaultAsyncRelayCommand(() => _vaultTimeoutService.LockAsync(true, true), allowsMultipleExecutions: false);
|
||||||
LogOutCommand = CreateDefaultAsyncCommnad(LogOutAsync);
|
LogOutCommand = CreateDefaultAsyncRelayCommand(LogOutAsync, allowsMultipleExecutions: false);
|
||||||
DeleteAccountCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushModalAsync(new NavigationPage(new DeleteAccountPage())));
|
DeleteAccountCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new DeleteAccountPage())), allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UseThisDeviceToApproveLoginRequests
|
public bool UseThisDeviceToApproveLoginRequests
|
||||||
@@ -114,8 +107,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
var biometricName = AppResources.Biometrics;
|
var biometricName = AppResources.Biometrics;
|
||||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
{
|
||||||
biometricName = _deviceActionService.SupportsFaceBiometric()
|
biometricName = _deviceActionService.SupportsFaceBiometric()
|
||||||
? AppResources.FaceID
|
? AppResources.FaceID
|
||||||
@@ -209,18 +201,17 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
private int? CurrentVaultTimeout => GetRawVaultTimeoutFrom(VaultTimeoutPickerViewModel.SelectedKey);
|
private int? CurrentVaultTimeout => GetRawVaultTimeoutFrom(VaultTimeoutPickerViewModel.SelectedKey);
|
||||||
|
|
||||||
private bool IncludeLinksWithSubscriptionInfo => // TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
private bool IncludeLinksWithSubscriptionInfo => DeviceInfo.Platform != DevicePlatform.iOS;
|
||||||
Device.RuntimePlatform != Device.iOS;
|
|
||||||
|
|
||||||
private bool HasVaultTimeoutActionPolicy => !string.IsNullOrEmpty(_vaultTimeoutActionPolicy);
|
private bool HasVaultTimeoutActionPolicy => !string.IsNullOrEmpty(_vaultTimeoutActionPolicy);
|
||||||
|
|
||||||
public PickerViewModel<int> VaultTimeoutPickerViewModel { get; }
|
public PickerViewModel<int> VaultTimeoutPickerViewModel { get; }
|
||||||
public PickerViewModel<VaultTimeoutAction> VaultTimeoutActionPickerViewModel { get; }
|
public PickerViewModel<VaultTimeoutAction> VaultTimeoutActionPickerViewModel { get; }
|
||||||
|
|
||||||
public AsyncCommand ToggleUseThisDeviceToApproveLoginRequestsCommand { get; }
|
public AsyncRelayCommand ToggleUseThisDeviceToApproveLoginRequestsCommand { get; }
|
||||||
public ICommand GoToPendingLogInRequestsCommand { get; }
|
public ICommand GoToPendingLogInRequestsCommand { get; }
|
||||||
public AsyncCommand ToggleCanUnlockWithBiometricsCommand { get; }
|
public AsyncRelayCommand ToggleCanUnlockWithBiometricsCommand { get; }
|
||||||
public AsyncCommand ToggleCanUnlockWithPinCommand { get; }
|
public AsyncRelayCommand ToggleCanUnlockWithPinCommand { get; }
|
||||||
public ICommand ShowAccountFingerprintPhraseCommand { get; }
|
public ICommand ShowAccountFingerprintPhraseCommand { get; }
|
||||||
public ICommand GoToTwoStepLoginCommand { get; }
|
public ICommand GoToTwoStepLoginCommand { get; }
|
||||||
public ICommand GoToChangeMasterPasswordCommand { get; }
|
public ICommand GoToChangeMasterPasswordCommand { get; }
|
||||||
@@ -256,11 +247,11 @@ Device.RuntimePlatform != Device.iOS;
|
|||||||
TriggerPropertyChanged(nameof(VaultTimeoutPolicyDescription));
|
TriggerPropertyChanged(nameof(VaultTimeoutPolicyDescription));
|
||||||
TriggerPropertyChanged(nameof(ShowChangeMasterPassword));
|
TriggerPropertyChanged(nameof(ShowChangeMasterPassword));
|
||||||
TriggerUpdateCustomVaultTimeoutPicker();
|
TriggerUpdateCustomVaultTimeoutPicker();
|
||||||
ToggleUseThisDeviceToApproveLoginRequestsCommand.RaiseCanExecuteChanged();
|
ToggleUseThisDeviceToApproveLoginRequestsCommand.NotifyCanExecuteChanged();
|
||||||
ToggleCanUnlockWithBiometricsCommand.RaiseCanExecuteChanged();
|
ToggleCanUnlockWithBiometricsCommand.NotifyCanExecuteChanged();
|
||||||
ToggleCanUnlockWithPinCommand.RaiseCanExecuteChanged();
|
ToggleCanUnlockWithPinCommand.NotifyCanExecuteChanged();
|
||||||
VaultTimeoutPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
VaultTimeoutPickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||||
VaultTimeoutActionPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
VaultTimeoutActionPickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +266,7 @@ Device.RuntimePlatform != Device.iOS;
|
|||||||
_maximumVaultTimeoutPolicy = maximumVaultTimeoutPolicy?.GetInt(Policy.MINUTES_KEY);
|
_maximumVaultTimeoutPolicy = maximumVaultTimeoutPolicy?.GetInt(Policy.MINUTES_KEY);
|
||||||
_vaultTimeoutActionPolicy = maximumVaultTimeoutPolicy?.GetString(Policy.ACTION_KEY);
|
_vaultTimeoutActionPolicy = maximumVaultTimeoutPolicy?.GetString(Policy.ACTION_KEY);
|
||||||
|
|
||||||
MainThread.BeginInvokeOnMainThread(VaultTimeoutActionPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged);
|
MainThread.BeginInvokeOnMainThread(VaultTimeoutActionPickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InitVaultTimeoutPickerAsync()
|
private async Task InitVaultTimeoutPickerAsync()
|
||||||
@@ -368,10 +359,9 @@ Device.RuntimePlatform != Device.iOS;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
|
|
||||||
if (!_supportsBiometric
|
if (!_supportsBiometric
|
||||||
||
|
||
|
||||||
!await _platformUtilsService.AuthenticateBiometricAsync(null, Device.RuntimePlatform == Device.Android ? "." : null))
|
!await _platformUtilsService.AuthenticateBiometricAsync(null, DeviceInfo.Platform == DevicePlatform.Android ? "." : null))
|
||||||
{
|
{
|
||||||
_canUnlockWithBiometrics = false;
|
_canUnlockWithBiometrics = false;
|
||||||
MainThread.BeginInvokeOnMainThread(() => TriggerPropertyChanged(nameof(CanUnlockWithBiometrics)));
|
MainThread.BeginInvokeOnMainThread(() => TriggerPropertyChanged(nameof(CanUnlockWithBiometrics)));
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using Bit.Core.Resources.Localization;
|
using Bit.Core.Resources.Localization;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -7,7 +8,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
public SettingsPageViewModel()
|
public SettingsPageViewModel()
|
||||||
{
|
{
|
||||||
ExecuteSettingItemCommand = new AsyncCommand<SettingsPageListItem>(item => item.ExecuteAsync(),
|
ExecuteSettingItemCommand = CreateDefaultAsyncRelayCommand<SettingsPageListItem>(item => item.ExecuteAsync(),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public List<SettingsPageListItem> SettingsItems { get; }
|
public List<SettingsPageListItem> SettingsItems { get; }
|
||||||
|
|
||||||
public AsyncCommand<SettingsPageListItem> ExecuteSettingItemCommand { get; }
|
public AsyncRelayCommand<SettingsPageListItem> ExecuteSettingItemCommand { get; }
|
||||||
|
|
||||||
private async Task NavigateToAsync(Page page)
|
private async Task NavigateToAsync(Page page)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,15 +22,15 @@ namespace Bit.App.Pages
|
|||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>();
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>();
|
||||||
_environmentService = ServiceContainer.Resolve<IEnvironmentService>();
|
_environmentService = ServiceContainer.Resolve<IEnvironmentService>();
|
||||||
|
|
||||||
GoToFoldersCommand = new AsyncCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new FoldersPage())),
|
GoToFoldersCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new FoldersPage())),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
GoToExportVaultCommand = new AsyncCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new ExportVaultPage())),
|
GoToExportVaultCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new ExportVaultPage())),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
GoToImportItemsCommand = new AsyncCommand(GoToImportItemsAsync,
|
GoToImportItemsCommand = CreateDefaultAsyncRelayCommand(GoToImportItemsAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace Bit.App.Pages
|
|||||||
_logger = ServiceContainer.Resolve<ILogger>();
|
_logger = ServiceContainer.Resolve<ILogger>();
|
||||||
Attachments = new ExtendedObservableCollection<AttachmentView>();
|
Attachments = new ExtendedObservableCollection<AttachmentView>();
|
||||||
DeleteAttachmentCommand = new Command<AttachmentView>(DeleteAsync);
|
DeleteAttachmentCommand = new Command<AttachmentView>(DeleteAsync);
|
||||||
SubmitAsyncCommand = new AsyncCommand(SubmitAsync, allowsMultipleExecutions: false);
|
SubmitAsyncCommand = CreateDefaultAsyncRelayCommand(SubmitAsync, allowsMultipleExecutions: false);
|
||||||
PageTitle = AppResources.Attachments;
|
PageTitle = AppResources.Attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Bit.Core.Exceptions;
|
|||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
@@ -28,7 +29,7 @@ namespace Bit.App.Pages
|
|||||||
_auditService = ServiceContainer.Resolve<IAuditService>("auditService");
|
_auditService = ServiceContainer.Resolve<IAuditService>("auditService");
|
||||||
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
||||||
|
|
||||||
CheckPasswordCommand = new AsyncCommand(CheckPasswordAsync, allowsMultipleExecutions: false);
|
CheckPasswordCommand = CreateDefaultAsyncRelayCommand(CheckPasswordAsync, allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CipherView Cipher
|
public CipherView Cipher
|
||||||
@@ -39,7 +40,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public string CreationDate => string.Format(AppResources.CreatedXY, Cipher?.CreationDate.ToShortDateString(), Cipher?.CreationDate.ToShortTimeString());
|
public string CreationDate => string.Format(AppResources.CreatedXY, Cipher?.CreationDate.ToShortDateString(), Cipher?.CreationDate.ToShortTimeString());
|
||||||
|
|
||||||
public AsyncCommand CheckPasswordCommand { get; }
|
public AsyncRelayCommand CheckPasswordCommand { get; }
|
||||||
|
|
||||||
protected async Task CheckPasswordAsync()
|
protected async Task CheckPasswordAsync()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using Bit.Core.Utilities;
|
|||||||
using Microsoft.Maui.Controls;
|
using Microsoft.Maui.Controls;
|
||||||
using Microsoft.Maui;
|
using Microsoft.Maui;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
@@ -99,8 +100,8 @@ namespace Bit.App.Pages
|
|||||||
UriOptionsCommand = new Command<LoginUriView>(UriOptions);
|
UriOptionsCommand = new Command<LoginUriView>(UriOptions);
|
||||||
FieldOptionsCommand = new Command<ICustomFieldItemViewModel>(FieldOptions);
|
FieldOptionsCommand = new Command<ICustomFieldItemViewModel>(FieldOptions);
|
||||||
PasswordPromptHelpCommand = new Command(PasswordPromptHelp);
|
PasswordPromptHelpCommand = new Command(PasswordPromptHelp);
|
||||||
CopyCommand = new AsyncCommand(CopyTotpClipboardAsync, onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
CopyCommand = CreateDefaultAsyncRelayCommand(CopyTotpClipboardAsync, onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
||||||
GenerateUsernameCommand = new AsyncCommand(GenerateUsernameAsync, onException: ex => OnGenerateUsernameException(ex), allowsMultipleExecutions: false);
|
GenerateUsernameCommand = CreateDefaultAsyncRelayCommand(GenerateUsernameAsync, onException: ex => OnGenerateUsernameException(ex), allowsMultipleExecutions: false);
|
||||||
Uris = new ExtendedObservableCollection<LoginUriView>();
|
Uris = new ExtendedObservableCollection<LoginUriView>();
|
||||||
Fields = new ExtendedObservableCollection<ICustomFieldItemViewModel>();
|
Fields = new ExtendedObservableCollection<ICustomFieldItemViewModel>();
|
||||||
Collections = new ExtendedObservableCollection<CollectionViewModel>();
|
Collections = new ExtendedObservableCollection<CollectionViewModel>();
|
||||||
@@ -163,8 +164,8 @@ namespace Bit.App.Pages
|
|||||||
public Command UriOptionsCommand { get; set; }
|
public Command UriOptionsCommand { get; set; }
|
||||||
public Command FieldOptionsCommand { get; set; }
|
public Command FieldOptionsCommand { get; set; }
|
||||||
public Command PasswordPromptHelpCommand { get; set; }
|
public Command PasswordPromptHelpCommand { get; set; }
|
||||||
public AsyncCommand CopyCommand { get; set; }
|
public AsyncRelayCommand CopyCommand { get; set; }
|
||||||
public AsyncCommand GenerateUsernameCommand { get; set; }
|
public AsyncRelayCommand GenerateUsernameCommand { get; set; }
|
||||||
public string CipherId { get; set; }
|
public string CipherId { get; set; }
|
||||||
public string OrganizationId { get; set; }
|
public string OrganizationId { get; set; }
|
||||||
public string FolderId { get; set; }
|
public string FolderId { get; set; }
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ using Bit.Core.Enums;
|
|||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Microsoft.Maui.Controls;
|
using Microsoft.Maui.Controls;
|
||||||
using Microsoft.Maui;
|
using Microsoft.Maui;
|
||||||
|
|
||||||
@@ -66,15 +66,15 @@ namespace Bit.App.Pages
|
|||||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||||
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
||||||
|
|
||||||
CopyCommand = new AsyncCommand<string>((id) => CopyAsync(id, null), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
CopyCommand = CreateDefaultAsyncRelayCommand<string>((id) => CopyAsync(id, null), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
||||||
CopyUriCommand = new AsyncCommand<LoginUriView>(uriView => CopyAsync("LoginUri", uriView.Uri), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
CopyUriCommand = CreateDefaultAsyncRelayCommand<LoginUriView>(uriView => CopyAsync("LoginUri", uriView.Uri), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
||||||
CopyFieldCommand = new AsyncCommand<FieldView>(field => CopyAsync(field.Type == FieldType.Hidden ? "H_FieldValue" : "FieldValue", field.Value), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
CopyFieldCommand = CreateDefaultAsyncRelayCommand<FieldView>(field => CopyAsync(field.Type == FieldType.Hidden ? "H_FieldValue" : "FieldValue", field.Value), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
||||||
LaunchUriCommand = new Command<ILaunchableView>(LaunchUri);
|
LaunchUriCommand = new Command<ILaunchableView>(LaunchUri);
|
||||||
CloneCommand = new AsyncCommand(CloneAsync, onException: ex => HandleException(ex), allowsMultipleExecutions: false);
|
CloneCommand = CreateDefaultAsyncRelayCommand(CloneAsync, onException: ex => HandleException(ex), allowsMultipleExecutions: false);
|
||||||
TogglePasswordCommand = new Command(TogglePassword);
|
TogglePasswordCommand = new Command(TogglePassword);
|
||||||
ToggleCardNumberCommand = new Command(ToggleCardNumber);
|
ToggleCardNumberCommand = new Command(ToggleCardNumber);
|
||||||
ToggleCardCodeCommand = new Command(ToggleCardCode);
|
ToggleCardCodeCommand = new Command(ToggleCardCode);
|
||||||
DownloadAttachmentCommand = new AsyncCommand<AttachmentView>(DownloadAttachmentAsync, allowsMultipleExecutions: false);
|
DownloadAttachmentCommand = CreateDefaultAsyncRelayCommand<AttachmentView>(DownloadAttachmentAsync, allowsMultipleExecutions: false);
|
||||||
|
|
||||||
PageTitle = AppResources.ViewItem;
|
PageTitle = AppResources.ViewItem;
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ namespace Bit.App.Pages
|
|||||||
public Command TogglePasswordCommand { get; set; }
|
public Command TogglePasswordCommand { get; set; }
|
||||||
public Command ToggleCardNumberCommand { get; set; }
|
public Command ToggleCardNumberCommand { get; set; }
|
||||||
public Command ToggleCardCodeCommand { get; set; }
|
public Command ToggleCardCodeCommand { get; set; }
|
||||||
public AsyncCommand<AttachmentView> DownloadAttachmentCommand { get; set; }
|
public AsyncRelayCommand<AttachmentView> DownloadAttachmentCommand { get; set; }
|
||||||
public string CipherId { get; set; }
|
public string CipherId { get; set; }
|
||||||
protected override string[] AdditionalPropertiesToRaiseOnCipherChanged => new string[]
|
protected override string[] AdditionalPropertiesToRaiseOnCipherChanged => new string[]
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -45,13 +45,13 @@ namespace Bit.App.Pages
|
|||||||
_logger = ServiceContainer.Resolve<ILogger>();
|
_logger = ServiceContainer.Resolve<ILogger>();
|
||||||
|
|
||||||
GroupedItems = new ObservableRangeCollection<IGroupingsPageListItem>();
|
GroupedItems = new ObservableRangeCollection<IGroupingsPageListItem>();
|
||||||
CipherOptionsCommand = new AsyncCommand<CipherView>(cipher => AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService),
|
CipherOptionsCommand = CreateDefaultAsyncRelayCommand<CipherView>(cipher => AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
SelectCipherCommand = new AsyncCommand<IGroupingsPageListItem>(SelectCipherAsync,
|
SelectCipherCommand = CreateDefaultAsyncRelayCommand<IGroupingsPageListItem>(SelectCipherAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
AddCipherCommand = new AsyncCommand(AddCipherAsync,
|
AddCipherCommand = CreateDefaultAsyncRelayCommand(AddCipherAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,10 @@ namespace Bit.App.Pages
|
|||||||
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
||||||
|
|
||||||
Ciphers = new ExtendedObservableCollection<CipherView>();
|
Ciphers = new ExtendedObservableCollection<CipherView>();
|
||||||
CipherOptionsCommand = new AsyncCommand<CipherView>(cipher => Utilities.AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService),
|
CipherOptionsCommand = CreateDefaultAsyncRelayCommand<CipherView>(cipher => Utilities.AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService),
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
AddCipherCommand = new AsyncCommand(AddCipherAsync,
|
AddCipherCommand = CreateDefaultAsyncRelayCommand(AddCipherAsync,
|
||||||
onException: ex => HandleException(ex),
|
onException: ex => HandleException(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using Bit.App.Utilities;
|
|||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Microsoft.Maui.ApplicationModel;
|
using Microsoft.Maui.ApplicationModel;
|
||||||
using Microsoft.Maui.Controls;
|
using Microsoft.Maui.Controls;
|
||||||
using Microsoft.Maui;
|
using Microsoft.Maui;
|
||||||
@@ -37,13 +37,13 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
Cipher = cipherView;
|
Cipher = cipherView;
|
||||||
WebsiteIconsEnabled = websiteIconsEnabled;
|
WebsiteIconsEnabled = websiteIconsEnabled;
|
||||||
CopyCommand = new AsyncCommand(CopyToClipboardAsync,
|
CopyCommand = CreateDefaultAsyncRelayCommand(CopyToClipboardAsync,
|
||||||
onException: ex => _logger.Value.Exception(ex),
|
onException: ex => _logger.Value.Exception(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
_totpTickHelper = new TotpHelper(cipherView);
|
_totpTickHelper = new TotpHelper(cipherView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncCommand CopyCommand { get; set; }
|
public AsyncRelayCommand CopyCommand { get; set; }
|
||||||
|
|
||||||
public CipherView Cipher
|
public CipherView Cipher
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -71,10 +71,10 @@ namespace Bit.App.Pages
|
|||||||
Refreshing = true;
|
Refreshing = true;
|
||||||
await LoadAsync();
|
await LoadAsync();
|
||||||
});
|
});
|
||||||
CipherOptionsCommand = new AsyncCommand<CipherView>(cipher => AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService),
|
CipherOptionsCommand = CreateDefaultAsyncRelayCommand<CipherView>(cipher => AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService),
|
||||||
onException: ex => _logger.Exception(ex),
|
onException: ex => _logger.Exception(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
VaultFilterCommand = new AsyncCommand(VaultFilterOptionsAsync,
|
VaultFilterCommand = CreateDefaultAsyncRelayCommand(VaultFilterOptionsAsync,
|
||||||
onException: ex => _logger.Exception(ex),
|
onException: ex => _logger.Exception(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public ScanPageViewModel()
|
public ScanPageViewModel()
|
||||||
{
|
{
|
||||||
ToggleScanModeCommand = new AsyncCommand(ToggleScanMode, onException: HandleException);
|
ToggleScanModeCommand = CreateDefaultAsyncRelayCommand(ToggleScanMode, onException: HandleException);
|
||||||
StartCameraCommand = new Command(StartCamera);
|
StartCameraCommand = new Command(StartCamera);
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace Bit.App.Pages
|
|||||||
OrganizationOptions = new List<KeyValuePair<string, string>>();
|
OrganizationOptions = new List<KeyValuePair<string, string>>();
|
||||||
PageTitle = AppResources.MoveToOrganization;
|
PageTitle = AppResources.MoveToOrganization;
|
||||||
|
|
||||||
MoveCommand = new AsyncCommand(MoveAsync, onException: ex => HandleException(ex), allowsMultipleExecutions: false);
|
MoveCommand = CreateDefaultAsyncRelayCommand(MoveAsync, onException: ex => HandleException(ex), allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string CipherId { get; set; }
|
public string CipherId { get; set; }
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public VaultFilterViewModel()
|
public VaultFilterViewModel()
|
||||||
{
|
{
|
||||||
VaultFilterCommand = new AsyncCommand(VaultFilterOptionsAsync,
|
VaultFilterCommand = CreateDefaultAsyncRelayCommand(VaultFilterOptionsAsync,
|
||||||
onException: ex => logger.Exception(ex),
|
onException: ex => logger.Exception(ex),
|
||||||
allowsMultipleExecutions: false);
|
allowsMultipleExecutions: false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
using System.Windows.Input;
|
|
||||||
using CommunityToolkit.Mvvm.Input;
|
|
||||||
|
|
||||||
namespace Bit.App.Utilities
|
|
||||||
{
|
|
||||||
// TODO: [MAUI-Migration] DELETE WHEN MIGRATION IS DONE
|
|
||||||
/// <summary>
|
|
||||||
|
|
||||||
/// Wrapper of <see cref="AsyncRelayCommand"/> just to ease with the MAUI migration process.
|
|
||||||
/// After the process is done, remove this and use AsyncRelayCommand directly
|
|
||||||
/// </summary>
|
|
||||||
public class AsyncCommand : ICommand
|
|
||||||
{
|
|
||||||
readonly AsyncRelayCommand _relayCommand;
|
|
||||||
|
|
||||||
public AsyncCommand(Func<Task> execute, Func<bool> canExecute = null, Action<Exception> onException = null, bool allowsMultipleExecutions = true)
|
|
||||||
{
|
|
||||||
async Task doAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await execute?.Invoke();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
onException?.Invoke(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var safeCanExecute = canExecute;
|
|
||||||
if (canExecute is null)
|
|
||||||
{
|
|
||||||
safeCanExecute = () => true;
|
|
||||||
}
|
|
||||||
_relayCommand = new AsyncRelayCommand(doAsync, safeCanExecute, allowsMultipleExecutions ? AsyncRelayCommandOptions.AllowConcurrentExecutions : AsyncRelayCommandOptions.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
public event EventHandler CanExecuteChanged;
|
|
||||||
|
|
||||||
public bool CanExecute(object parameter) => _relayCommand.CanExecute(parameter);
|
|
||||||
public void Execute(object parameter) => _relayCommand.Execute(parameter);
|
|
||||||
public void RaiseCanExecuteChanged() => _relayCommand.NotifyCanExecuteChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper of <see cref="AsyncRelayCommand"/> just to ease with the MAUI migration process.
|
|
||||||
/// After the process is done, remove this and use AsyncRelayCommand directly
|
|
||||||
/// </summary>
|
|
||||||
public class AsyncCommand<T> : ICommand
|
|
||||||
{
|
|
||||||
readonly AsyncRelayCommand<T> _relayCommand;
|
|
||||||
|
|
||||||
public AsyncCommand(Func<T, Task> execute, Predicate<T?> canExecute = null, Action<Exception> onException = null, bool allowsMultipleExecutions = true)
|
|
||||||
{
|
|
||||||
async Task doAsync(T foo)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await execute?.Invoke(foo);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
onException?.Invoke(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var safeCanExecute = canExecute;
|
|
||||||
if (canExecute is null)
|
|
||||||
{
|
|
||||||
safeCanExecute = _ => true;
|
|
||||||
}
|
|
||||||
_relayCommand = new AsyncRelayCommand<T>(doAsync, safeCanExecute, allowsMultipleExecutions ? AsyncRelayCommandOptions.AllowConcurrentExecutions : AsyncRelayCommandOptions.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
public event EventHandler CanExecuteChanged;
|
|
||||||
|
|
||||||
public bool CanExecute(object parameter) => _relayCommand.CanExecute(parameter);
|
|
||||||
public void Execute(object parameter) => _relayCommand.Execute(parameter);
|
|
||||||
public void RaiseCanExecuteChanged() => _relayCommand.NotifyCanExecuteChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,96 @@
|
|||||||
using System;
|
using System.ComponentModel;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
|
using Bit.Core.Resources.Localization;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
namespace Bit.Core.Utilities
|
namespace Bit.Core.Utilities
|
||||||
{
|
{
|
||||||
public abstract class ExtendedViewModel : INotifyPropertyChanged
|
public abstract class ExtendedViewModel : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
|
protected LazyResolve<IDeviceActionService> _deviceActionService = new LazyResolve<IDeviceActionService>();
|
||||||
|
protected LazyResolve<IPlatformUtilsService> _platformUtilsService = new LazyResolve<IPlatformUtilsService>();
|
||||||
|
protected LazyResolve<ILogger> _logger = new LazyResolve<ILogger>();
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
protected AsyncRelayCommand CreateDefaultAsyncRelayCommand(Func<Task> execute, Func<bool> canExecute = null, Action<Exception> onException = null, bool allowsMultipleExecutions = true)
|
||||||
|
{
|
||||||
|
var safeCanExecute = canExecute;
|
||||||
|
if (canExecute is null)
|
||||||
|
{
|
||||||
|
safeCanExecute = () => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task doAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await execute?.Invoke();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (onException != null)
|
||||||
|
{
|
||||||
|
onException(ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AsyncRelayCommand(doAsync, safeCanExecute, allowsMultipleExecutions ? AsyncRelayCommandOptions.AllowConcurrentExecutions : AsyncRelayCommandOptions.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AsyncRelayCommand<T> CreateDefaultAsyncRelayCommand<T>(Func<T, Task> execute, Predicate<T?> canExecute = null, Action<Exception> onException = null, bool allowsMultipleExecutions = true)
|
||||||
|
{
|
||||||
|
var safeCanExecute = canExecute;
|
||||||
|
if (canExecute is null)
|
||||||
|
{
|
||||||
|
safeCanExecute = _ => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task doAsync(T foo)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await execute?.Invoke(foo);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (onException != null)
|
||||||
|
{
|
||||||
|
onException(ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AsyncRelayCommand<T>(doAsync, safeCanExecute, allowsMultipleExecutions ? AsyncRelayCommandOptions.AllowConcurrentExecutions : AsyncRelayCommandOptions.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void HandleException(Exception ex, string message = null)
|
||||||
|
{
|
||||||
|
if (ex is ApiException apiException && apiException.Error != null)
|
||||||
|
{
|
||||||
|
message = apiException.Error.GetSingleMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
Microsoft.Maui.ApplicationModel.MainThread.InvokeOnMainThreadAsync(async () =>
|
||||||
|
{
|
||||||
|
await _deviceActionService.Value.HideLoadingAsync();
|
||||||
|
await _platformUtilsService.Value.ShowDialogAsync(message ?? AppResources.GenericErrorMessage);
|
||||||
|
}).FireAndForget();
|
||||||
|
_logger.Value.Exception(ex);
|
||||||
|
}
|
||||||
|
|
||||||
protected bool SetProperty<T>(ref T backingStore, T value, Action onChanged = null,
|
protected bool SetProperty<T>(ref T backingStore, T value, Action onChanged = null,
|
||||||
[CallerMemberName] string propertyName = "", string[] additionalPropertyNames = null)
|
[CallerMemberName] string propertyName = "", string[] additionalPropertyNames = null)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user