From df4d89cd52a92b2f049f2a1b5c4ef8cbb79530ce Mon Sep 17 00:00:00 2001 From: Federico Maccaroni Date: Tue, 14 Nov 2023 13:43:59 -0300 Subject: [PATCH] PM-3350 Fixed iOS Extensions navigation to several pages and improved avoiding duplicate calls to OnNavigatedTo --- .../Pages/Accounts/EnvironmentPage.xaml.cs | 17 ++--- src/Core/Pages/Accounts/HomePage.xaml.cs | 65 +++++++++---------- .../Accounts/LoginApproveDevicePage.xaml.cs | 15 ++--- src/Core/Pages/Accounts/LoginPage.xaml.cs | 10 +-- .../LoginPasswordlessRequestPage.xaml.cs | 24 +++---- .../LoginPasswordlessRequestViewModel.cs | 18 +---- src/Core/Pages/Accounts/LoginSsoPage.xaml.cs | 21 +----- src/Core/Pages/Accounts/RegisterPage.xaml.cs | 25 ++++--- .../Pages/Accounts/SetPasswordPage.xaml.cs | 24 +++---- src/Core/Pages/Accounts/TwoFactorPage.xaml.cs | 35 +++++----- .../Accounts/UpdateTempPasswordPage.xaml.cs | 20 +++--- src/Core/Pages/BaseContentPage.cs | 46 ++++++++++--- src/iOS.Extension/iOS.Extension.csproj | 4 -- 13 files changed, 145 insertions(+), 179 deletions(-) diff --git a/src/Core/Pages/Accounts/EnvironmentPage.xaml.cs b/src/Core/Pages/Accounts/EnvironmentPage.xaml.cs index 8a27e9af5..fb4a28d08 100644 --- a/src/Core/Pages/Accounts/EnvironmentPage.xaml.cs +++ b/src/Core/Pages/Accounts/EnvironmentPage.xaml.cs @@ -1,10 +1,6 @@ -using System; -using System.Threading.Tasks; +using Bit.Core.Abstractions; using Bit.Core.Resources.Localization; -using Bit.Core.Abstractions; using Bit.Core.Utilities; -using Microsoft.Maui.Controls; -using Microsoft.Maui; namespace Bit.App.Pages { @@ -19,11 +15,10 @@ namespace Bit.App.Pages InitializeComponent(); _vm = BindingContext as EnvironmentPageViewModel; _vm.Page = this; - // 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.Android) - { - ToolbarItems.RemoveAt(0); - } + +#if ANDROID + ToolbarItems.RemoveAt(0); +#endif _webVaultEntry.ReturnType = ReturnType.Next; _webVaultEntry.ReturnCommand = new Command(() => _apiEntry.Focus()); @@ -31,7 +26,7 @@ namespace Bit.App.Pages _apiEntry.ReturnCommand = new Command(() => _identityEntry.Focus()); _identityEntry.ReturnType = ReturnType.Next; _identityEntry.ReturnCommand = new Command(() => _iconsEntry.Focus()); - _vm.SubmitSuccessAction = () => Device.BeginInvokeOnMainThread(async () => await SubmitSuccessAsync()); + _vm.SubmitSuccessAction = () => MainThread.BeginInvokeOnMainThread(async () => await SubmitSuccessAsync()); _vm.CloseAction = async () => { await Navigation.PopModalAsync(); diff --git a/src/Core/Pages/Accounts/HomePage.xaml.cs b/src/Core/Pages/Accounts/HomePage.xaml.cs index 91d258781..05dcbb7cf 100644 --- a/src/Core/Pages/Accounts/HomePage.xaml.cs +++ b/src/Core/Pages/Accounts/HomePage.xaml.cs @@ -1,11 +1,7 @@ -using System; -using System.Threading.Tasks; -using Bit.App.Models; +using Bit.App.Models; using Bit.App.Utilities; using Bit.Core.Abstractions; using Bit.Core.Utilities; -using Microsoft.Maui.Controls; -using Microsoft.Maui; namespace Bit.App.Pages { @@ -20,16 +16,16 @@ namespace Bit.App.Pages public HomePage(AppOptions appOptions = null) { - _broadcasterService = ServiceContainer.Resolve("broadcasterService"); + _broadcasterService = ServiceContainer.Resolve(); _appOptions = appOptions; InitializeComponent(); _vm = BindingContext as HomeViewModel; _vm.Page = this; _vm.ShowCancelButton = _appOptions?.IosExtension ?? false; _vm.StartLoginAction = async () => await StartLoginAsync(); - _vm.StartRegisterAction = () => Device.BeginInvokeOnMainThread(async () => await StartRegisterAsync()); - _vm.StartSsoLoginAction = () => Device.BeginInvokeOnMainThread(async () => await StartSsoLoginAsync()); - _vm.StartEnvironmentAction = () => Device.BeginInvokeOnMainThread(async () => await StartEnvironmentAsync()); + _vm.StartRegisterAction = () => MainThread.BeginInvokeOnMainThread(async () => await StartRegisterAsync()); + _vm.StartSsoLoginAction = () => MainThread.BeginInvokeOnMainThread(async () => await StartSsoLoginAsync()); + _vm.StartEnvironmentAction = () => MainThread.BeginInvokeOnMainThread(async () => await StartEnvironmentAsync()); _vm.CloseAction = async () => { await _accountListOverlay.HideAsync(); @@ -53,28 +49,28 @@ namespace Bit.App.Pages await Navigation.PushModalAsync(new NavigationPage(new LoginPage(email, _appOptions))); } - protected override async void OnAppearing() + protected override async void OnNavigatedTo(NavigatedToEventArgs args) { - base.OnAppearing(); - _mainContent.Content = _mainLayout; - _accountAvatar?.OnAppearing(); + base.OnNavigatedTo(args); + + await MainThread.InvokeOnMainThreadAsync(() => _mainContent.Content = _mainLayout); - if (!_appOptions?.HideAccountSwitcher ?? false) - { - _vm.AvatarImageSource = await GetAvatarImageSourceAsync(false); - } - _broadcasterService.Subscribe(nameof(HomePage), (message) => - { - if (message.Command is ThemeManager.UPDATED_THEME_MESSAGE_KEY) - { - Device.BeginInvokeOnMainThread(() => - { - UpdateLogo(); - }); - } - }); try { + _accountAvatar?.OnAppearing(); + + if (!_appOptions?.HideAccountSwitcher ?? false) + { + await MainThread.InvokeOnMainThreadAsync(async () => _vm.AvatarImageSource = await GetAvatarImageSourceAsync(false)); + } + _broadcasterService.Subscribe(nameof(HomePage), (message) => + { + if (message.Command is ThemeManager.UPDATED_THEME_MESSAGE_KEY) + { + MainThread.BeginInvokeOnMainThread(UpdateLogo); + } + }); + await _vm.UpdateEnvironment(); } catch (Exception ex) @@ -83,6 +79,14 @@ namespace Bit.App.Pages } } + protected override void OnNavigatingFrom(NavigatingFromEventArgs args) + { + base.OnNavigatingFrom(args); + + _broadcasterService?.Unsubscribe(nameof(HomePage)); + _accountAvatar?.OnDisappearing(); + } + protected override bool OnBackButtonPressed() { if (_accountListOverlay.IsVisible) @@ -93,13 +97,6 @@ namespace Bit.App.Pages return false; } - protected override void OnDisappearing() - { - base.OnDisappearing(); - _broadcasterService.Unsubscribe(nameof(HomePage)); - _accountAvatar?.OnDisappearing(); - } - private void UpdateLogo() { _logo.Source = !ThemeManager.UsingLightTheme ? "logo_white.png" : "logo.png"; diff --git a/src/Core/Pages/Accounts/LoginApproveDevicePage.xaml.cs b/src/Core/Pages/Accounts/LoginApproveDevicePage.xaml.cs index f1de9187b..ea8eb015f 100644 --- a/src/Core/Pages/Accounts/LoginApproveDevicePage.xaml.cs +++ b/src/Core/Pages/Accounts/LoginApproveDevicePage.xaml.cs @@ -1,18 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Bit.App.Models; +using Bit.App.Models; using Bit.App.Utilities; using Bit.Core.Enums; using Bit.Core.Utilities; -using Microsoft.Maui.Controls; -using Microsoft.Maui; namespace Bit.App.Pages { public partial class LoginApproveDevicePage : BaseContentPage { - private readonly LoginApproveDeviceViewModel _vm; private readonly AppOptions _appOptions; @@ -28,9 +22,11 @@ namespace Bit.App.Pages _appOptions = appOptions; } - protected override void OnAppearing() + protected override bool ShouldCheckToPreventOnNavigatedToCalledTwice => true; + + protected override async Task InitOnNavigatedToAsync() { - _vm.InitAsync(); + await _vm.InitAsync(); } private async Task ContinueToVaultAsync() @@ -62,4 +58,3 @@ namespace Bit.App.Pages } } } - diff --git a/src/Core/Pages/Accounts/LoginPage.xaml.cs b/src/Core/Pages/Accounts/LoginPage.xaml.cs index 1f8c6ff67..82125add3 100644 --- a/src/Core/Pages/Accounts/LoginPage.xaml.cs +++ b/src/Core/Pages/Accounts/LoginPage.xaml.cs @@ -64,16 +64,12 @@ namespace Bit.App.Pages } } + protected override bool ShouldCheckToPreventOnNavigatedToCalledTwice => true; + public Entry MasterPasswordEntry { get; set; } - protected override async void OnNavigatedTo(NavigatedToEventArgs args) + protected override async Task InitOnNavigatedToAsync() { - base.OnNavigatedTo(args); - - //IsInitialized is used as a workaround to avoid duplicate initialization issues because of OnNavigatedTo being called twice. - if (HasInitialized) { return; } - HasInitialized = true; - _broadcasterService.Subscribe(nameof(LoginPage), message => { if (message.Command == Constants.ClearSensitiveFields) diff --git a/src/Core/Pages/Accounts/LoginPasswordlessRequestPage.xaml.cs b/src/Core/Pages/Accounts/LoginPasswordlessRequestPage.xaml.cs index dd7eb9691..ddc7addbc 100644 --- a/src/Core/Pages/Accounts/LoginPasswordlessRequestPage.xaml.cs +++ b/src/Core/Pages/Accounts/LoginPasswordlessRequestPage.xaml.cs @@ -1,11 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Bit.App.Models; +using Bit.App.Models; using Bit.App.Utilities; using Bit.Core.Enums; -using Microsoft.Maui.Controls; -using Microsoft.Maui; namespace Bit.App.Pages { @@ -23,23 +18,25 @@ namespace Bit.App.Pages _vm.Email = email; _vm.AuthRequestType = authRequestType; _vm.AuthingWithSso = authingWithSso; - _vm.StartTwoFactorAction = () => Device.BeginInvokeOnMainThread(async () => await StartTwoFactorAsync()); - _vm.LogInSuccessAction = () => Device.BeginInvokeOnMainThread(async () => await LogInSuccessAsync()); - _vm.UpdateTempPasswordAction = () => Device.BeginInvokeOnMainThread(async () => await UpdateTempPasswordAsync()); + _vm.StartTwoFactorAction = () => MainThread.BeginInvokeOnMainThread(async () => await StartTwoFactorAsync()); + _vm.LogInSuccessAction = () => MainThread.BeginInvokeOnMainThread(async () => await LogInSuccessAsync()); + _vm.UpdateTempPasswordAction = () => MainThread.BeginInvokeOnMainThread(async () => await UpdateTempPasswordAsync()); _vm.CloseAction = () => { Navigation.PopModalAsync(); }; _vm.CreatePasswordlessLoginCommand.Execute(null); } - protected override void OnAppearing() + protected override bool ShouldCheckToPreventOnNavigatedToCalledTwice => true; + + protected override Task InitOnNavigatedToAsync() { - base.OnAppearing(); _vm.StartCheckLoginRequestStatus(); + return Task.CompletedTask; } - protected override void OnDisappearing() + protected override void OnNavigatedFrom(NavigatedFromEventArgs args) { - base.OnDisappearing(); + base.OnNavigatedFrom(args); _vm.StopCheckLoginRequestStatus(); } @@ -66,4 +63,3 @@ namespace Bit.App.Pages } } } - diff --git a/src/Core/Pages/Accounts/LoginPasswordlessRequestViewModel.cs b/src/Core/Pages/Accounts/LoginPasswordlessRequestViewModel.cs index b1366224f..ab96ebde1 100644 --- a/src/Core/Pages/Accounts/LoginPasswordlessRequestViewModel.cs +++ b/src/Core/Pages/Accounts/LoginPasswordlessRequestViewModel.cs @@ -1,26 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Text; -using System.Threading; -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; using Bit.Core.Abstractions; using Bit.Core.Enums; using Bit.Core.Exceptions; using Bit.Core.Models.Domain; using Bit.Core.Models.Response; -using Bit.Core.Services; +using Bit.Core.Resources.Localization; using Bit.Core.Utilities; -using Microsoft.Maui.Controls; -using Microsoft.Maui; - namespace Bit.App.Pages { public class LoginPasswordlessRequestViewModel : CaptchaProtectedViewModel @@ -72,7 +60,7 @@ namespace Bit.App.Pages onException: ex => HandleException(ex), allowsMultipleExecutions: false); - CloseCommand = new AsyncCommand(() => Device.InvokeOnMainThreadAsync(CloseAction), + CloseCommand = new AsyncCommand(() => MainThread.InvokeOnMainThreadAsync(CloseAction), onException: _logger.Exception, allowsMultipleExecutions: false); } diff --git a/src/Core/Pages/Accounts/LoginSsoPage.xaml.cs b/src/Core/Pages/Accounts/LoginSsoPage.xaml.cs index 20bcdeb2a..ad05b5a25 100644 --- a/src/Core/Pages/Accounts/LoginSsoPage.xaml.cs +++ b/src/Core/Pages/Accounts/LoginSsoPage.xaml.cs @@ -39,25 +39,10 @@ namespace Bit.App.Pages } } - protected override async void OnNavigatedTo(NavigatedToEventArgs args) + protected override bool ShouldCheckToPreventOnNavigatedToCalledTwice => true; + + protected override async Task InitOnNavigatedToAsync() { - base.OnNavigatedTo(args); - - //IsInitialized is used as a workaround to avoid duplicate initialization issues because of OnNavigatedTo being called twice. - if (HasInitialized) { return; } - HasInitialized = true; - - await _vm.InitAsync(); - if (string.IsNullOrWhiteSpace(_vm.OrgIdentifier)) - { - RequestFocus(_orgIdentifier); - } - } - - protected override async void OnNavigatedFrom(NavigatedFromEventArgs args) - { - base.OnNavigatedFrom(args); - await _vm.InitAsync(); if (string.IsNullOrWhiteSpace(_vm.OrgIdentifier)) { diff --git a/src/Core/Pages/Accounts/RegisterPage.xaml.cs b/src/Core/Pages/Accounts/RegisterPage.xaml.cs index 2cc4ff366..d1b273031 100644 --- a/src/Core/Pages/Accounts/RegisterPage.xaml.cs +++ b/src/Core/Pages/Accounts/RegisterPage.xaml.cs @@ -1,9 +1,4 @@ -using System; -using System.Threading.Tasks; -using Microsoft.Maui.Controls; -using Microsoft.Maui; - -namespace Bit.App.Pages +namespace Bit.App.Pages { public partial class RegisterPage : BaseContentPage { @@ -16,18 +11,17 @@ namespace Bit.App.Pages InitializeComponent(); _vm = BindingContext as RegisterPageViewModel; _vm.Page = this; - _vm.RegistrationSuccess = () => Device.BeginInvokeOnMainThread(async () => await RegistrationSuccessAsync(homePage)); + _vm.RegistrationSuccess = () => MainThread.BeginInvokeOnMainThread(async () => await RegistrationSuccessAsync(homePage)); _vm.CloseAction = async () => { await Navigation.PopModalAsync(); }; MasterPasswordEntry = _masterPassword; ConfirmMasterPasswordEntry = _confirmMasterPassword; - // 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.Android) - { - ToolbarItems.RemoveAt(0); - } + +#if ANDROID + ToolbarItems.RemoveAt(0); +#endif _email.ReturnType = ReturnType.Next; _email.ReturnCommand = new Command(() => _masterPassword.Focus()); @@ -40,14 +34,17 @@ namespace Bit.App.Pages public Entry MasterPasswordEntry { get; set; } public Entry ConfirmMasterPasswordEntry { get; set; } - protected override void OnAppearing() + protected override bool ShouldCheckToPreventOnNavigatedToCalledTwice => true; + + protected override Task InitOnNavigatedToAsync() { - base.OnAppearing(); if (!_inputFocused) { RequestFocus(_email); _inputFocused = true; } + + return Task.CompletedTask; } private async void Submit_Clicked(object sender, EventArgs e) diff --git a/src/Core/Pages/Accounts/SetPasswordPage.xaml.cs b/src/Core/Pages/Accounts/SetPasswordPage.xaml.cs index 50d194eb6..3fdf38f8e 100644 --- a/src/Core/Pages/Accounts/SetPasswordPage.xaml.cs +++ b/src/Core/Pages/Accounts/SetPasswordPage.xaml.cs @@ -1,9 +1,5 @@ -using System; -using System.Threading.Tasks; -using Bit.App.Models; +using Bit.App.Models; using Bit.App.Utilities; -using Microsoft.Maui.Controls; -using Microsoft.Maui; namespace Bit.App.Pages { @@ -19,17 +15,16 @@ namespace Bit.App.Pages _vm = BindingContext as SetPasswordPageViewModel; _vm.Page = this; _vm.SetPasswordSuccessAction = - () => Device.BeginInvokeOnMainThread(async () => await SetPasswordSuccessAsync()); + () => MainThread.BeginInvokeOnMainThread(async () => await SetPasswordSuccessAsync()); _vm.CloseAction = async () => { await Navigation.PopModalAsync(); }; _vm.OrgIdentifier = orgIdentifier; - // 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.Android) - { - ToolbarItems.RemoveAt(0); - } + +#if ANDROID + ToolbarItems.RemoveAt(0); +#endif MasterPasswordEntry = _masterPassword; ConfirmMasterPasswordEntry = _confirmMasterPassword; @@ -43,9 +38,10 @@ namespace Bit.App.Pages public Entry MasterPasswordEntry { get; set; } public Entry ConfirmMasterPasswordEntry { get; set; } - protected override async void OnAppearing() + protected override bool ShouldCheckToPreventOnNavigatedToCalledTwice => true; + + protected override async Task InitOnNavigatedToAsync() { - base.OnAppearing(); await _vm.InitAsync(); RequestFocus(_masterPassword); } @@ -58,7 +54,7 @@ namespace Bit.App.Pages } } - private async void Close_Clicked(object sender, EventArgs e) + private void Close_Clicked(object sender, EventArgs e) { if (DoOnce()) { diff --git a/src/Core/Pages/Accounts/TwoFactorPage.xaml.cs b/src/Core/Pages/Accounts/TwoFactorPage.xaml.cs index 1dd59a971..ee92ca538 100644 --- a/src/Core/Pages/Accounts/TwoFactorPage.xaml.cs +++ b/src/Core/Pages/Accounts/TwoFactorPage.xaml.cs @@ -22,8 +22,8 @@ namespace Bit.App.Pages SetActivityIndicator(); _appOptions = appOptions; _orgIdentifier = orgIdentifier; - _broadcasterService = ServiceContainer.Resolve("broadcasterService"); - _messagingService = ServiceContainer.Resolve("messagingService"); + _broadcasterService = ServiceContainer.Resolve(); + _messagingService = ServiceContainer.Resolve(); _vm = BindingContext as TwoFactorPageViewModel; _vm.Page = this; _vm.AuthingWithSso = authingWithSso ?? false; @@ -40,25 +40,21 @@ namespace Bit.App.Pages _vm.CloseAction = async () => await Navigation.PopModalAsync(); DuoWebView = _duoWebView; - if (DeviceInfo.Platform == DevicePlatform.Android) - { - ToolbarItems.Remove(_cancelItem); - } - if (DeviceInfo.Platform == DevicePlatform.iOS) - { - ToolbarItems.Add(_moreItem); - } - else - { - ToolbarItems.Add(_useAnotherTwoStepMethod); - } +#if ANDROID + ToolbarItems.Remove(_cancelItem); + ToolbarItems.Add(_useAnotherTwoStepMethod); +#else + + ToolbarItems.Add(_moreItem); +#endif } public HybridWebView DuoWebView { get; set; } - protected override async void OnAppearing() + protected override bool ShouldCheckToPreventOnNavigatedToCalledTwice => true; + + protected override async Task InitOnNavigatedToAsync() { - base.OnAppearing(); _broadcasterService.Subscribe(nameof(TwoFactorPage), (message) => { if (message.Command == "gotYubiKeyOTP") @@ -101,10 +97,11 @@ namespace Bit.App.Pages return Task.FromResult(0); }); } - - protected override void OnDisappearing() + + protected override void OnNavigatedFrom(NavigatedFromEventArgs args) { - base.OnDisappearing(); + base.OnNavigatedFrom(args); + if (!_vm.YubikeyMethod) { _messagingService.Send("listenYubiKeyOTP", false); diff --git a/src/Core/Pages/Accounts/UpdateTempPasswordPage.xaml.cs b/src/Core/Pages/Accounts/UpdateTempPasswordPage.xaml.cs index 4a11670e4..fa314ffe1 100644 --- a/src/Core/Pages/Accounts/UpdateTempPasswordPage.xaml.cs +++ b/src/Core/Pages/Accounts/UpdateTempPasswordPage.xaml.cs @@ -1,9 +1,6 @@ -using System; +using Bit.Core.Abstractions; using Bit.Core.Resources.Localization; -using Bit.Core.Abstractions; using Bit.Core.Utilities; -using Microsoft.Maui.Controls; -using Microsoft.Maui; namespace Bit.App.Pages { @@ -17,8 +14,8 @@ namespace Bit.App.Pages public UpdateTempPasswordPage() { // Service Init - _messagingService = ServiceContainer.Resolve("messagingService"); - _platformUtilsService = ServiceContainer.Resolve("platformUtilsService"); + _messagingService = ServiceContainer.Resolve(); + _platformUtilsService = ServiceContainer.Resolve(); // Binding InitializeComponent(); @@ -30,9 +27,9 @@ namespace Bit.App.Pages // Actions Declaration _vm.LogOutAction = () => { - _messagingService.Send("logout"); + _messagingService.Send(AccountsManagerMessageCommands.LOGOUT); }; - _vm.UpdateTempPasswordSuccessAction = () => Device.BeginInvokeOnMainThread(UpdateTempPasswordSuccess); + _vm.UpdateTempPasswordSuccessAction = () => MainThread.BeginInvokeOnMainThread(UpdateTempPasswordSuccess); // Link fields that will be referenced in codebehind MasterPasswordEntry = _masterPassword; @@ -48,9 +45,10 @@ namespace Bit.App.Pages public Entry MasterPasswordEntry { get; set; } public Entry ConfirmMasterPasswordEntry { get; set; } - protected override async void OnAppearing() + protected override bool ShouldCheckToPreventOnNavigatedToCalledTwice => true; + + protected override async Task InitOnNavigatedToAsync() { - base.OnAppearing(); await LoadOnAppearedAsync(_mainLayout, true, async () => { await _vm.InitAsync(true); @@ -81,7 +79,7 @@ namespace Bit.App.Pages private void UpdateTempPasswordSuccess() { - _messagingService.Send("logout"); + _messagingService.Send(AccountsManagerMessageCommands.LOGOUT); } } } diff --git a/src/Core/Pages/BaseContentPage.cs b/src/Core/Pages/BaseContentPage.cs index 4fed7a050..fcb1ca1f9 100644 --- a/src/Core/Pages/BaseContentPage.cs +++ b/src/Core/Pages/BaseContentPage.cs @@ -3,8 +3,10 @@ using Bit.App.Controls; using Bit.App.Utilities; using Bit.Core.Abstractions; using Bit.Core.Utilities; +#if IOS using Microsoft.Maui.Controls.PlatformConfiguration; using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific; +#endif namespace Bit.App.Pages { @@ -16,22 +18,34 @@ namespace Bit.App.Pages protected int ShowModalAnimationDelay = 400; protected int ShowPageAnimationDelay = 100; + /// + /// Used as a workaround to avoid duplicate initialization issues for some pages where OnNavigatedTo is called twice. + /// + private bool _hasInitedOnNavigatedTo; + public BaseContentPage() { - if (DeviceInfo.Platform == DevicePlatform.iOS) - { - On().SetUseSafeArea(true); - On().SetModalPresentationStyle(UIModalPresentationStyle.FullScreen); - } +#if IOS + On().SetUseSafeArea(true); + On().SetModalPresentationStyle(UIModalPresentationStyle.FullScreen); +#endif } - //IsInitialized is used as a workaround to avoid duplicate initialization issues for some pages where OnNavigatedTo is called twice. - protected bool HasInitialized { get; set; } - public DateTime? LastPageAction { get; set; } public bool IsThemeDirty { get; set; } + /// + /// This flag is used to see if check is needed to avoid duplicate calls of + /// Usually on modal navigation to the current page this flag should be true + /// Also this flag is added instead of directly checking for all pages to avoid potential issues on the app + /// and focusing only on the places where it's actually needed. + /// + /// + /// This should be removed once MAUI fixes the issue of duplicate call to the method. + /// + protected virtual bool ShouldCheckToPreventOnNavigatedToCalledTwice => false; + protected override async void OnNavigatedTo(NavigatedToEventArgs args) { base.OnNavigatedTo(args); @@ -42,6 +56,22 @@ namespace Bit.App.Pages } await SaveActivityAsync(); + + if (ShouldCheckToPreventOnNavigatedToCalledTwice && _hasInitedOnNavigatedTo) + { + return; + } + _hasInitedOnNavigatedTo = true; + + await InitOnNavigatedToAsync(); + } + + protected virtual Task InitOnNavigatedToAsync() => Task.CompletedTask; + + protected override void OnNavigatedFrom(NavigatedFromEventArgs args) + { + base.OnNavigatedFrom(args); + _hasInitedOnNavigatedTo = false; } public bool DoOnce(Action action = null, int milliseconds = 1000) diff --git a/src/iOS.Extension/iOS.Extension.csproj b/src/iOS.Extension/iOS.Extension.csproj index 5ea6323d1..4fa82679e 100644 --- a/src/iOS.Extension/iOS.Extension.csproj +++ b/src/iOS.Extension/iOS.Extension.csproj @@ -73,10 +73,6 @@ - - - TestViewController.cs -