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 CommunityToolkit.Mvvm.Input; namespace Bit.App.Pages { public class AboutSettingsPageViewModel : BaseViewModel { private readonly IPlatformUtilsService _platformUtilsService; private readonly IDeviceActionService _deviceActionService; private readonly ILogger _logger; private bool _inited; private bool _shouldSubmitCrashLogs; public AboutSettingsPageViewModel() { _platformUtilsService = ServiceContainer.Resolve(); _deviceActionService = ServiceContainer.Resolve(); _logger = ServiceContainer.Resolve(); var environmentService = ServiceContainer.Resolve(); var clipboardService = ServiceContainer.Resolve(); ToggleSubmitCrashLogsCommand = CreateDefaultAsyncRelayCommand(ToggleSubmitCrashLogsAsync, allowsMultipleExecutions: false); GoToHelpCenterCommand = CreateDefaultAsyncRelayCommand( () => LaunchUriAsync(AppResources.LearnMoreAboutHowToUseBitwardenOnTheHelpCenter, AppResources.ContinueToHelpCenter, ExternalLinksConstants.HELP_CENTER), allowsMultipleExecutions: false); GoToPrivacyPolicyCommand = CreateDefaultAsyncRelayCommand( () => LaunchUriAsync(AppResources.PrivacyPolicyDescriptionLong, AppResources.ContinueToPrivacyPolicy, ExternalLinksConstants.PRIVACY_POLICY), allowsMultipleExecutions: false); GoToWebVaultCommand = CreateDefaultAsyncRelayCommand( () => LaunchUriAsync(AppResources.ExploreMoreFeaturesOfYourBitwardenAccountOnTheWebApp, AppResources.ContinueToWebApp, environmentService.GetWebVaultUrl()), allowsMultipleExecutions: false); GoToLearnAboutOrgsCommand = CreateDefaultAsyncRelayCommand( () => LaunchUriAsync(AppResources.LearnAboutOrganizationsDescriptionLong, string.Format(AppResources.ContinueToX, ExternalLinksConstants.BITWARDEN_WEBSITE), ExternalLinksConstants.HELP_ABOUT_ORGANIZATIONS), allowsMultipleExecutions: false); RateTheAppCommand = CreateDefaultAsyncRelayCommand(RateAppAsync, allowsMultipleExecutions: false); CopyAppInfoCommand = CreateDefaultAsyncRelayCommand( () => clipboardService.CopyTextAsync(AppInfo), allowsMultipleExecutions: false); } public bool ShouldSubmitCrashLogs { get => _shouldSubmitCrashLogs; set { SetProperty(ref _shouldSubmitCrashLogs, value); ((ICommand)ToggleSubmitCrashLogsCommand).Execute(null); } } public string AppInfo { get { var appInfo = string.Format("{0}: {1} ({2})", AppResources.Version, _platformUtilsService.GetApplicationVersion(), _deviceActionService.GetBuildNumber()); return $"© Bitwarden Inc. 2015-{DateTime.Now.Year}\n\n{appInfo}"; } } public AsyncRelayCommand ToggleSubmitCrashLogsCommand { get; } public ICommand GoToHelpCenterCommand { get; } public ICommand GoToPrivacyPolicyCommand { get; } public ICommand GoToWebVaultCommand { get; } public ICommand GoToLearnAboutOrgsCommand { get; } public ICommand RateTheAppCommand { get; } public ICommand CopyAppInfoCommand { get; } public async Task InitAsync() { _shouldSubmitCrashLogs = await _logger.IsEnabled(); _inited = true; MainThread.BeginInvokeOnMainThread(() => { TriggerPropertyChanged(nameof(ShouldSubmitCrashLogs)); ToggleSubmitCrashLogsCommand.NotifyCanExecuteChanged(); }); } private async Task ToggleSubmitCrashLogsAsync() { await _logger.SetEnabled(ShouldSubmitCrashLogs); _shouldSubmitCrashLogs = await _logger.IsEnabled(); MainThread.BeginInvokeOnMainThread(() => TriggerPropertyChanged(nameof(ShouldSubmitCrashLogs))); } private async Task LaunchUriAsync(string dialogText, string dialogTitle, string uri) { if (await _platformUtilsService.ShowDialogAsync(dialogText, dialogTitle, AppResources.Continue, AppResources.Cancel)) { _platformUtilsService.LaunchUri(uri); } } private async Task RateAppAsync() { if (await _platformUtilsService.ShowDialogAsync(AppResources.RateAppDescriptionLong, AppResources.ContinueToAppStore, AppResources.Continue, AppResources.Cancel)) { await MainThread.InvokeOnMainThreadAsync(_deviceActionService.RateApp); } } /// INFO: Left here in case we need to debug push notifications /// /// Sets up app info plus debugging information for push notifications. /// Useful when trying to solve problems regarding push notifications. /// /// /// Add an IniAsync() method to be called on view appearing, change the AppInfo to be a normal property with setter /// and set the result of this method in the main thread to that property to show that in the UI. /// // public async Task GetAppInfoForPushNotificationsDebugAsync() // { // var stateService = ServiceContainer.Resolve(); // var appInfo = string.Format("{0}: {1} ({2})", AppResources.Version, // _platformUtilsService.GetApplicationVersion(), _deviceActionService.GetBuildNumber()); //#if DEBUG // var pushNotificationsRegistered = ServiceContainer.Resolve("pushNotificationService").IsRegisteredForPush; // var pnServerRegDate = await stateService.GetPushLastRegistrationDateAsync(); // var pnServerError = await stateService.GetPushInstallationRegistrationErrorAsync(); // var pnServerRegDateMessage = default(DateTime) == pnServerRegDate ? "-" : $"{pnServerRegDate.GetValueOrDefault().ToShortDateString()}-{pnServerRegDate.GetValueOrDefault().ToShortTimeString()} UTC"; // var errorMessage = string.IsNullOrEmpty(pnServerError) ? string.Empty : $"Push Notifications Server Registration error: {pnServerError}"; // var text = string.Format("© Bitwarden Inc. 2015-{0}\n\n{1}\nPush Notifications registered:{2}\nPush Notifications Server Last Date :{3}\n{4}", DateTime.Now.Year, appInfo, pushNotificationsRegistered, pnServerRegDateMessage, errorMessage); //#else // var text = string.Format("© Bitwarden Inc. 2015-{0}\n\n{1}", DateTime.Now.Year, appInfo); //#endif // return text; // } } }