mirror of
https://github.com/bitwarden/android.git
synced 2025-01-13 19:57:37 +03: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:
parent
f02b3415a3
commit
2c7870d660
41 changed files with 282 additions and 349 deletions
|
@ -1,7 +1,7 @@
|
|||
using System.Windows.Input;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
|
@ -37,17 +37,14 @@ namespace Bit.App.Controls
|
|||
{
|
||||
InitializeComponent();
|
||||
|
||||
ToggleVisibililtyCommand = new AsyncCommand(ToggleVisibilityAsync,
|
||||
onException: ex => _logger.Value.Exception(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
ToggleVisibililtyCommand = new AsyncRelayCommand(ToggleVisibilityAsync,
|
||||
AsyncRelayCommandOptions.None);
|
||||
|
||||
SelectAccountCommand = new AsyncCommand<AccountViewCellViewModel>(SelectAccountAsync,
|
||||
onException: ex => _logger.Value.Exception(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
SelectAccountCommand = new AsyncRelayCommand<AccountViewCellViewModel>(SelectAccountAsync,
|
||||
AsyncRelayCommandOptions.None);
|
||||
|
||||
LongPressAccountCommand = new AsyncCommand<AccountViewCellViewModel>(LongPressAccountAsync,
|
||||
onException: ex => _logger.Value.Exception(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
LongPressAccountCommand = new AsyncRelayCommand<AccountViewCellViewModel>(LongPressAccountAsync,
|
||||
AsyncRelayCommandOptions.None);
|
||||
}
|
||||
|
||||
public AccountSwitchingOverlayViewModel ViewModel => BindingContext as AccountSwitchingOverlayViewModel;
|
||||
|
@ -70,13 +67,20 @@ namespace Bit.App.Controls
|
|||
|
||||
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)
|
||||
{
|
||||
if (!LongPressAccountEnabled || item == null || !item.IsAccount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!LongPressAccountEnabled || item == null || !item.IsAccount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Delay(100);
|
||||
await HideAsync();
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@ namespace Bit.App.Controls
|
|||
_stateService = stateService;
|
||||
_messagingService = messagingService;
|
||||
|
||||
SelectAccountCommand = new AsyncCommand<AccountViewCellViewModel>(SelectAccountAsync,
|
||||
SelectAccountCommand = CreateDefaultAsyncRelayCommand<AccountViewCellViewModel>(SelectAccountAsync,
|
||||
onException: ex => logger.Exception(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
LongPressAccountCommand = new AsyncCommand<Tuple<ContentPage, AccountViewCellViewModel>>(LongPressAccountAsync,
|
||||
LongPressAccountCommand = CreateDefaultAsyncRelayCommand<Tuple<ContentPage, AccountViewCellViewModel>>(LongPressAccountAsync,
|
||||
onException: ex => logger.Exception(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Bit.App.Lists.ItemViewModels.CustomFields
|
|||
_eventService = eventService;
|
||||
|
||||
CopyFieldCommand = new Command(() => copyFieldCommand?.Execute(Field));
|
||||
ToggleHiddenValueCommand = new AsyncCommand(ToggleHiddenValueAsync, null, ex =>
|
||||
ToggleHiddenValueCommand = CreateDefaultAsyncRelayCommand(ToggleHiddenValueAsync, null, ex =>
|
||||
{
|
||||
//#if !FDROID
|
||||
// Microsoft.AppCenter.Crashes.Crashes.TrackError(ex);
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Input;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.App.Utilities;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -26,7 +23,7 @@ namespace Bit.App.Pages
|
|||
IdentityUrl = _environmentService.IdentityUrl;
|
||||
IconsUrl = _environmentService.IconsUrl;
|
||||
NotificationsUrls = _environmentService.NotificationsUrl;
|
||||
SubmitCommand = new AsyncCommand(SubmitAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
||||
SubmitCommand = CreateDefaultAsyncRelayCommand(SubmitAsync, onException: OnSubmitException, allowsMultipleExecutions: false);
|
||||
}
|
||||
|
||||
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.Core.Resources.Localization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.App.Utilities;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -25,7 +23,7 @@ namespace Bit.App.Pages
|
|||
_logger = ServiceContainer.Resolve<ILogger>();
|
||||
|
||||
PageTitle = AppResources.PasswordHint;
|
||||
SubmitCommand = new AsyncCommand(SubmitAsync,
|
||||
SubmitCommand = CreateDefaultAsyncRelayCommand(SubmitAsync,
|
||||
onException: ex =>
|
||||
{
|
||||
_logger.Exception(ex);
|
||||
|
|
|
@ -11,6 +11,7 @@ using Bit.Core.Utilities;
|
|||
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -50,12 +51,12 @@ namespace Bit.App.Pages
|
|||
AllowActiveAccountSelection = true
|
||||
};
|
||||
RememberEmailCommand = new Command(() => RememberEmail = !RememberEmail);
|
||||
ContinueCommand = new AsyncCommand(ContinueToLoginStepAsync, allowsMultipleExecutions: false);
|
||||
CreateAccountCommand = new AsyncCommand(async () => Device.InvokeOnMainThreadAsync(StartRegisterAction),
|
||||
ContinueCommand = CreateDefaultAsyncRelayCommand(ContinueToLoginStepAsync, allowsMultipleExecutions: false);
|
||||
CreateAccountCommand = CreateDefaultAsyncRelayCommand(async () => Device.InvokeOnMainThreadAsync(StartRegisterAction),
|
||||
onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||
CloseCommand = new AsyncCommand(async () => Device.InvokeOnMainThreadAsync(CloseAction),
|
||||
CloseCommand = CreateDefaultAsyncRelayCommand(async () => Device.InvokeOnMainThreadAsync(CloseAction),
|
||||
onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||
ShowEnvironmentPickerCommand = new AsyncCommand(ShowEnvironmentPickerAsync,
|
||||
ShowEnvironmentPickerCommand = CreateDefaultAsyncRelayCommand(ShowEnvironmentPickerAsync,
|
||||
onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||
InitAsync().FireAndForget();
|
||||
}
|
||||
|
@ -113,10 +114,10 @@ namespace Bit.App.Pages
|
|||
public Action StartEnvironmentAction { get; set; }
|
||||
public Action CloseAction { get; set; }
|
||||
public Command RememberEmailCommand { get; set; }
|
||||
public AsyncCommand ContinueCommand { get; }
|
||||
public AsyncCommand CloseCommand { get; }
|
||||
public AsyncCommand CreateAccountCommand { get; }
|
||||
public AsyncCommand ShowEnvironmentPickerCommand { get; }
|
||||
public AsyncRelayCommand ContinueCommand { get; }
|
||||
public AsyncRelayCommand CloseCommand { get; }
|
||||
public AsyncRelayCommand CreateAccountCommand { get; }
|
||||
public AsyncRelayCommand ShowEnvironmentPickerCommand { get; }
|
||||
|
||||
public async Task InitAsync()
|
||||
{
|
||||
|
|
|
@ -55,19 +55,19 @@ namespace Bit.App.Pages
|
|||
PageTitle = AppResources.LogInInitiated;
|
||||
RememberThisDevice = true;
|
||||
|
||||
ApproveWithMyOtherDeviceCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithDeviceAction),
|
||||
ApproveWithMyOtherDeviceCommand = CreateDefaultAsyncRelayCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithDeviceAction),
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
RequestAdminApprovalCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(RequestAdminApprovalAction),
|
||||
RequestAdminApprovalCommand = CreateDefaultAsyncRelayCommand(() => SetDeviceTrustAndInvokeAsync(RequestAdminApprovalAction),
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
ApproveWithMasterPasswordCommand = new AsyncCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithMasterPasswordAction),
|
||||
ApproveWithMasterPasswordCommand = CreateDefaultAsyncRelayCommand(() => SetDeviceTrustAndInvokeAsync(LogInWithMasterPasswordAction),
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
ContinueCommand = new AsyncCommand(CreateNewSsoUserAsync,
|
||||
ContinueCommand = CreateDefaultAsyncRelayCommand(CreateNewSsoUserAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
|
|
|
@ -62,8 +62,8 @@ namespace Bit.App.Pages
|
|||
PageTitle = AppResources.Bitwarden;
|
||||
TogglePasswordCommand = new Command(TogglePassword);
|
||||
LogInCommand = new Command(async () => await LogInAsync());
|
||||
MoreCommand = new AsyncCommand(MoreAsync, onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||
LogInWithDeviceCommand = new AsyncCommand(() => Device.InvokeOnMainThreadAsync(LogInWithDeviceAction), onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||
MoreCommand = CreateDefaultAsyncRelayCommand(MoreAsync, onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||
LogInWithDeviceCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(LogInWithDeviceAction), onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||
|
||||
AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger)
|
||||
{
|
||||
|
|
|
@ -56,11 +56,11 @@ namespace Bit.App.Pages
|
|||
_cryptoFunctionService = ServiceContainer.Resolve<ICryptoFunctionService>();
|
||||
_cryptoService = ServiceContainer.Resolve<ICryptoService>();
|
||||
|
||||
CreatePasswordlessLoginCommand = new AsyncCommand(CreatePasswordlessLoginAsync,
|
||||
CreatePasswordlessLoginCommand = CreateDefaultAsyncRelayCommand(CreatePasswordlessLoginAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
CloseCommand = new AsyncCommand(() => MainThread.InvokeOnMainThreadAsync(CloseAction),
|
||||
CloseCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(CloseAction),
|
||||
onException: _logger.Exception,
|
||||
allowsMultipleExecutions: false);
|
||||
}
|
||||
|
|
|
@ -39,10 +39,10 @@ namespace Bit.App.Pages
|
|||
|
||||
PageTitle = AppResources.LogInRequested;
|
||||
|
||||
AcceptRequestCommand = new AsyncCommand(() => PasswordlessLoginAsync(true),
|
||||
AcceptRequestCommand = CreateDefaultAsyncRelayCommand(() => PasswordlessLoginAsync(true),
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
RejectRequestCommand = new AsyncCommand(() => PasswordlessLoginAsync(false),
|
||||
RejectRequestCommand = CreateDefaultAsyncRelayCommand(() => PasswordlessLoginAsync(false),
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace Bit.App.Pages
|
|||
_cryptoService = ServiceContainer.Resolve<ICryptoService>();
|
||||
|
||||
PageTitle = AppResources.Bitwarden;
|
||||
LogInCommand = new AsyncCommand(LogInAsync, allowsMultipleExecutions: false);
|
||||
LogInCommand = CreateDefaultAsyncRelayCommand(LogInAsync, allowsMultipleExecutions: false);
|
||||
}
|
||||
|
||||
public string OrgIdentifier
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace Bit.App.Pages
|
|||
|
||||
PageTitle = AppResources.TwoStepLogin;
|
||||
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
|
||||
|
|
|
@ -11,6 +11,7 @@ using Bit.Core.Utilities;
|
|||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
using Bit.App.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -25,14 +26,14 @@ namespace Bit.App.Pages
|
|||
PageTitle = AppResources.UpdateMasterPassword;
|
||||
TogglePasswordCommand = new Command(TogglePassword);
|
||||
ToggleConfirmPasswordCommand = new Command(ToggleConfirmPassword);
|
||||
SubmitCommand = new AsyncCommand(SubmitAsync,
|
||||
SubmitCommand = CreateDefaultAsyncRelayCommand(SubmitAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
_userVerificationService = ServiceContainer.Resolve<IUserVerificationService>();
|
||||
}
|
||||
|
||||
public AsyncCommand SubmitCommand { get; }
|
||||
public AsyncRelayCommand SubmitCommand { get; }
|
||||
public Command TogglePasswordCommand { get; }
|
||||
public Command ToggleConfirmPasswordCommand { get; }
|
||||
public Action UpdateTempPasswordSuccessAction { get; set; }
|
||||
|
|
|
@ -39,8 +39,8 @@ namespace Bit.App.Pages
|
|||
PageTitle = AppResources.VerificationCode;
|
||||
|
||||
TogglePasswordCommand = new Command(TogglePassword);
|
||||
MainActionCommand = new AsyncCommand(MainActionAsync, allowsMultipleExecutions: false);
|
||||
RequestOTPCommand = new AsyncCommand(RequestOTPAsync, allowsMultipleExecutions: false);
|
||||
MainActionCommand = CreateDefaultAsyncRelayCommand(MainActionAsync, allowsMultipleExecutions: false);
|
||||
RequestOTPCommand = CreateDefaultAsyncRelayCommand(RequestOTPAsync, allowsMultipleExecutions: false);
|
||||
}
|
||||
|
||||
public bool ShowPassword
|
||||
|
|
|
@ -1,27 +1,13 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
using Microsoft.Maui.Networking;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
using Bit.App.Utilities;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
public abstract class BaseViewModel : ExtendedViewModel
|
||||
{
|
||||
private string _pageTitle = string.Empty;
|
||||
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
|
||||
{
|
||||
|
@ -37,29 +23,6 @@ namespace Bit.App.Pages
|
|||
|
||||
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()
|
||||
{
|
||||
if (Connectivity.NetworkAccess == NetworkAccess.None)
|
||||
|
|
|
@ -89,11 +89,11 @@ namespace Bit.App.Pages
|
|||
};
|
||||
|
||||
UsernameTypePromptHelpCommand = new Command(UsernameTypePromptHelp);
|
||||
RegenerateCommand = new AsyncCommand(RegenerateAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
||||
RegenerateUsernameCommand = new AsyncCommand(RegenerateUsernameAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
||||
RegenerateCommand = CreateDefaultAsyncRelayCommand(RegenerateAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
||||
RegenerateUsernameCommand = CreateDefaultAsyncRelayCommand(RegenerateUsernameAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
||||
ToggleForwardedEmailHiddenValueCommand = new Command(() => ShowForwardedEmailApiSecret = !ShowForwardedEmailApiSecret);
|
||||
CopyCommand = new AsyncCommand(CopyAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
|
||||
CloseCommand = new AsyncCommand(CloseAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
|
||||
CopyCommand = CreateDefaultAsyncRelayCommand(CopyAsync, 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; }
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
using Bit.App.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -33,10 +32,10 @@ namespace Bit.App.Pages
|
|||
_onSelectionChangingAsync = onSelectionChangingAsync;
|
||||
_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;
|
||||
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Input;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.Maui.ApplicationModel;
|
||||
using Bit.App.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -29,32 +26,32 @@ namespace Bit.App.Pages
|
|||
var environmentService = ServiceContainer.Resolve<IEnvironmentService>();
|
||||
var clipboardService = ServiceContainer.Resolve<IClipboardService>();
|
||||
|
||||
ToggleSubmitCrashLogsCommand = CreateDefaultAsyncCommnad(ToggleSubmitCrashLogsAsync);
|
||||
ToggleSubmitCrashLogsCommand = CreateDefaultAsyncRelayCommand(ToggleSubmitCrashLogsAsync, allowsMultipleExecutions: false);
|
||||
|
||||
GoToHelpCenterCommand = CreateDefaultAsyncCommnad(
|
||||
GoToHelpCenterCommand = CreateDefaultAsyncRelayCommand(
|
||||
() => LaunchUriAsync(AppResources.LearnMoreAboutHowToUseBitwardenOnTheHelpCenter,
|
||||
AppResources.ContinueToHelpCenter,
|
||||
ExternalLinksConstants.HELP_CENTER));
|
||||
ExternalLinksConstants.HELP_CENTER), allowsMultipleExecutions: false);
|
||||
|
||||
ContactBitwardenSupportCommand = CreateDefaultAsyncCommnad(
|
||||
ContactBitwardenSupportCommand = CreateDefaultAsyncRelayCommand(
|
||||
() => LaunchUriAsync(AppResources.ContactSupportDescriptionLong,
|
||||
AppResources.ContinueToContactSupport,
|
||||
ExternalLinksConstants.CONTACT_SUPPORT));
|
||||
ExternalLinksConstants.CONTACT_SUPPORT), allowsMultipleExecutions: false);
|
||||
|
||||
GoToWebVaultCommand = CreateDefaultAsyncCommnad(
|
||||
GoToWebVaultCommand = CreateDefaultAsyncRelayCommand(
|
||||
() => LaunchUriAsync(AppResources.ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp,
|
||||
AppResources.ContinueToWebApp,
|
||||
environmentService.GetWebVaultUrl()));
|
||||
environmentService.GetWebVaultUrl()), allowsMultipleExecutions: false);
|
||||
|
||||
GoToLearnAboutOrgsCommand = CreateDefaultAsyncCommnad(
|
||||
GoToLearnAboutOrgsCommand = CreateDefaultAsyncRelayCommand(
|
||||
() => LaunchUriAsync(AppResources.LearnAboutOrganizationsDescriptionLong,
|
||||
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(
|
||||
() => clipboardService.CopyTextAsync(AppInfo));
|
||||
CopyAppInfoCommand = CreateDefaultAsyncRelayCommand(
|
||||
() => clipboardService.CopyTextAsync(AppInfo), allowsMultipleExecutions: false);
|
||||
}
|
||||
|
||||
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 ContactBitwardenSupportCommand { get; }
|
||||
public ICommand GoToWebVaultCommand { get; }
|
||||
|
@ -97,7 +94,7 @@ namespace Bit.App.Pages
|
|||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
TriggerPropertyChanged(nameof(ShouldSubmitCrashLogs));
|
||||
ToggleSubmitCrashLogsCommand.RaiseCanExecuteChanged();
|
||||
ToggleSubmitCrashLogsCommand.NotifyCanExecuteChanged();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Input;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.Maui.ApplicationModel;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -64,7 +58,7 @@ namespace Bit.App.Pages
|
|||
() => _inited,
|
||||
ex => HandleException(ex));
|
||||
|
||||
ToggleShowWebsiteIconsCommand = CreateDefaultAsyncCommnad(ToggleShowWebsiteIconsAsync, () => _inited);
|
||||
ToggleShowWebsiteIconsCommand = CreateDefaultAsyncRelayCommand(ToggleShowWebsiteIconsAsync, () => _inited, allowsMultipleExecutions: false);
|
||||
}
|
||||
|
||||
public PickerViewModel<string> LanguagePickerViewModel { get; }
|
||||
|
@ -87,7 +81,7 @@ namespace Bit.App.Pages
|
|||
|
||||
public bool IsShowWebsiteIconsEnabled => ToggleShowWebsiteIconsCommand.CanExecute(null);
|
||||
|
||||
public AsyncCommand ToggleShowWebsiteIconsCommand { get; }
|
||||
public AsyncRelayCommand ToggleShowWebsiteIconsCommand { get; }
|
||||
|
||||
public async Task InitAsync()
|
||||
{
|
||||
|
@ -102,10 +96,10 @@ namespace Bit.App.Pages
|
|||
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
ToggleShowWebsiteIconsCommand.RaiseCanExecuteChanged();
|
||||
LanguagePickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
||||
ThemePickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
||||
DefaultDarkThemePickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
||||
ToggleShowWebsiteIconsCommand.NotifyCanExecuteChanged();
|
||||
LanguagePickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||
ThemePickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||
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 Microsoft.Maui.ApplicationModel;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
using Bit.App.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -16,8 +12,7 @@ namespace Bit.App.Pages
|
|||
private bool _useDrawOver;
|
||||
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
|
||||
Device.RuntimePlatform == Device.Android && _deviceActionService.SupportsAutofillServices();
|
||||
public bool SupportsAndroidAutofillServices => DeviceInfo.Platform == DevicePlatform.Android && _deviceActionService.SupportsAutofillServices();
|
||||
|
||||
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
|
||||
Device.RuntimePlatform == Device.Android;
|
||||
public bool ShowUseAccessibilityToggle => DeviceInfo.Platform == DevicePlatform.Android;
|
||||
|
||||
public string UseAccessibilityDescription => _deviceActionService.GetAutofillAccessibilityDescription();
|
||||
|
||||
|
@ -90,21 +84,21 @@ Device.RuntimePlatform == Device.Android;
|
|||
}
|
||||
}
|
||||
|
||||
public AsyncCommand ToggleUseAutofillServicesCommand { get; private set; }
|
||||
public AsyncCommand ToggleUseInlineAutofillCommand { get; private set; }
|
||||
public AsyncCommand ToggleUseAccessibilityCommand { get; private set; }
|
||||
public AsyncCommand ToggleUseDrawOverCommand { get; private set; }
|
||||
public AsyncCommand ToggleAskToAddLoginCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleUseAutofillServicesCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleUseInlineAutofillCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleUseAccessibilityCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleUseDrawOverCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleAskToAddLoginCommand { get; private set; }
|
||||
public ICommand GoToBlockAutofillUrisCommand { get; private set; }
|
||||
|
||||
private void InitAndroidCommands()
|
||||
{
|
||||
ToggleUseAutofillServicesCommand = CreateDefaultAsyncCommnad(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseAutofillServices()), () => _inited);
|
||||
ToggleUseInlineAutofillCommand = CreateDefaultAsyncCommnad(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseInlineAutofillEnabledAsync()), () => _inited);
|
||||
ToggleUseAccessibilityCommand = CreateDefaultAsyncCommnad(ToggleUseAccessibilityAsync, () => _inited);
|
||||
ToggleUseDrawOverCommand = CreateDefaultAsyncCommnad(() => MainThread.InvokeOnMainThreadAsync(() => ToggleDrawOver()), () => _inited);
|
||||
ToggleAskToAddLoginCommand = CreateDefaultAsyncCommnad(ToggleAskToAddLoginAsync, () => _inited);
|
||||
GoToBlockAutofillUrisCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushAsync(new BlockAutofillUrisPage()));
|
||||
ToggleUseAutofillServicesCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseAutofillServices()), () => _inited, allowsMultipleExecutions: false);
|
||||
ToggleUseInlineAutofillCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => ToggleUseInlineAutofillEnabledAsync()), () => _inited, allowsMultipleExecutions: false);
|
||||
ToggleUseAccessibilityCommand = CreateDefaultAsyncRelayCommand(ToggleUseAccessibilityAsync, () => _inited, allowsMultipleExecutions: false);
|
||||
ToggleUseDrawOverCommand = CreateDefaultAsyncRelayCommand(() => MainThread.InvokeOnMainThreadAsync(() => ToggleDrawOver()), () => _inited, allowsMultipleExecutions: false);
|
||||
ToggleAskToAddLoginCommand = CreateDefaultAsyncRelayCommand(ToggleAskToAddLoginAsync, () => _inited, allowsMultipleExecutions: false);
|
||||
GoToBlockAutofillUrisCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushAsync(new BlockAutofillUrisPage()), allowsMultipleExecutions: false);
|
||||
}
|
||||
|
||||
private async Task InitAndroidAutofillSettingsAsync()
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Input;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.Maui.ApplicationModel;
|
||||
using Bit.App.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -36,7 +33,7 @@ namespace Bit.App.Pages
|
|||
() => _inited,
|
||||
ex => HandleException(ex));
|
||||
|
||||
ToggleCopyTotpAutomaticallyCommand = CreateDefaultAsyncCommnad(ToggleCopyTotpAutomaticallyAsync, () => _inited);
|
||||
ToggleCopyTotpAutomaticallyCommand = CreateDefaultAsyncRelayCommand(ToggleCopyTotpAutomaticallyAsync, () => _inited, allowsMultipleExecutions: false);
|
||||
|
||||
InitAndroidCommands();
|
||||
InitIOSCommands();
|
||||
|
@ -56,7 +53,7 @@ namespace Bit.App.Pages
|
|||
|
||||
public PickerViewModel<UriMatchType> DefaultUriMatchDetectionPickerViewModel { get; }
|
||||
|
||||
public AsyncCommand ToggleCopyTotpAutomaticallyCommand { get; private set; }
|
||||
public AsyncRelayCommand ToggleCopyTotpAutomaticallyCommand { get; private set; }
|
||||
|
||||
public async Task InitAsync()
|
||||
{
|
||||
|
@ -72,11 +69,11 @@ namespace Bit.App.Pages
|
|||
{
|
||||
TriggerPropertyChanged(nameof(CopyTotpAutomatically));
|
||||
|
||||
ToggleUseAutofillServicesCommand.RaiseCanExecuteChanged();
|
||||
ToggleUseInlineAutofillCommand.RaiseCanExecuteChanged();
|
||||
ToggleUseAccessibilityCommand.RaiseCanExecuteChanged();
|
||||
ToggleUseDrawOverCommand.RaiseCanExecuteChanged();
|
||||
DefaultUriMatchDetectionPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
||||
ToggleUseAutofillServicesCommand.NotifyCanExecuteChanged();
|
||||
ToggleUseInlineAutofillCommand.NotifyCanExecuteChanged();
|
||||
ToggleUseAccessibilityCommand.NotifyCanExecuteChanged();
|
||||
ToggleUseDrawOverCommand.NotifyCanExecuteChanged();
|
||||
DefaultUriMatchDetectionPickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
using System.Windows.Input;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
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
|
||||
Device.RuntimePlatform == Device.iOS && _deviceActionService.SupportsAutofillServices();
|
||||
public bool SupportsiOSAutofill => DeviceInfo.Platform == DevicePlatform.iOS && _deviceActionService.SupportsAutofillServices();
|
||||
|
||||
public ICommand GoToPasswordAutofillCommand { get; private set; }
|
||||
public ICommand GoToAppExtensionCommand { get; private set; }
|
||||
|
||||
private void InitIOSCommands()
|
||||
{
|
||||
GoToPasswordAutofillCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillPage())));
|
||||
GoToAppExtensionCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushModalAsync(new NavigationPage(new ExtensionPage())));
|
||||
GoToPasswordAutofillCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillPage())), allowsMultipleExecutions: false);
|
||||
GoToAppExtensionCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new ExtensionPage())), allowsMultipleExecutions: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,11 +28,11 @@ namespace Bit.App.Pages
|
|||
_stateService = ServiceContainer.Resolve<IStateService>();
|
||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>();
|
||||
|
||||
AddUriCommand = new AsyncCommand(AddUriAsync,
|
||||
AddUriCommand = CreateDefaultAsyncRelayCommand(AddUriAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
EditUriCommand = new AsyncCommand<BlockAutofillUriItemViewModel>(EditUriAsync,
|
||||
EditUriCommand = CreateDefaultAsyncRelayCommand<BlockAutofillUriItemViewModel>(EditUriAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ using Microsoft.Maui.ApplicationModel;
|
|||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
using Bit.App.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -34,11 +35,11 @@ namespace Bit.App.Pages
|
|||
PageTitle = AppResources.PendingLogInRequests;
|
||||
LoginRequests = new ObservableRangeCollection<PasswordlessLoginResponse>();
|
||||
|
||||
AnswerRequestCommand = new AsyncCommand<PasswordlessLoginResponse>(PasswordlessLoginAsync,
|
||||
AnswerRequestCommand = CreateDefaultAsyncRelayCommand<PasswordlessLoginResponse>(PasswordlessLoginAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
DeclineAllRequestsCommand = new AsyncCommand(DeclineAllRequestsAsync,
|
||||
DeclineAllRequestsCommand = CreateDefaultAsyncRelayCommand(DeclineAllRequestsAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
|
@ -47,9 +48,9 @@ namespace Bit.App.Pages
|
|||
|
||||
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; }
|
||||
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Input;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
using Microsoft.Maui.ApplicationModel;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
using Bit.App.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -42,19 +35,21 @@ namespace Bit.App.Pages
|
|||
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
||||
_logger = ServiceContainer.Resolve<ILogger>();
|
||||
|
||||
SyncCommand = CreateDefaultAsyncCommnad(SyncAsync, () => _inited);
|
||||
ToggleIsScreenCaptureAllowedCommand = CreateDefaultAsyncCommnad(ToggleIsScreenCaptureAllowedAsync, () => _inited);
|
||||
ToggleShouldConnectToWatchCommand = CreateDefaultAsyncCommnad(ToggleShouldConnectToWatchAsync, () => _inited);
|
||||
SyncCommand = CreateDefaultAsyncRelayCommand(SyncAsync, CanExecuteIfInited, allowsMultipleExecutions: false);
|
||||
ToggleIsScreenCaptureAllowedCommand = CreateDefaultAsyncRelayCommand(ToggleIsScreenCaptureAllowedAsync, CanExecuteIfInited, allowsMultipleExecutions: false);
|
||||
ToggleShouldConnectToWatchCommand = CreateDefaultAsyncRelayCommand(ToggleShouldConnectToWatchAsync, CanExecuteIfInited, allowsMultipleExecutions: false);
|
||||
|
||||
ClearClipboardPickerViewModel = new PickerViewModel<int>(
|
||||
_deviceActionService,
|
||||
_logger,
|
||||
OnClearClipboardChangingAsync,
|
||||
AppResources.ClearClipboard,
|
||||
() => _inited,
|
||||
CanExecuteIfInited,
|
||||
ex => HandleException(ex));
|
||||
}
|
||||
|
||||
private bool CanExecuteIfInited() => _inited;
|
||||
|
||||
public bool EnableSyncOnRefresh
|
||||
{
|
||||
get => _syncOnRefresh;
|
||||
|
@ -103,9 +98,9 @@ namespace Bit.App.Pages
|
|||
|
||||
public bool CanToggleShouldConnectToWatch => ToggleShouldConnectToWatchCommand.CanExecute(null);
|
||||
|
||||
public AsyncCommand SyncCommand { get; }
|
||||
public AsyncCommand ToggleIsScreenCaptureAllowedCommand { get; }
|
||||
public AsyncCommand ToggleShouldConnectToWatchCommand { get; }
|
||||
public AsyncRelayCommand SyncCommand { get; }
|
||||
public AsyncRelayCommand ToggleIsScreenCaptureAllowedCommand { get; }
|
||||
public AsyncRelayCommand ToggleShouldConnectToWatchCommand { get; }
|
||||
|
||||
public async Task InitAsync()
|
||||
{
|
||||
|
@ -124,10 +119,10 @@ namespace Bit.App.Pages
|
|||
{
|
||||
TriggerPropertyChanged(nameof(IsScreenCaptureAllowed));
|
||||
TriggerPropertyChanged(nameof(ShouldConnectToWatch));
|
||||
SyncCommand.RaiseCanExecuteChanged();
|
||||
ClearClipboardPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
||||
ToggleIsScreenCaptureAllowedCommand.RaiseCanExecuteChanged();
|
||||
ToggleShouldConnectToWatchCommand.RaiseCanExecuteChanged();
|
||||
SyncCommand.NotifyCanExecuteChanged();
|
||||
ClearClipboardPickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||
ToggleIsScreenCaptureAllowedCommand.NotifyCanExecuteChanged();
|
||||
ToggleShouldConnectToWatchCommand.NotifyCanExecuteChanged();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -141,8 +136,7 @@ namespace Bit.App.Pages
|
|||
[30] = AppResources.ThirtySeconds,
|
||||
[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 (Device.RuntimePlatform != Device.iOS)
|
||||
if (DeviceInfo.Platform != DevicePlatform.iOS)
|
||||
{
|
||||
clearClipboardOptions.Add(120, AppResources.TwoMinutes);
|
||||
clearClipboardOptions.Add(300, AppResources.FiveMinutes);
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Input;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Pages.Accounts;
|
||||
using Bit.Core.Resources.Localization;
|
||||
|
@ -12,10 +8,7 @@ using Bit.Core.Abstractions;
|
|||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
using Microsoft.Maui.ApplicationModel;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -80,16 +73,16 @@ namespace Bit.App.Pages
|
|||
() => _inited && !HasVaultTimeoutActionPolicy,
|
||||
ex => HandleException(ex));
|
||||
|
||||
ToggleUseThisDeviceToApproveLoginRequestsCommand = CreateDefaultAsyncCommnad(ToggleUseThisDeviceToApproveLoginRequestsAsync, () => _inited);
|
||||
GoToPendingLogInRequestsCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushModalAsync(new NavigationPage(new LoginPasswordlessRequestsListPage())));
|
||||
ToggleCanUnlockWithBiometricsCommand = CreateDefaultAsyncCommnad(ToggleCanUnlockWithBiometricsAsync, () => _inited);
|
||||
ToggleCanUnlockWithPinCommand = CreateDefaultAsyncCommnad(ToggleCanUnlockWithPinAsync, () => _inited);
|
||||
ShowAccountFingerprintPhraseCommand = CreateDefaultAsyncCommnad(ShowAccountFingerprintPhraseAsync);
|
||||
GoToTwoStepLoginCommand = CreateDefaultAsyncCommnad(() => GoToWebVaultSettingsAsync(AppResources.TwoStepLoginDescriptionLong, AppResources.ContinueToWebApp));
|
||||
GoToChangeMasterPasswordCommand = CreateDefaultAsyncCommnad(() => GoToWebVaultSettingsAsync(AppResources.ChangeMasterPasswordDescriptionLong, AppResources.ContinueToWebApp));
|
||||
LockCommand = CreateDefaultAsyncCommnad(() => _vaultTimeoutService.LockAsync(true, true));
|
||||
LogOutCommand = CreateDefaultAsyncCommnad(LogOutAsync);
|
||||
DeleteAccountCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushModalAsync(new NavigationPage(new DeleteAccountPage())));
|
||||
ToggleUseThisDeviceToApproveLoginRequestsCommand = CreateDefaultAsyncRelayCommand(ToggleUseThisDeviceToApproveLoginRequestsAsync, () => _inited, allowsMultipleExecutions: false);
|
||||
GoToPendingLogInRequestsCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new LoginPasswordlessRequestsListPage())), allowsMultipleExecutions: false);
|
||||
ToggleCanUnlockWithBiometricsCommand = CreateDefaultAsyncRelayCommand(ToggleCanUnlockWithBiometricsAsync, () => _inited, allowsMultipleExecutions: false);
|
||||
ToggleCanUnlockWithPinCommand = CreateDefaultAsyncRelayCommand(ToggleCanUnlockWithPinAsync, () => _inited, allowsMultipleExecutions: false);
|
||||
ShowAccountFingerprintPhraseCommand = CreateDefaultAsyncRelayCommand(ShowAccountFingerprintPhraseAsync, allowsMultipleExecutions: false);
|
||||
GoToTwoStepLoginCommand = CreateDefaultAsyncRelayCommand(() => GoToWebVaultSettingsAsync(AppResources.TwoStepLoginDescriptionLong, AppResources.ContinueToWebApp), allowsMultipleExecutions: false);
|
||||
GoToChangeMasterPasswordCommand = CreateDefaultAsyncRelayCommand(() => GoToWebVaultSettingsAsync(AppResources.ChangeMasterPasswordDescriptionLong, AppResources.ContinueToWebApp), allowsMultipleExecutions: false);
|
||||
LockCommand = CreateDefaultAsyncRelayCommand(() => _vaultTimeoutService.LockAsync(true, true), allowsMultipleExecutions: false);
|
||||
LogOutCommand = CreateDefaultAsyncRelayCommand(LogOutAsync, allowsMultipleExecutions: false);
|
||||
DeleteAccountCommand = CreateDefaultAsyncRelayCommand(() => Page.Navigation.PushModalAsync(new NavigationPage(new DeleteAccountPage())), allowsMultipleExecutions: false);
|
||||
}
|
||||
|
||||
public bool UseThisDeviceToApproveLoginRequests
|
||||
|
@ -114,8 +107,7 @@ namespace Bit.App.Pages
|
|||
}
|
||||
|
||||
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 (Device.RuntimePlatform == Device.iOS)
|
||||
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
||||
{
|
||||
biometricName = _deviceActionService.SupportsFaceBiometric()
|
||||
? AppResources.FaceID
|
||||
|
@ -209,18 +201,17 @@ namespace Bit.App.Pages
|
|||
|
||||
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
|
||||
Device.RuntimePlatform != Device.iOS;
|
||||
private bool IncludeLinksWithSubscriptionInfo => DeviceInfo.Platform != DevicePlatform.iOS;
|
||||
|
||||
private bool HasVaultTimeoutActionPolicy => !string.IsNullOrEmpty(_vaultTimeoutActionPolicy);
|
||||
|
||||
public PickerViewModel<int> VaultTimeoutPickerViewModel { get; }
|
||||
public PickerViewModel<VaultTimeoutAction> VaultTimeoutActionPickerViewModel { get; }
|
||||
|
||||
public AsyncCommand ToggleUseThisDeviceToApproveLoginRequestsCommand { get; }
|
||||
public AsyncRelayCommand ToggleUseThisDeviceToApproveLoginRequestsCommand { get; }
|
||||
public ICommand GoToPendingLogInRequestsCommand { get; }
|
||||
public AsyncCommand ToggleCanUnlockWithBiometricsCommand { get; }
|
||||
public AsyncCommand ToggleCanUnlockWithPinCommand { get; }
|
||||
public AsyncRelayCommand ToggleCanUnlockWithBiometricsCommand { get; }
|
||||
public AsyncRelayCommand ToggleCanUnlockWithPinCommand { get; }
|
||||
public ICommand ShowAccountFingerprintPhraseCommand { get; }
|
||||
public ICommand GoToTwoStepLoginCommand { get; }
|
||||
public ICommand GoToChangeMasterPasswordCommand { get; }
|
||||
|
@ -256,11 +247,11 @@ Device.RuntimePlatform != Device.iOS;
|
|||
TriggerPropertyChanged(nameof(VaultTimeoutPolicyDescription));
|
||||
TriggerPropertyChanged(nameof(ShowChangeMasterPassword));
|
||||
TriggerUpdateCustomVaultTimeoutPicker();
|
||||
ToggleUseThisDeviceToApproveLoginRequestsCommand.RaiseCanExecuteChanged();
|
||||
ToggleCanUnlockWithBiometricsCommand.RaiseCanExecuteChanged();
|
||||
ToggleCanUnlockWithPinCommand.RaiseCanExecuteChanged();
|
||||
VaultTimeoutPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
||||
VaultTimeoutActionPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged();
|
||||
ToggleUseThisDeviceToApproveLoginRequestsCommand.NotifyCanExecuteChanged();
|
||||
ToggleCanUnlockWithBiometricsCommand.NotifyCanExecuteChanged();
|
||||
ToggleCanUnlockWithPinCommand.NotifyCanExecuteChanged();
|
||||
VaultTimeoutPickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||
VaultTimeoutActionPickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -275,7 +266,7 @@ Device.RuntimePlatform != Device.iOS;
|
|||
_maximumVaultTimeoutPolicy = maximumVaultTimeoutPolicy?.GetInt(Policy.MINUTES_KEY);
|
||||
_vaultTimeoutActionPolicy = maximumVaultTimeoutPolicy?.GetString(Policy.ACTION_KEY);
|
||||
|
||||
MainThread.BeginInvokeOnMainThread(VaultTimeoutActionPickerViewModel.SelectOptionCommand.RaiseCanExecuteChanged);
|
||||
MainThread.BeginInvokeOnMainThread(VaultTimeoutActionPickerViewModel.SelectOptionCommand.NotifyCanExecuteChanged);
|
||||
}
|
||||
|
||||
private async Task InitVaultTimeoutPickerAsync()
|
||||
|
@ -368,10 +359,9 @@ Device.RuntimePlatform != Device.iOS;
|
|||
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
|
||||
||
|
||||
!await _platformUtilsService.AuthenticateBiometricAsync(null, Device.RuntimePlatform == Device.Android ? "." : null))
|
||||
!await _platformUtilsService.AuthenticateBiometricAsync(null, DeviceInfo.Platform == DevicePlatform.Android ? "." : null))
|
||||
{
|
||||
_canUnlockWithBiometrics = false;
|
||||
MainThread.BeginInvokeOnMainThread(() => TriggerPropertyChanged(nameof(CanUnlockWithBiometrics)));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Bit.App.Utilities;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -7,7 +8,7 @@ namespace Bit.App.Pages
|
|||
{
|
||||
public SettingsPageViewModel()
|
||||
{
|
||||
ExecuteSettingItemCommand = new AsyncCommand<SettingsPageListItem>(item => item.ExecuteAsync(),
|
||||
ExecuteSettingItemCommand = CreateDefaultAsyncRelayCommand<SettingsPageListItem>(item => item.ExecuteAsync(),
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
|
@ -24,7 +25,7 @@ namespace Bit.App.Pages
|
|||
|
||||
public List<SettingsPageListItem> SettingsItems { get; }
|
||||
|
||||
public AsyncCommand<SettingsPageListItem> ExecuteSettingItemCommand { get; }
|
||||
public AsyncRelayCommand<SettingsPageListItem> ExecuteSettingItemCommand { get; }
|
||||
|
||||
private async Task NavigateToAsync(Page page)
|
||||
{
|
||||
|
|
|
@ -22,15 +22,15 @@ namespace Bit.App.Pages
|
|||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>();
|
||||
_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),
|
||||
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),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
GoToImportItemsCommand = new AsyncCommand(GoToImportItemsAsync,
|
||||
GoToImportItemsCommand = CreateDefaultAsyncRelayCommand(GoToImportItemsAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace Bit.App.Pages
|
|||
_logger = ServiceContainer.Resolve<ILogger>();
|
||||
Attachments = new ExtendedObservableCollection<AttachmentView>();
|
||||
DeleteAttachmentCommand = new Command<AttachmentView>(DeleteAsync);
|
||||
SubmitAsyncCommand = new AsyncCommand(SubmitAsync, allowsMultipleExecutions: false);
|
||||
SubmitAsyncCommand = CreateDefaultAsyncRelayCommand(SubmitAsync, allowsMultipleExecutions: false);
|
||||
PageTitle = AppResources.Attachments;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ using Bit.Core.Exceptions;
|
|||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.App.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -28,7 +29,7 @@ namespace Bit.App.Pages
|
|||
_auditService = ServiceContainer.Resolve<IAuditService>("auditService");
|
||||
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
||||
|
||||
CheckPasswordCommand = new AsyncCommand(CheckPasswordAsync, allowsMultipleExecutions: false);
|
||||
CheckPasswordCommand = CreateDefaultAsyncRelayCommand(CheckPasswordAsync, allowsMultipleExecutions: false);
|
||||
}
|
||||
|
||||
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 AsyncCommand CheckPasswordCommand { get; }
|
||||
public AsyncRelayCommand CheckPasswordCommand { get; }
|
||||
|
||||
protected async Task CheckPasswordAsync()
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@ using Bit.Core.Utilities;
|
|||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
using Bit.App.Utilities;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
@ -99,8 +100,8 @@ namespace Bit.App.Pages
|
|||
UriOptionsCommand = new Command<LoginUriView>(UriOptions);
|
||||
FieldOptionsCommand = new Command<ICustomFieldItemViewModel>(FieldOptions);
|
||||
PasswordPromptHelpCommand = new Command(PasswordPromptHelp);
|
||||
CopyCommand = new AsyncCommand(CopyTotpClipboardAsync, onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
||||
GenerateUsernameCommand = new AsyncCommand(GenerateUsernameAsync, onException: ex => OnGenerateUsernameException(ex), allowsMultipleExecutions: false);
|
||||
CopyCommand = CreateDefaultAsyncRelayCommand(CopyTotpClipboardAsync, onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
||||
GenerateUsernameCommand = CreateDefaultAsyncRelayCommand(GenerateUsernameAsync, onException: ex => OnGenerateUsernameException(ex), allowsMultipleExecutions: false);
|
||||
Uris = new ExtendedObservableCollection<LoginUriView>();
|
||||
Fields = new ExtendedObservableCollection<ICustomFieldItemViewModel>();
|
||||
Collections = new ExtendedObservableCollection<CollectionViewModel>();
|
||||
|
@ -163,8 +164,8 @@ namespace Bit.App.Pages
|
|||
public Command UriOptionsCommand { get; set; }
|
||||
public Command FieldOptionsCommand { get; set; }
|
||||
public Command PasswordPromptHelpCommand { get; set; }
|
||||
public AsyncCommand CopyCommand { get; set; }
|
||||
public AsyncCommand GenerateUsernameCommand { get; set; }
|
||||
public AsyncRelayCommand CopyCommand { get; set; }
|
||||
public AsyncRelayCommand GenerateUsernameCommand { get; set; }
|
||||
public string CipherId { get; set; }
|
||||
public string OrganizationId { get; set; }
|
||||
public string FolderId { get; set; }
|
||||
|
|
|
@ -14,7 +14,7 @@ using Bit.Core.Enums;
|
|||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
|
||||
|
@ -66,15 +66,15 @@ namespace Bit.App.Pages
|
|||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
||||
|
||||
CopyCommand = new AsyncCommand<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);
|
||||
CopyFieldCommand = new AsyncCommand<FieldView>(field => CopyAsync(field.Type == FieldType.Hidden ? "H_FieldValue" : "FieldValue", field.Value), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
||||
CopyCommand = CreateDefaultAsyncRelayCommand<string>((id) => CopyAsync(id, null), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
||||
CopyUriCommand = CreateDefaultAsyncRelayCommand<LoginUriView>(uriView => CopyAsync("LoginUri", uriView.Uri), 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);
|
||||
CloneCommand = new AsyncCommand(CloneAsync, onException: ex => HandleException(ex), allowsMultipleExecutions: false);
|
||||
CloneCommand = CreateDefaultAsyncRelayCommand(CloneAsync, onException: ex => HandleException(ex), allowsMultipleExecutions: false);
|
||||
TogglePasswordCommand = new Command(TogglePassword);
|
||||
ToggleCardNumberCommand = new Command(ToggleCardNumber);
|
||||
ToggleCardCodeCommand = new Command(ToggleCardCode);
|
||||
DownloadAttachmentCommand = new AsyncCommand<AttachmentView>(DownloadAttachmentAsync, allowsMultipleExecutions: false);
|
||||
DownloadAttachmentCommand = CreateDefaultAsyncRelayCommand<AttachmentView>(DownloadAttachmentAsync, allowsMultipleExecutions: false);
|
||||
|
||||
PageTitle = AppResources.ViewItem;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ namespace Bit.App.Pages
|
|||
public Command TogglePasswordCommand { get; set; }
|
||||
public Command ToggleCardNumberCommand { get; set; }
|
||||
public Command ToggleCardCodeCommand { get; set; }
|
||||
public AsyncCommand<AttachmentView> DownloadAttachmentCommand { get; set; }
|
||||
public AsyncRelayCommand<AttachmentView> DownloadAttachmentCommand { get; set; }
|
||||
public string CipherId { get; set; }
|
||||
protected override string[] AdditionalPropertiesToRaiseOnCipherChanged => new string[]
|
||||
{
|
||||
|
|
|
@ -45,13 +45,13 @@ namespace Bit.App.Pages
|
|||
_logger = ServiceContainer.Resolve<ILogger>();
|
||||
|
||||
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),
|
||||
allowsMultipleExecutions: false);
|
||||
SelectCipherCommand = new AsyncCommand<IGroupingsPageListItem>(SelectCipherAsync,
|
||||
SelectCipherCommand = CreateDefaultAsyncRelayCommand<IGroupingsPageListItem>(SelectCipherAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
AddCipherCommand = new AsyncCommand(AddCipherAsync,
|
||||
AddCipherCommand = CreateDefaultAsyncRelayCommand(AddCipherAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
|
|
|
@ -52,10 +52,10 @@ namespace Bit.App.Pages
|
|||
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
||||
|
||||
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),
|
||||
allowsMultipleExecutions: false);
|
||||
AddCipherCommand = new AsyncCommand(AddCipherAsync,
|
||||
AddCipherCommand = CreateDefaultAsyncRelayCommand(AddCipherAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ using Bit.App.Utilities;
|
|||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Maui.ApplicationModel;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui;
|
||||
|
@ -37,13 +37,13 @@ namespace Bit.App.Pages
|
|||
|
||||
Cipher = cipherView;
|
||||
WebsiteIconsEnabled = websiteIconsEnabled;
|
||||
CopyCommand = new AsyncCommand(CopyToClipboardAsync,
|
||||
CopyCommand = CreateDefaultAsyncRelayCommand(CopyToClipboardAsync,
|
||||
onException: ex => _logger.Value.Exception(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
_totpTickHelper = new TotpHelper(cipherView);
|
||||
}
|
||||
|
||||
public AsyncCommand CopyCommand { get; set; }
|
||||
public AsyncRelayCommand CopyCommand { get; set; }
|
||||
|
||||
public CipherView Cipher
|
||||
{
|
||||
|
|
|
@ -71,10 +71,10 @@ namespace Bit.App.Pages
|
|||
Refreshing = true;
|
||||
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),
|
||||
allowsMultipleExecutions: false);
|
||||
VaultFilterCommand = new AsyncCommand(VaultFilterOptionsAsync,
|
||||
VaultFilterCommand = CreateDefaultAsyncRelayCommand(VaultFilterOptionsAsync,
|
||||
onException: ex => _logger.Exception(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Bit.App.Pages
|
|||
|
||||
public ScanPageViewModel()
|
||||
{
|
||||
ToggleScanModeCommand = new AsyncCommand(ToggleScanMode, onException: HandleException);
|
||||
ToggleScanModeCommand = CreateDefaultAsyncRelayCommand(ToggleScanMode, onException: HandleException);
|
||||
StartCameraCommand = new Command(StartCamera);
|
||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Bit.App.Pages
|
|||
OrganizationOptions = new List<KeyValuePair<string, string>>();
|
||||
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; }
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Bit.App.Pages
|
|||
|
||||
public VaultFilterViewModel()
|
||||
{
|
||||
VaultFilterCommand = new AsyncCommand(VaultFilterOptionsAsync,
|
||||
VaultFilterCommand = CreateDefaultAsyncRelayCommand(VaultFilterOptionsAsync,
|
||||
onException: ex => logger.Exception(ex),
|
||||
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.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel;
|
||||
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
|
||||
{
|
||||
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;
|
||||
|
||||
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,
|
||||
[CallerMemberName] string propertyName = "", string[] additionalPropertyNames = null)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue