mirror of
https://github.com/bitwarden/android.git
synced 2024-12-28 03:48:31 +03:00
PM-3350 Improved code safety adding a lot of try...catch and logging throughout the app. Also made the invoking on main thread safer on several places of the app. Additionally, on the GroupingsPageViewModel changed the code removing the old Xamarin hack and just using Replace directly instead of Clearing first to see if that fixes the crash we're having sometimes on the app.
This commit is contained in:
parent
27fa79e0bd
commit
1949a450fd
20 changed files with 745 additions and 512 deletions
|
@ -54,10 +54,6 @@ namespace Bit.iOS
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
||||||
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
||||||
|
|
||||||
//LoadApplication(new App.App(null));
|
|
||||||
//iOSCoreHelpers.AppearanceAdjustments();
|
|
||||||
//ZXing.Net.Mobile.Forms.iOS.Platform.Init();
|
|
||||||
|
|
||||||
ConnectToWatchIfNeededAsync().FireAndForget();
|
ConnectToWatchIfNeededAsync().FireAndForget();
|
||||||
|
|
||||||
_broadcasterService.Subscribe(nameof(AppDelegate), async (message) =>
|
_broadcasterService.Subscribe(nameof(AppDelegate), async (message) =>
|
||||||
|
@ -219,7 +215,11 @@ namespace Bit.iOS
|
||||||
|
|
||||||
public override void DidEnterBackground(UIApplication uiApplication)
|
public override void DidEnterBackground(UIApplication uiApplication)
|
||||||
{
|
{
|
||||||
_stateService?.SetLastActiveTimeAsync(_deviceActionService.GetActiveTime());
|
if (_stateService != null && _deviceActionService != null)
|
||||||
|
{
|
||||||
|
_stateService.SetLastActiveTimeAsync(_deviceActionService.GetActiveTime());
|
||||||
|
}
|
||||||
|
|
||||||
_messagingService?.Send("slept");
|
_messagingService?.Send("slept");
|
||||||
base.DidEnterBackground(uiApplication);
|
base.DidEnterBackground(uiApplication);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,8 @@ namespace Bit.App
|
||||||
private readonly IAccountsManager _accountsManager;
|
private readonly IAccountsManager _accountsManager;
|
||||||
private readonly IPushNotificationService _pushNotificationService;
|
private readonly IPushNotificationService _pushNotificationService;
|
||||||
private readonly IConfigService _configService;
|
private readonly IConfigService _configService;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
private static bool _isResumed;
|
private static bool _isResumed;
|
||||||
// these variables are static because the app is launching new activities on notification click, creating new instances of App.
|
// these variables are static because the app is launching new activities on notification click, creating new instances of App.
|
||||||
private static bool _pendingCheckPasswordlessLoginRequests;
|
private static bool _pendingCheckPasswordlessLoginRequests;
|
||||||
|
@ -155,6 +157,7 @@ namespace Bit.App
|
||||||
_accountsManager = ServiceContainer.Resolve<IAccountsManager>("accountsManager");
|
_accountsManager = ServiceContainer.Resolve<IAccountsManager>("accountsManager");
|
||||||
_pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>();
|
_pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>();
|
||||||
_configService = ServiceContainer.Resolve<IConfigService>();
|
_configService = ServiceContainer.Resolve<IConfigService>();
|
||||||
|
_logger = ServiceContainer.Resolve<ILogger>();
|
||||||
|
|
||||||
_accountsManager.Init(() => Options, this);
|
_accountsManager.Init(() => Options, this);
|
||||||
|
|
||||||
|
@ -169,7 +172,7 @@ namespace Bit.App
|
||||||
var confirmed = true;
|
var confirmed = true;
|
||||||
var confirmText = string.IsNullOrWhiteSpace(details.ConfirmText) ?
|
var confirmText = string.IsNullOrWhiteSpace(details.ConfirmText) ?
|
||||||
AppResources.Ok : details.ConfirmText;
|
AppResources.Ok : details.ConfirmText;
|
||||||
MainThread.BeginInvokeOnMainThread(async () =>
|
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(details.CancelText))
|
if (!string.IsNullOrWhiteSpace(details.CancelText))
|
||||||
{
|
{
|
||||||
|
@ -183,20 +186,16 @@ namespace Bit.App
|
||||||
_messagingService.Send("showDialogResolve", new Tuple<int, bool>(details.DialogId, confirmed));
|
_messagingService.Send("showDialogResolve", new Tuple<int, bool>(details.DialogId, confirmed));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#if IOS
|
||||||
else if (message.Command == AppHelpers.RESUMED_MESSAGE_COMMAND)
|
else if (message.Command == AppHelpers.RESUMED_MESSAGE_COMMAND)
|
||||||
{
|
|
||||||
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
|
||||||
{
|
{
|
||||||
ResumedAsync().FireAndForget();
|
ResumedAsync().FireAndForget();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (message.Command == "slept")
|
else if (message.Command == "slept")
|
||||||
{
|
|
||||||
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
|
||||||
{
|
{
|
||||||
await SleptAsync();
|
await SleptAsync();
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
else if (message.Command == "migrated")
|
else if (message.Command == "migrated")
|
||||||
{
|
{
|
||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
|
@ -213,7 +212,7 @@ namespace Bit.App
|
||||||
Options.OtpData = new OtpData((string)message.Data);
|
Options.OtpData = new OtpData((string)message.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainThread.InvokeOnMainThreadAsync(async () =>
|
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||||||
{
|
{
|
||||||
if (MainPage is TabsPage tabsPage)
|
if (MainPage is TabsPage tabsPage)
|
||||||
{
|
{
|
||||||
|
@ -249,7 +248,7 @@ namespace Bit.App
|
||||||
}
|
}
|
||||||
else if (message.Command == "convertAccountToKeyConnector")
|
else if (message.Command == "convertAccountToKeyConnector")
|
||||||
{
|
{
|
||||||
MainThread.BeginInvokeOnMainThread(async () =>
|
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||||||
{
|
{
|
||||||
await MainPage.Navigation.PushModalAsync(
|
await MainPage.Navigation.PushModalAsync(
|
||||||
new NavigationPage(new RemoveMasterPasswordPage()));
|
new NavigationPage(new RemoveMasterPasswordPage()));
|
||||||
|
@ -257,7 +256,7 @@ namespace Bit.App
|
||||||
}
|
}
|
||||||
else if (message.Command == Constants.ForceUpdatePassword)
|
else if (message.Command == Constants.ForceUpdatePassword)
|
||||||
{
|
{
|
||||||
MainThread.BeginInvokeOnMainThread(async () =>
|
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||||||
{
|
{
|
||||||
await MainPage.Navigation.PushModalAsync(
|
await MainPage.Navigation.PushModalAsync(
|
||||||
new NavigationPage(new UpdateTempPasswordPage()));
|
new NavigationPage(new UpdateTempPasswordPage()));
|
||||||
|
@ -372,6 +371,8 @@ namespace Bit.App
|
||||||
public AppOptions Options { get; private set; }
|
public AppOptions Options { get; private set; }
|
||||||
|
|
||||||
protected override async void OnStart()
|
protected override async void OnStart()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine("XF App: OnStart");
|
System.Diagnostics.Debug.WriteLine("XF App: OnStart");
|
||||||
_isResumed = true;
|
_isResumed = true;
|
||||||
|
@ -390,23 +391,33 @@ namespace Bit.App
|
||||||
{
|
{
|
||||||
_messagingService.Send(Constants.PasswordlessLoginRequestKey);
|
_messagingService.Send(Constants.PasswordlessLoginRequestKey);
|
||||||
}
|
}
|
||||||
if (DeviceInfo.Platform == DevicePlatform.Android)
|
#if ANDROID
|
||||||
{
|
|
||||||
await _vaultTimeoutService.CheckVaultTimeoutAsync();
|
await _vaultTimeoutService.CheckVaultTimeoutAsync();
|
||||||
// Reset delay on every start
|
// Reset delay on every start
|
||||||
_vaultTimeoutService.DelayLockAndLogoutMs = null;
|
_vaultTimeoutService.DelayLockAndLogoutMs = null;
|
||||||
}
|
#endif
|
||||||
|
|
||||||
await _configService.GetAsync();
|
await _configService.GetAsync();
|
||||||
_messagingService.Send("startEventTimer");
|
_messagingService.Send("startEventTimer");
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger?.Exception(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
protected override async void OnSleep()
|
protected override async void OnSleep()
|
||||||
|
#else
|
||||||
|
protected override void OnSleep()
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine("XF App: OnSleep");
|
System.Diagnostics.Debug.WriteLine("XF App: OnSleep");
|
||||||
_isResumed = false;
|
_isResumed = false;
|
||||||
if (DeviceInfo.Platform == DevicePlatform.Android)
|
#if ANDROID
|
||||||
{
|
|
||||||
var isLocked = await _vaultTimeoutService.IsLockedAsync();
|
var isLocked = await _vaultTimeoutService.IsLockedAsync();
|
||||||
if (!isLocked)
|
if (!isLocked)
|
||||||
{
|
{
|
||||||
|
@ -417,10 +428,18 @@ namespace Bit.App
|
||||||
ClearAutofillUri();
|
ClearAutofillUri();
|
||||||
}
|
}
|
||||||
await SleptAsync();
|
await SleptAsync();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger?.Exception(ex);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnResume()
|
protected override void OnResume()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine("XF App: OnResume");
|
System.Diagnostics.Debug.WriteLine("XF App: OnResume");
|
||||||
_isResumed = true;
|
_isResumed = true;
|
||||||
|
@ -428,9 +447,15 @@ namespace Bit.App
|
||||||
{
|
{
|
||||||
_messagingService.Send(Constants.PasswordlessLoginRequestKey);
|
_messagingService.Send(Constants.PasswordlessLoginRequestKey);
|
||||||
}
|
}
|
||||||
if (DeviceInfo.Platform == DevicePlatform.Android)
|
#if ANDROID
|
||||||
{
|
|
||||||
ResumedAsync().FireAndForget();
|
ResumedAsync().FireAndForget();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger?.Exception(ex);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,6 +541,8 @@ namespace Bit.App
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
MainThread.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Options.Uri = null;
|
Options.Uri = null;
|
||||||
if (isLocked)
|
if (isLocked)
|
||||||
|
@ -526,6 +553,12 @@ namespace Bit.App
|
||||||
{
|
{
|
||||||
App.MainPage = new TabsPage();
|
App.MainPage = new TabsPage();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
|
@ -549,7 +582,7 @@ namespace Bit.App
|
||||||
ThemeManager.SetTheme(Resources);
|
ThemeManager.SetTheme(Resources);
|
||||||
RequestedThemeChanged += (s, a) =>
|
RequestedThemeChanged += (s, a) =>
|
||||||
{
|
{
|
||||||
UpdateThemeAsync();
|
UpdateThemeAsync().FireAndForget();
|
||||||
};
|
};
|
||||||
_isResumed = true;
|
_isResumed = true;
|
||||||
#if IOS
|
#if IOS
|
||||||
|
@ -567,6 +600,8 @@ namespace Bit.App
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var lastSync = await _syncService.GetLastSyncAsync();
|
var lastSync = await _syncService.GetLastSyncAsync();
|
||||||
if (lastSync == null || ((DateTime.UtcNow - lastSync) > TimeSpan.FromMinutes(30)))
|
if (lastSync == null || ((DateTime.UtcNow - lastSync) > TimeSpan.FromMinutes(30)))
|
||||||
|
@ -574,6 +609,11 @@ namespace Bit.App
|
||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
await _syncService.FullSyncAsync(false);
|
await _syncService.FullSyncAsync(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ using Bit.App.Utilities;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
@ -26,16 +27,24 @@ namespace Bit.App.Pages
|
||||||
_vm = BindingContext as LockPageViewModel;
|
_vm = BindingContext as LockPageViewModel;
|
||||||
_vm.CheckPendingAuthRequests = checkPendingAuthRequests;
|
_vm.CheckPendingAuthRequests = checkPendingAuthRequests;
|
||||||
_vm.Page = this;
|
_vm.Page = this;
|
||||||
_vm.UnlockedAction = () => MainThread.BeginInvokeOnMainThread(async () => await UnlockedAsync());
|
_vm.UnlockedAction = () => MainThread.BeginInvokeOnMainThread(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await UnlockedAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
#if IOS
|
||||||
{
|
|
||||||
ToolbarItems.Add(_moreItem);
|
ToolbarItems.Add(_moreItem);
|
||||||
}
|
#else
|
||||||
else
|
|
||||||
{
|
|
||||||
ToolbarItems.Add(_logOut);
|
ToolbarItems.Add(_logOut);
|
||||||
}
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entry SecretEntry
|
public Entry SecretEntry
|
||||||
|
@ -64,6 +73,8 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async void OnAppearing()
|
protected override async void OnAppearing()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
_broadcasterService.Subscribe(nameof(LockPage), message =>
|
_broadcasterService.Subscribe(nameof(LockPage), message =>
|
||||||
|
@ -108,11 +119,17 @@ namespace Bit.App.Pages
|
||||||
var tasks = Task.Run(async () =>
|
var tasks = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
MainThread.BeginInvokeOnMainThread(async () => await _vm.PromptBiometricAsync());
|
await MainThread.InvokeOnMainThreadAsync(async () => await _vm.PromptBiometricAsync());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void PerformFocusSecretEntry(int? cursorPosition)
|
private void PerformFocusSecretEntry(int? cursorPosition)
|
||||||
{
|
{
|
||||||
|
@ -166,14 +183,25 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Biometric_Clicked(object sender, EventArgs e)
|
private async void Biometric_Clicked(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (DoOnce())
|
if (DoOnce())
|
||||||
{
|
{
|
||||||
await _vm.PromptBiometricAsync();
|
await _vm.PromptBiometricAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void More_Clicked(object sender, System.EventArgs e)
|
private async void More_Clicked(object sender, System.EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await _accountListOverlay.HideAsync();
|
await _accountListOverlay.HideAsync();
|
||||||
|
|
||||||
|
@ -190,6 +218,12 @@ namespace Bit.App.Pages
|
||||||
await _vm.LogOutAsync();
|
await _vm.LogOutAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task UnlockedAsync()
|
private async Task UnlockedAsync()
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
private readonly LazyResolve<IStateService> _stateService = new LazyResolve<IStateService>();
|
private readonly LazyResolve<IStateService> _stateService = new LazyResolve<IStateService>();
|
||||||
private readonly LazyResolve<IDeviceActionService> _deviceActionService = new LazyResolve<IDeviceActionService>();
|
private readonly LazyResolve<IDeviceActionService> _deviceActionService = new LazyResolve<IDeviceActionService>();
|
||||||
|
private readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>();
|
||||||
|
|
||||||
protected int ShowModalAnimationDelay = 400;
|
protected int ShowModalAnimationDelay = 400;
|
||||||
protected int ShowPageAnimationDelay = 100;
|
protected int ShowPageAnimationDelay = 100;
|
||||||
|
@ -47,12 +48,22 @@ namespace Bit.App.Pages
|
||||||
protected virtual bool ShouldCheckToPreventOnNavigatedToCalledTwice => false;
|
protected virtual bool ShouldCheckToPreventOnNavigatedToCalledTwice => false;
|
||||||
|
|
||||||
protected override async void OnNavigatedTo(NavigatedToEventArgs args)
|
protected override async void OnNavigatedTo(NavigatedToEventArgs args)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
base.OnNavigatedTo(args);
|
base.OnNavigatedTo(args);
|
||||||
|
|
||||||
if (IsThemeDirty)
|
if (IsThemeDirty)
|
||||||
{
|
{
|
||||||
UpdateOnThemeChanged();
|
try
|
||||||
|
{
|
||||||
|
await UpdateOnThemeChanged();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Core.Services.LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
// Don't rethrow on theme changed so the user can still continue on the app.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await SaveActivityAsync();
|
await SaveActivityAsync();
|
||||||
|
@ -65,6 +76,12 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
await InitOnNavigatedToAsync();
|
await InitOnNavigatedToAsync();
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Core.Services.LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual Task InitOnNavigatedToAsync() => Task.CompletedTask;
|
protected virtual Task InitOnNavigatedToAsync() => Task.CompletedTask;
|
||||||
|
|
||||||
|
@ -115,6 +132,8 @@ namespace Bit.App.Pages
|
||||||
ContentView targetView = null)
|
ContentView targetView = null)
|
||||||
{
|
{
|
||||||
async Task DoWorkAsync()
|
async Task DoWorkAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await workFunction.Invoke();
|
await workFunction.Invoke();
|
||||||
if (sourceView != null)
|
if (sourceView != null)
|
||||||
|
@ -129,16 +148,22 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await DoWorkAsync();
|
_logger.Value.Exception(ex);
|
||||||
return;
|
throw;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IOS
|
||||||
|
await DoWorkAsync();
|
||||||
|
#else
|
||||||
await Task.Run(async () =>
|
await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(fromModal ? ShowModalAnimationDelay : ShowPageAnimationDelay);
|
await Task.Delay(fromModal ? ShowModalAnimationDelay : ShowPageAnimationDelay);
|
||||||
MainThread.BeginInvokeOnMainThread(async () => await DoWorkAsync());
|
MainThread.BeginInvokeOnMainThread(async () => await DoWorkAsync());
|
||||||
});
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void RequestFocus(InputView input)
|
protected void RequestFocus(InputView input)
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace Bit.App.Pages
|
||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
{
|
{
|
||||||
var history = await _passwordGenerationService.GetHistoryAsync();
|
var history = await _passwordGenerationService.GetHistoryAsync();
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
History.ResetWithRange(history ?? new List<GeneratedPasswordHistory>());
|
History.ResetWithRange(history ?? new List<GeneratedPasswordHistory>());
|
||||||
ShowNoData = History.Count == 0;
|
ShowNoData = History.Count == 0;
|
||||||
|
@ -66,7 +66,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Device.InvokeOnMainThreadAsync(() => History.ResetWithRange(new List<GeneratedPasswordHistory>()));
|
await MainThread.InvokeOnMainThreadAsync(() => History.ResetWithRange(new List<GeneratedPasswordHistory>()));
|
||||||
|
|
||||||
await InitAsync();
|
await InitAsync();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace Bit.App.Pages
|
||||||
public partial class GeneratorPage : BaseContentPage, IThemeDirtablePage
|
public partial class GeneratorPage : BaseContentPage, IThemeDirtablePage
|
||||||
{
|
{
|
||||||
private readonly IBroadcasterService _broadcasterService;
|
private readonly IBroadcasterService _broadcasterService;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
private GeneratorPageViewModel _vm;
|
private GeneratorPageViewModel _vm;
|
||||||
private readonly bool _fromTabPage;
|
private readonly bool _fromTabPage;
|
||||||
|
@ -26,6 +27,8 @@ namespace Bit.App.Pages
|
||||||
_tabsPage = tabsPage;
|
_tabsPage = tabsPage;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>();
|
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>();
|
||||||
|
_logger = ServiceContainer.Resolve<ILogger>();
|
||||||
|
|
||||||
_vm = BindingContext as GeneratorPageViewModel;
|
_vm = BindingContext as GeneratorPageViewModel;
|
||||||
_vm.Page = this;
|
_vm.Page = this;
|
||||||
_fromTabPage = fromTabPage;
|
_fromTabPage = fromTabPage;
|
||||||
|
@ -35,26 +38,21 @@ namespace Bit.App.Pages
|
||||||
_vm.EmailWebsite = emailWebsite;
|
_vm.EmailWebsite = emailWebsite;
|
||||||
_vm.EditMode = editMode;
|
_vm.EditMode = editMode;
|
||||||
_vm.IosExtension = appOptions?.IosExtension ?? false;
|
_vm.IosExtension = appOptions?.IosExtension ?? false;
|
||||||
// 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
|
|
||||||
var isIos = Device.RuntimePlatform == Device.iOS;
|
|
||||||
if (selectAction != null)
|
if (selectAction != null)
|
||||||
{
|
{
|
||||||
if (isIos)
|
#if IOS
|
||||||
{
|
|
||||||
ToolbarItems.Add(_closeItem);
|
ToolbarItems.Add(_closeItem);
|
||||||
}
|
#endif
|
||||||
ToolbarItems.Add(_selectItem);
|
ToolbarItems.Add(_selectItem);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (isIos)
|
#if IOS
|
||||||
{
|
|
||||||
ToolbarItems.Add(_moreItem);
|
ToolbarItems.Add(_moreItem);
|
||||||
}
|
#else
|
||||||
else
|
|
||||||
{
|
|
||||||
ToolbarItems.Add(_historyItem);
|
ToolbarItems.Add(_historyItem);
|
||||||
}
|
#endif
|
||||||
}
|
}
|
||||||
_typePicker.On<Microsoft.Maui.Controls.PlatformConfiguration.iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
_typePicker.On<Microsoft.Maui.Controls.PlatformConfiguration.iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
||||||
_passwordTypePicker.On<Microsoft.Maui.Controls.PlatformConfiguration.iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
_passwordTypePicker.On<Microsoft.Maui.Controls.PlatformConfiguration.iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
||||||
|
@ -70,6 +68,8 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async override void OnAppearing()
|
protected async override void OnAppearing()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
|
|
||||||
|
@ -84,10 +84,16 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
if (message.Command is ThemeManager.UPDATED_THEME_MESSAGE_KEY)
|
if (message.Command is ThemeManager.UPDATED_THEME_MESSAGE_KEY)
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(() => _vm.RedrawPassword());
|
MainThread.BeginInvokeOnMainThread(() => _vm.RedrawPassword());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnDisappearing()
|
protected override void OnDisappearing()
|
||||||
{
|
{
|
||||||
|
@ -100,16 +106,19 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
protected override bool OnBackButtonPressed()
|
protected override bool OnBackButtonPressed()
|
||||||
{
|
{
|
||||||
// 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 ANDROID
|
||||||
if (Device.RuntimePlatform == Device.Android && _tabsPage != null)
|
if (_tabsPage != null)
|
||||||
{
|
{
|
||||||
_tabsPage.ResetToVaultPage();
|
_tabsPage.ResetToVaultPage();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return base.OnBackButtonPressed();
|
return base.OnBackButtonPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void More_Clicked(object sender, EventArgs e)
|
private async void More_Clicked(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (!DoOnce())
|
if (!DoOnce())
|
||||||
{
|
{
|
||||||
|
@ -123,6 +132,11 @@ namespace Bit.App.Pages
|
||||||
await Navigation.PushModalAsync(new Microsoft.Maui.Controls.NavigationPage(page));
|
await Navigation.PushModalAsync(new Microsoft.Maui.Controls.NavigationPage(page));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Select_Clicked(object sender, EventArgs e)
|
private void Select_Clicked(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
@ -144,7 +158,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
await base.UpdateOnThemeChanged();
|
await base.UpdateOnThemeChanged();
|
||||||
|
|
||||||
await Device.InvokeOnMainThreadAsync(() =>
|
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||||
{
|
{
|
||||||
if (_vm != null)
|
if (_vm != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace Bit.App.Pages
|
||||||
private readonly ISyncService _syncService;
|
private readonly ISyncService _syncService;
|
||||||
private readonly IVaultTimeoutService _vaultTimeoutService;
|
private readonly IVaultTimeoutService _vaultTimeoutService;
|
||||||
private readonly ISendService _sendService;
|
private readonly ISendService _sendService;
|
||||||
|
private readonly ILogger _logger;
|
||||||
private readonly SendGroupingsPageViewModel _vm;
|
private readonly SendGroupingsPageViewModel _vm;
|
||||||
private readonly string _pageName;
|
private readonly string _pageName;
|
||||||
|
|
||||||
|
@ -33,6 +34,8 @@ namespace Bit.App.Pages
|
||||||
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
||||||
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
||||||
_sendService = ServiceContainer.Resolve<ISendService>("sendService");
|
_sendService = ServiceContainer.Resolve<ISendService>("sendService");
|
||||||
|
_logger = ServiceContainer.Resolve<ILogger>();
|
||||||
|
|
||||||
_vm = BindingContext as SendGroupingsPageViewModel;
|
_vm = BindingContext as SendGroupingsPageViewModel;
|
||||||
_vm.Page = this;
|
_vm.Page = this;
|
||||||
_vm.MainPage = mainPage;
|
_vm.MainPage = mainPage;
|
||||||
|
@ -43,25 +46,23 @@ namespace Bit.App.Pages
|
||||||
_vm.PageTitle = pageTitle;
|
_vm.PageTitle = pageTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 IOS
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
_absLayout.Children.Remove(_fab);
|
_absLayout.Children.Remove(_fab);
|
||||||
if (type == null)
|
if (type == null)
|
||||||
{
|
{
|
||||||
ToolbarItems.Add(_aboutIconItem);
|
ToolbarItems.Add(_aboutIconItem);
|
||||||
}
|
}
|
||||||
ToolbarItems.Add(_addItem);
|
ToolbarItems.Add(_addItem);
|
||||||
}
|
#else
|
||||||
else
|
|
||||||
{
|
|
||||||
ToolbarItems.Add(_syncItem);
|
ToolbarItems.Add(_syncItem);
|
||||||
ToolbarItems.Add(_lockItem);
|
ToolbarItems.Add(_lockItem);
|
||||||
ToolbarItems.Add(_aboutTextItem);
|
ToolbarItems.Add(_aboutTextItem);
|
||||||
}
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async void OnAppearing()
|
protected override async void OnAppearing()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
if (_syncService.SyncInProgress)
|
if (_syncService.SyncInProgress)
|
||||||
|
@ -75,12 +76,12 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
if (message.Command == "syncStarted")
|
if (message.Command == "syncStarted")
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(() => IsBusy = true);
|
MainThread.BeginInvokeOnMainThread(() => IsBusy = true);
|
||||||
}
|
}
|
||||||
else if (message.Command == "syncCompleted" || message.Command == "sendUpdated")
|
else if (message.Command == "syncCompleted" || message.Command == "sendUpdated")
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||||
{
|
{
|
||||||
IsBusy = false;
|
IsBusy = false;
|
||||||
if (_vm.LoadedOnce)
|
if (_vm.LoadedOnce)
|
||||||
|
@ -123,6 +124,12 @@ namespace Bit.App.Pages
|
||||||
await CheckAddRequest();
|
await CheckAddRequest();
|
||||||
}, _mainContent);
|
}, _mainContent);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnDisappearing()
|
protected override void OnDisappearing()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,22 +1,11 @@
|
||||||
using System;
|
using Bit.App.Abstractions;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.Core.Resources.Localization;
|
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using Bit.Core;
|
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
using DeviceType = Bit.Core.Enums.DeviceType;
|
|
||||||
using Microsoft.Maui.Networking;
|
|
||||||
using Microsoft.Maui.Devices;
|
|
||||||
using Microsoft.Maui.Controls;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class SendGroupingsPageViewModel : BaseViewModel
|
public class SendGroupingsPageViewModel : BaseViewModel
|
||||||
|
@ -117,6 +106,9 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
var authed = await _stateService.IsAuthenticatedAsync();
|
var authed = await _stateService.IsAuthenticatedAsync();
|
||||||
if (!authed)
|
if (!authed)
|
||||||
{
|
{
|
||||||
|
@ -139,6 +131,13 @@ namespace Bit.App.Pages
|
||||||
Loading = true;
|
Loading = true;
|
||||||
ShowList = false;
|
ShowList = false;
|
||||||
SendEnabled = !await AppHelpers.IsSendDisabledByPolicyAsync();
|
SendEnabled = !await AppHelpers.IsSendDisabledByPolicyAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Value.Exception(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
var groupedSends = new List<SendGroupingsPageListGroup>();
|
var groupedSends = new List<SendGroupingsPageListGroup>();
|
||||||
var page = Page as SendGroupingsPage;
|
var page = Page as SendGroupingsPage;
|
||||||
|
|
||||||
|
@ -146,8 +145,11 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
await LoadDataAsync();
|
await LoadDataAsync();
|
||||||
|
|
||||||
// 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 IOS
|
||||||
var uppercaseGroupNames = Device.RuntimePlatform == Device.iOS;
|
var uppercaseGroupNames = true;
|
||||||
|
#else
|
||||||
|
var uppercaseGroupNames = false;
|
||||||
|
#endif
|
||||||
if (MainPage)
|
if (MainPage)
|
||||||
{
|
{
|
||||||
groupedSends.Add(new SendGroupingsPageListGroup(
|
groupedSends.Add(new SendGroupingsPageListGroup(
|
||||||
|
@ -208,6 +210,11 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Value.Exception(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_doingLoad = false;
|
_doingLoad = false;
|
||||||
|
@ -314,6 +321,8 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SendOptionsAsync(SendView send)
|
private async void SendOptionsAsync(SendView send)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if ((Page as BaseContentPage).DoOnce())
|
if ((Page as BaseContentPage).DoOnce())
|
||||||
{
|
{
|
||||||
|
@ -324,5 +333,11 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Value.Exception(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
if (message.Command == "selectSaveFileResult")
|
if (message.Command == "selectSaveFileResult")
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
var data = message.Data as Tuple<string, string>;
|
var data = message.Data as Tuple<string, string>;
|
||||||
if (data == null)
|
if (data == null)
|
||||||
|
|
|
@ -49,12 +49,10 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
private void UpdatePlaceholder()
|
private void UpdatePlaceholder()
|
||||||
{
|
{
|
||||||
// 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 ANDROID
|
||||||
if (Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
|
||||||
MainThread.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
_emptyPlaceholder.Source = ImageSource.FromFile(ThemeManager.UsingLightTheme ? "empty_login_requests" : "empty_login_requests_dark"));
|
_emptyPlaceholder.Source = ImageSource.FromFile(ThemeManager.UsingLightTheme ? "empty_login_requests" : "empty_login_requests_dark"));
|
||||||
}
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Domain;
|
using Bit.Core.Models.Domain;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
@ -86,6 +87,8 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async void OnAppearing()
|
protected override async void OnAppearing()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
_broadcasterService.Subscribe(nameof(TabsPage), async (message) =>
|
_broadcasterService.Subscribe(nameof(TabsPage), async (message) =>
|
||||||
|
@ -103,6 +106,12 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
await ForcePasswordResetIfNeededAsync();
|
await ForcePasswordResetIfNeededAsync();
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ForcePasswordResetIfNeededAsync()
|
private async Task ForcePasswordResetIfNeededAsync()
|
||||||
{
|
{
|
||||||
|
@ -173,6 +182,8 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async void OnCurrentPageChanged()
|
protected override async void OnCurrentPageChanged()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (CurrentPage is NavigationPage navPage)
|
if (CurrentPage is NavigationPage navPage)
|
||||||
{
|
{
|
||||||
|
@ -192,6 +203,12 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void OnPageReselected()
|
public void OnPageReselected()
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
if (message.Command == "selectFileResult")
|
if (message.Command == "selectFileResult")
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
var data = message.Data as Tuple<byte[], string>;
|
var data = message.Data as Tuple<byte[], string>;
|
||||||
_vm.FileData = data.Item1;
|
_vm.FileData = data.Item1;
|
||||||
|
|
|
@ -7,6 +7,7 @@ using Bit.Core.Enums;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.Maui.Controls.PlatformConfiguration;
|
using Microsoft.Maui.Controls.PlatformConfiguration;
|
||||||
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;
|
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
@ -262,9 +263,17 @@ namespace Bit.App.Pages
|
||||||
var page = new ScanPage(key =>
|
var page = new ScanPage(key =>
|
||||||
{
|
{
|
||||||
MainThread.BeginInvokeOnMainThread(async () =>
|
MainThread.BeginInvokeOnMainThread(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await Navigation.PopModalAsync();
|
await Navigation.PopModalAsync();
|
||||||
await _vm.UpdateTotpKeyAsync(key);
|
await _vm.UpdateTotpKeyAsync(key);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -63,12 +63,12 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
if (message.Command == "syncStarted")
|
if (message.Command == "syncStarted")
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(() => IsBusy = true);
|
MainThread.BeginInvokeOnMainThread(() => IsBusy = true);
|
||||||
}
|
}
|
||||||
else if (message.Command == "syncCompleted")
|
else if (message.Command == "syncCompleted")
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
IsBusy = false;
|
IsBusy = false;
|
||||||
if (message.Data is Dictionary<string, object> data && data.ContainsKey("successfully"))
|
if (message.Data is Dictionary<string, object> data && data.ContainsKey("successfully"))
|
||||||
|
@ -83,7 +83,7 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
else if (message.Command == "selectSaveFileResult")
|
else if (message.Command == "selectSaveFileResult")
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
var data = message.Data as Tuple<string, string>;
|
var data = message.Data as Tuple<string, string>;
|
||||||
if (data == null)
|
if (data == null)
|
||||||
|
|
|
@ -108,6 +108,8 @@ namespace Bit.App.Pages
|
||||||
var previousCts = _searchCancellationTokenSource;
|
var previousCts = _searchCancellationTokenSource;
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
List<CipherView> ciphers = null;
|
List<CipherView> ciphers = null;
|
||||||
var searchable = !string.IsNullOrWhiteSpace(searchText) && searchText.Length > 1;
|
var searchable = !string.IsNullOrWhiteSpace(searchText) && searchText.Length > 1;
|
||||||
|
@ -155,6 +157,11 @@ namespace Bit.App.Pages
|
||||||
ShowNoData = !shouldShowAllWhenEmpty && searchable && Ciphers.Count == 0;
|
ShowNoData = !shouldShowAllWhenEmpty && searchable && Ciphers.Count == 0;
|
||||||
ShowList = (searchable || shouldShowAllWhenEmpty) && !ShowNoData;
|
ShowList = (searchable || shouldShowAllWhenEmpty) && !ShowNoData;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
}
|
||||||
}, cts.Token);
|
}, cts.Token);
|
||||||
_searchCancellationTokenSource = cts;
|
_searchCancellationTokenSource = cts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Controls;
|
using Bit.App.Controls;
|
||||||
using Bit.Core.Resources.Localization;
|
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ namespace Bit.App.Pages
|
||||||
private readonly ICipherService _cipherService;
|
private readonly ICipherService _cipherService;
|
||||||
private readonly IDeviceActionService _deviceActionService;
|
private readonly IDeviceActionService _deviceActionService;
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
private readonly IPlatformUtilsService _platformUtilsService;
|
||||||
|
private readonly ILogger _logger;
|
||||||
private readonly GroupingsPageViewModel _vm;
|
private readonly GroupingsPageViewModel _vm;
|
||||||
private readonly string _pageName;
|
private readonly string _pageName;
|
||||||
|
|
||||||
|
@ -39,6 +40,8 @@ namespace Bit.App.Pages
|
||||||
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||||
|
_logger = ServiceContainer.Resolve<ILogger>();
|
||||||
|
|
||||||
_vm = BindingContext as GroupingsPageViewModel;
|
_vm = BindingContext as GroupingsPageViewModel;
|
||||||
_vm.Page = this;
|
_vm.Page = this;
|
||||||
_vm.MainPage = mainPage;
|
_vm.MainPage = mainPage;
|
||||||
|
@ -57,17 +60,14 @@ namespace Bit.App.Pages
|
||||||
_vm.VaultFilterDescription = vaultFilterSelection;
|
_vm.VaultFilterDescription = vaultFilterSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
#if IOS
|
||||||
{
|
|
||||||
_absLayout.Children.Remove(_fab);
|
_absLayout.Children.Remove(_fab);
|
||||||
ToolbarItems.Add(_addItem);
|
ToolbarItems.Add(_addItem);
|
||||||
}
|
#else
|
||||||
else
|
|
||||||
{
|
|
||||||
ToolbarItems.Add(_syncItem);
|
ToolbarItems.Add(_syncItem);
|
||||||
ToolbarItems.Add(_lockItem);
|
ToolbarItems.Add(_lockItem);
|
||||||
ToolbarItems.Add(_exitItem);
|
ToolbarItems.Add(_exitItem);
|
||||||
}
|
#endif
|
||||||
if (deleted || showTotp)
|
if (deleted || showTotp)
|
||||||
{
|
{
|
||||||
_absLayout.Children.Remove(_fab);
|
_absLayout.Children.Remove(_fab);
|
||||||
|
@ -80,6 +80,8 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async void OnAppearing()
|
protected override async void OnAppearing()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
if (_syncService.SyncInProgress)
|
if (_syncService.SyncInProgress)
|
||||||
|
@ -184,6 +186,12 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnBackButtonPressed()
|
protected override bool OnBackButtonPressed()
|
||||||
{
|
{
|
||||||
|
@ -195,7 +203,9 @@ namespace Bit.App.Pages
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async void OnDisappearing()
|
protected override void OnDisappearing()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
base.OnDisappearing();
|
base.OnDisappearing();
|
||||||
IsBusy = false;
|
IsBusy = false;
|
||||||
|
@ -204,6 +214,12 @@ namespace Bit.App.Pages
|
||||||
_vm.DisableRefreshing();
|
_vm.DisableRefreshing();
|
||||||
_accountAvatar?.OnDisappearing();
|
_accountAvatar?.OnDisappearing();
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
@ -263,6 +279,8 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Search_Clicked(object sender, EventArgs e)
|
private async void Search_Clicked(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await _accountListOverlay.HideAsync();
|
await _accountListOverlay.HideAsync();
|
||||||
if (DoOnce())
|
if (DoOnce())
|
||||||
|
@ -271,26 +289,54 @@ namespace Bit.App.Pages
|
||||||
await Navigation.PushModalAsync(new NavigationPage(page));
|
await Navigation.PushModalAsync(new NavigationPage(page));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void Sync_Clicked(object sender, EventArgs e)
|
private async void Sync_Clicked(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await _accountListOverlay.HideAsync();
|
await _accountListOverlay.HideAsync();
|
||||||
await _vm.SyncAsync();
|
await _vm.SyncAsync();
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void Lock_Clicked(object sender, EventArgs e)
|
private async void Lock_Clicked(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await _accountListOverlay.HideAsync();
|
await _accountListOverlay.HideAsync();
|
||||||
await _vaultTimeoutService.LockAsync(true, true);
|
await _vaultTimeoutService.LockAsync(true, true);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void Exit_Clicked(object sender, EventArgs e)
|
private async void Exit_Clicked(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await _accountListOverlay.HideAsync();
|
await _accountListOverlay.HideAsync();
|
||||||
await _vm.ExitAsync();
|
await _vm.ExitAsync();
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void AddButton_Clicked(object sender, EventArgs e)
|
private async void AddButton_Clicked(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var skipAction = _accountListOverlay.IsVisible && DeviceInfo.Platform == DevicePlatform.Android;
|
var skipAction = _accountListOverlay.IsVisible && DeviceInfo.Platform == DevicePlatform.Android;
|
||||||
await _accountListOverlay.HideAsync();
|
await _accountListOverlay.HideAsync();
|
||||||
|
@ -305,6 +351,11 @@ namespace Bit.App.Pages
|
||||||
await Navigation.PushModalAsync(new NavigationPage(page));
|
await Navigation.PushModalAsync(new NavigationPage(page));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ShowPreviousPageAsync()
|
private async Task ShowPreviousPageAsync()
|
||||||
{
|
{
|
||||||
|
|
|
@ -166,6 +166,9 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
var authed = await _stateService.IsAuthenticatedAsync();
|
var authed = await _stateService.IsAuthenticatedAsync();
|
||||||
if (!authed)
|
if (!authed)
|
||||||
{
|
{
|
||||||
|
@ -190,6 +193,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
PageTitle = ShowVaultFilter ? AppResources.Vaults : AppResources.MyVault;
|
PageTitle = ShowVaultFilter ? AppResources.Vaults : AppResources.MyVault;
|
||||||
}
|
}
|
||||||
|
|
||||||
_doingLoad = true;
|
_doingLoad = true;
|
||||||
LoadedOnce = true;
|
LoadedOnce = true;
|
||||||
ShowNoData = false;
|
ShowNoData = false;
|
||||||
|
@ -197,10 +201,17 @@ namespace Bit.App.Pages
|
||||||
ShowList = false;
|
ShowList = false;
|
||||||
ShowAddCipherButton = !Deleted;
|
ShowAddCipherButton = !Deleted;
|
||||||
|
|
||||||
|
_websiteIconsEnabled = await _stateService.GetDisableFaviconAsync() != true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
var groupedItems = new List<GroupingsPageListGroup>();
|
var groupedItems = new List<GroupingsPageListGroup>();
|
||||||
var page = Page as GroupingsPage;
|
var page = Page as GroupingsPage;
|
||||||
|
|
||||||
_websiteIconsEnabled = await _stateService.GetDisableFaviconAsync() != true;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LoadDataAsync();
|
await LoadDataAsync();
|
||||||
|
@ -307,11 +318,6 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
await MainThread.InvokeOnMainThreadAsync(() =>
|
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||||
{
|
{
|
||||||
#if IOS
|
|
||||||
// HACK: [PS-536] Fix to avoid blank list after back navigation on unlocking with previous page info
|
|
||||||
// because of update to XF v5.0.0.2401
|
|
||||||
GroupedItems.Clear();
|
|
||||||
#endif
|
|
||||||
GroupedItems.ReplaceRange(items);
|
GroupedItems.ReplaceRange(items);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -335,23 +341,22 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
await MainThread.InvokeOnMainThreadAsync(() =>
|
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||||
{
|
{
|
||||||
if (groupedItems.Any())
|
if (!groupedItems.Any())
|
||||||
{
|
{
|
||||||
#if IOS
|
|
||||||
// HACK: [PS-536] Fix to avoid blank list after back navigation on unlocking with previous page info
|
|
||||||
// because of update to XF v5.0.0.2401
|
|
||||||
GroupedItems.Clear();
|
GroupedItems.Clear();
|
||||||
#endif
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GroupedItems.ReplaceRange(new List<IGroupingsPageListItem> { new GroupingsPageHeaderListItem(groupedItems[0].Name, groupedItems[0].ItemCount) });
|
GroupedItems.ReplaceRange(new List<IGroupingsPageListItem> { new GroupingsPageHeaderListItem(groupedItems[0].Name, groupedItems[0].ItemCount) });
|
||||||
GroupedItems.AddRange(items);
|
GroupedItems.AddRange(items);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GroupedItems.Clear();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_doingLoad = false;
|
_doingLoad = false;
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
var cipher = await _cipherService.GetAsync(CipherId);
|
var cipher = await _cipherService.GetAsync(CipherId);
|
||||||
var decCipher = await cipher.DecryptAsync();
|
var decCipher = await cipher.DecryptAsync();
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
MainThread.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
History.ResetWithRange(decCipher.PasswordHistory ?? new List<PasswordHistoryView>());
|
History.ResetWithRange(decCipher.PasswordHistory ?? new List<PasswordHistoryView>());
|
||||||
ShowNoData = History.Count == 0;
|
ShowNoData = History.Count == 0;
|
||||||
|
|
|
@ -204,7 +204,18 @@ namespace Bit.iOS.Core.Controllers
|
||||||
var tasks = Task.Run(async () =>
|
var tasks = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
NSRunLoop.Main.BeginInvokeOnMainThread(async () => await PromptBiometricAsync());
|
NSRunLoop.Main.BeginInvokeOnMainThread(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await PromptBiometricAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace Bit.iOS.Core.Services
|
||||||
|
|
||||||
var dictArr = new NSDictionary<NSString, NSObject>[1];
|
var dictArr = new NSDictionary<NSString, NSObject>[1];
|
||||||
dictArr[0] = new NSDictionary<NSString, NSObject>(new NSString(UTType.UTF8PlainText), new NSString(text));
|
dictArr[0] = new NSDictionary<NSString, NSObject>(new NSString(UTType.UTF8PlainText), new NSString(text));
|
||||||
Device.BeginInvokeOnMainThread(() => UIPasteboard.General.SetItems(dictArr, new UIPasteboardOptions
|
MainThread.BeginInvokeOnMainThread(() => UIPasteboard.General.SetItems(dictArr, new UIPasteboardOptions
|
||||||
{
|
{
|
||||||
LocalOnly = true,
|
LocalOnly = true,
|
||||||
ExpirationDate = clearSeconds > 0 ? NSDate.FromTimeIntervalSinceNow(clearSeconds) : null
|
ExpirationDate = clearSeconds > 0 ? NSDate.FromTimeIntervalSinceNow(clearSeconds) : null
|
||||||
|
|
Loading…
Reference in a new issue