diff --git a/maui/src/Popup/Helpers/PopupExtension/PopupExtension.Android.cs b/maui/src/Popup/Helpers/PopupExtension/PopupExtension.Android.cs index 241c73a0..7192624b 100644 --- a/maui/src/Popup/Helpers/PopupExtension/PopupExtension.Android.cs +++ b/maui/src/Popup/Helpers/PopupExtension/PopupExtension.Android.cs @@ -120,12 +120,12 @@ internal static int GetLocationInApp(VisualElement virtualView) { int[] decorCoordinates = new int[2] { 0, 0 }; decorView.GetLocationInWindow(decorCoordinates); - return (int)Math.Round((viewCoordinates[1] - decorCoordinates[1]) / WindowOverlayHelper._density); + return Math.Max((int)Math.Round((viewCoordinates[1] - decorCoordinates[1]) / WindowOverlayHelper._density), 0); } } else { - return (int)Math.Round((viewCoordinates[1] - GetWindowInsets("Top")) / WindowOverlayHelper._density); + return Math.Max((int)Math.Round((viewCoordinates[1] - GetWindowInsets("Top")) / WindowOverlayHelper._density), 0); } } @@ -148,7 +148,12 @@ internal static int GetScreenWidth() return widthPixel; } - return (int)Math.Round(platformRootView!.Width / WindowOverlayHelper._density); + int leftInsets = 0; +#if NET10_0 + // In .NET 10, the root view’s width in landscape includes the navigation bar, so subtract the left window inset from the root view width to get the usable content width. + leftInsets = PopupExtension.GetWindowInsets("Left"); +#endif + return (int)Math.Round((platformRootView!.Width - leftInsets) / WindowOverlayHelper._density); } /// @@ -169,13 +174,24 @@ internal static int GetScreenHeight() } else if (platformRootView is not null) { + int topInsets = 0; + int bottomInsets = 0; +#if NET10_0 + // In .NET 10, the root view’s height includes the navigation bar, so subtract the bottom window inset from the root view height to get the usable content height. + bottomInsets = PopupExtension.GetWindowInsets("Bottom"); + if (!WindowFlagHasFullScreen) + { + topInsets = PopupExtension.GetWindowInsets("Top"); + } +#endif + if (IsResizeMode() && !WindowFlagHasNoLimits) { platformRootViewHeight = platformRootView.Height + (GetKeyboardHeight() * WindowOverlayHelper._density); } else { - platformRootViewHeight = platformRootView.Height; + platformRootViewHeight = platformRootView.Height - topInsets - bottomInsets; } return (int)Math.Round(platformRootViewHeight / WindowOverlayHelper._density); @@ -239,15 +255,30 @@ internal static int GetWindowInsets(string position) var windowInsets = ViewCompat.GetRootWindowInsets(WindowOverlayHelper._decorViewContent); if (windowInsets is not null) { +#pragma warning disable CS8602 // Dereference of a possibly null reference. var insets = windowInsets.GetInsets(WindowInsetsCompat.Type.SystemBars()); switch (position) { case "Bottom": return insets.Bottom; case "Top": - return insets.Top; + { +#if NET10_0 + // In .NET 10 case, fall back to decorViewFrame when Top inset is 0. + return insets.Top == 0 ? (int)Math.Round((WindowOverlayHelper._decorViewFrame?.Top ?? 0f) / WindowOverlayHelper._density) : insets.Top; +#else + return insets.Top; +#endif + } case "Left": - return insets.Left; + { +#if NET10_0 + // In .NET 10 case, fall back to decorViewFrame when Left inset is 0. + return insets.Left == 0 ? (int)Math.Round((WindowOverlayHelper._decorViewFrame?.Left ?? 0f) / WindowOverlayHelper._density) : insets.Left; +#else + return insets.Left; +#endif + } case "Right": return insets.Right; case "Keyboard": @@ -259,6 +290,8 @@ internal static int GetWindowInsets(string position) default: return 0; } +#pragma warning restore CS8602 + } } diff --git a/maui/src/Popup/Helpers/PopupExtension/PopupExtension.iOS.cs b/maui/src/Popup/Helpers/PopupExtension/PopupExtension.iOS.cs index 41cfc492..e6360e13 100644 --- a/maui/src/Popup/Helpers/PopupExtension/PopupExtension.iOS.cs +++ b/maui/src/Popup/Helpers/PopupExtension/PopupExtension.iOS.cs @@ -120,10 +120,28 @@ internal static int GetActionBarHeight() internal static int GetSafeAreaHeight(string position) { // The popup is drawn within the safe area when shown relative to a view. Safe area calculations apply only to the iOS X simulator on iOS. +#pragma warning disable CS0618 // Suppressing CS0618 warning because Page.GetUseSafeArea is marked obsolete in .NET 10. if (Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.Page.GetUseSafeArea(GetMainPage())) +#pragma warning restore CS0618 { var platformWindow = WindowOverlayHelper._window?.ToPlatform() as UIWindow; - var statusBarOrientation = platformWindow?.WindowScene?.InterfaceOrientation; + UIInterfaceOrientation? statusBarOrientation = null; + var scene = platformWindow?.WindowScene; + if (scene != null) + { +#if IOS || MACCATALYST + if (OperatingSystem.IsIOSVersionAtLeast(16, 0) || OperatingSystem.IsMacCatalystVersionAtLeast(16, 0)) + { + statusBarOrientation = scene.EffectiveGeometry.InterfaceOrientation; + } + else + { +#pragma warning disable CA1422 // InterfaceOrientation is obsoleted on newer SDKs; guarded by OS version checks + statusBarOrientation = scene.InterfaceOrientation; +#pragma warning restore CA1422 + } +#endif + } // Since StatusBarHeight is already calculated, the top safe area does not need to be computed. if (position == "Top") diff --git a/maui/src/Popup/PopupFooter.cs b/maui/src/Popup/PopupFooter.cs index bbb83f21..4f826896 100644 --- a/maui/src/Popup/PopupFooter.cs +++ b/maui/src/Popup/PopupFooter.cs @@ -83,7 +83,9 @@ public PopupFooter(PopupView popupView) { #if IOS // The value for the IgnoreSafeArea property is being set by retrieving the safe area value from the main page. +#pragma warning disable CS0618 // Suppressing CS0618 warning because Page.GetUseSafeArea is marked obsolete in .NET 10. IgnoreSafeArea = !Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.Page.GetUseSafeArea(PopupExtension.GetMainPage()); +#pragma warning restore CS0618 #endif _popupView = popupView; Initialize(); @@ -194,7 +196,9 @@ void AddChildViews() if (footerView is not null) { // The value for the IgnoreSafeArea property is being set by retrieving the safe area value from the main page. +#pragma warning disable CS0618 // Suppressing CS0618 warning because Layout.IgnoreSafeArea is marked obsolete in .NET 10. footerView.IgnoreSafeArea = IgnoreSafeArea; +#pragma warning restore CS0618 if (_popupView._popup.FooterTemplate is null) { if (_popupView._popup.AppearanceMode == PopupButtonAppearanceMode.OneButton) diff --git a/maui/src/Popup/PopupHeader.cs b/maui/src/Popup/PopupHeader.cs index 5c85cd4d..1f518879 100644 --- a/maui/src/Popup/PopupHeader.cs +++ b/maui/src/Popup/PopupHeader.cs @@ -68,7 +68,9 @@ public PopupHeader(PopupView popup) { #if IOS // When Page SafeArea is false, close icon overlaps header,because HeaderView arranging with safeArea. +#pragma warning disable CS0618 // Suppressing CS0618 warning because Page.GetUseSafeArea is marked obsolete in .NET 10. IgnoreSafeArea = !Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.Page.GetUseSafeArea(PopupExtension.GetMainPage()); +#pragma warning restore CS0618 #endif _popupView = popup; Initialize(); @@ -149,7 +151,9 @@ void AddChildViews() if (headerView is not null) { // The value for the IgnoreSafeArea property is being set by retrieving the safe area value from the main page. +#pragma warning disable CS0618 // Suppressing CS0618 warning because Layout.IgnoreSafeArea is marked obsolete in .NET 10. headerView.IgnoreSafeArea = IgnoreSafeArea; +#pragma warning restore CS0618 bool isFullScreen = _popupView._popup.CanShowPopupInFullScreen; if (isFullScreen) { diff --git a/maui/src/Popup/PopupMessageView.cs b/maui/src/Popup/PopupMessageView.cs index 67e4de4d..3e8a54f7 100644 --- a/maui/src/Popup/PopupMessageView.cs +++ b/maui/src/Popup/PopupMessageView.cs @@ -60,7 +60,9 @@ public PopupMessageView(PopupView popupView) { #if IOS // The value for the IgnoreSafeArea property is being set by retrieving the safe area value from the main page. +#pragma warning disable CS0618 // Suppressing CS0618 warning because Page.GetUseSafeArea is marked obsolete in .NET 10. IgnoreSafeArea = !Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.Page.GetUseSafeArea(PopupExtension.GetMainPage()); +#pragma warning restore CS0618 #endif _popupView = popupView; Initialize(); diff --git a/maui/src/Popup/SfPopup/SfPopup.Windows.cs b/maui/src/Popup/SfPopup/SfPopup.Windows.cs index ae458fbe..938cfb4e 100644 --- a/maui/src/Popup/SfPopup/SfPopup.Windows.cs +++ b/maui/src/Popup/SfPopup/SfPopup.Windows.cs @@ -228,9 +228,8 @@ async void OnPlatformWindowSizeChanged(object sender, WindowSizeChangedEventArgs // Abort the PopupView animation when the window size changes. AbortPopupViewAnimation(); ResetAnimatedProperties(); - ResetPopupWidthHeight(); - SyncPopupDimensionFields(); + ResetPopupWidthHeight(); // Need to update the effect visual size, when the window is resized or the orientation changes. if (IsOpen && ShowOverlayAlways && OverlayMode is PopupOverlayMode.Blur) diff --git a/maui/src/Popup/SfPopup/SfPopup.cs b/maui/src/Popup/SfPopup/SfPopup.cs index f0e4a24d..a90efc70 100644 --- a/maui/src/Popup/SfPopup/SfPopup.cs +++ b/maui/src/Popup/SfPopup/SfPopup.cs @@ -347,7 +347,7 @@ public partial class SfPopup : SfView, IParentThemeElement /// /// Identifies the Padding bindable property. /// - public static readonly BindableProperty PaddingProperty = + public static new readonly BindableProperty PaddingProperty = BindableProperty.Create("Padding", typeof(Thickness), typeof(SfPopup), new Thickness(0.0), BindingMode.Default, propertyChanged: OnPaddingPropertyChanged); /// @@ -1734,7 +1734,8 @@ public void ShowRelativeToView(View relativeView, PopupRelativePosition relative /// public void Dismiss() { - if (IsOpen && !StaysOpen) + // Maui:990257 When Dismiss() is called, the popup should close regardless of whether the StaysOpen property is set to true. + if (IsOpen) { OpenOrClosePopup(false); } @@ -2102,8 +2103,12 @@ void RaisePopupEvent() /// void DisplayPopup() { - if (_popupView is null) + // 989436 : [Android] Popup is not shown when IsOpen is set in XAML or constructor at loading with a Shell page. + // In Android, the Shell page is not loaded initially, so the popup is displayed only after the Shell page has loaded. + if (_popupView == null || (PopupExtension.GetMainWindowPage() is Shell shellPage && !shellPage.IsLoaded)) { + _isOpenDeferred = true; + WireEvents(); return; } #if ANDROID @@ -2775,8 +2780,13 @@ void WireEvents() if (windowPage.Navigation.ModalStack.LastOrDefault() is not null) { // LayoutChanged only wired for Modal page. Since when Popup is opened OnAppearing of Modal page height and width is not update in native level. - page.LayoutChanged -= OnPageLayoutChanged; - page.LayoutChanged += OnPageLayoutChanged; +#if NET10_0 + page.SizeChanged -= this.OnPageSizeChanged; + page.SizeChanged += this.OnPageSizeChanged; +#else + page.SizeChanged -= this.OnPageLayoutChanged; + page.SizeChanged += this.OnPageLayoutChanged; +#endif } #else // while calling show() from onAppearing, page.window is not null. So fails the first condition and hook the onMainPageLoaded. @@ -2836,6 +2846,23 @@ void OnApplicationPageAppearing(object? sender, Page e) WireEvents(); } + /// + /// Raise when the current page size has changed. + /// + /// Represents current Page. + /// Corresponding property changed event args. + private void OnPageSizeChanged(object? sender, EventArgs e) + { + this.InitializeOverlay(); + this.CheckAndOpenDeferredPopup(); + + // Here need to unwire the LayoutChanged. If not, this will cause issue when resizing the windows with Popup.IsOpen false. + if (sender is Page page) + { + page.SizeChanged -= this.OnPageSizeChanged; + } + } + /// /// Raise when the current page layout has changed. /// @@ -2849,7 +2876,11 @@ void OnPageLayoutChanged(object? sender, EventArgs e) // Unwire the LayoutChanged to avoid issues when resizing the window with Popup.IsOpen set to false. if (sender is Page page) { - page.LayoutChanged -= OnPageLayoutChanged; +#if NET10_0 + page.SizeChanged -= this.OnPageSizeChanged; +#else + page.LayoutChanged -= this.OnPageLayoutChanged; +#endif } } @@ -3485,12 +3516,19 @@ protected override void OnHandlerChanged() if (Handler is null && _popupOverlay is not null) { _popupOverlay.Dispose(); + _popupOverlay = null; } if (!_isOverlayAdded && Handler != null) { InitializeOverlay(); - } + + // 989436: Popup is not shown when IsOpen is set in XAML or in the constructor during loading with a direct page. So, the popup needs to be displayed when it is still not shown from OnIsOpenChanged. + if (_isOverlayAdded) + { + CheckAndOpenDeferredPopup(); + } + } base.OnHandlerChanged(); } @@ -3771,6 +3809,10 @@ static void OnShowHeaderPropertyChanged(BindableObject bindable, object oldValue if (popup._popupView.Contains(popup._popupView._headerView)) { popup._popupView.Remove(popup._popupView._headerView); + if (popup._popupView._headerView.Handler is not null) + { + popup._popupView._headerView.Handler.DisconnectHandler(); + } } } } diff --git a/maui/src/Popup/SfPopup/SfPopup.iOS.cs b/maui/src/Popup/SfPopup/SfPopup.iOS.cs index fe19dbe9..60825baa 100644 --- a/maui/src/Popup/SfPopup/SfPopup.iOS.cs +++ b/maui/src/Popup/SfPopup/SfPopup.iOS.cs @@ -58,11 +58,16 @@ internal void WirePlatformSpecificEvents() if (ModalPage is not null) { // Wired the size change event for the Modal page when a popup is opened from it. - ModalPage.SizeChanged += OnMainPageSizeChanged; + ModalPage.SizeChanged += this.OnMainPageSizeChanged; + } + else if (windowPage is Shell shellPage && shellPage.CurrentPage != null) + { + // Maui:990575-TODO : Shell page size changed event not triggered after .NET 10 update, so wire the size changed event for the current page of the Shell page. + shellPage.CurrentPage.SizeChanged += this.OnMainPageSizeChanged; } else { - windowPage.SizeChanged += OnMainPageSizeChanged; + windowPage.SizeChanged += this.OnMainPageSizeChanged; } } @@ -82,6 +87,11 @@ internal void UnWirePlatformSpecificEvents() // Wired the size change event for the Modal page when a popup is opened from it. ModalPage.SizeChanged -= OnMainPageSizeChanged; } + else if (windowPage is Shell shellPage && shellPage.CurrentPage != null) + { + // Maui:990575-TODO : Shell page size changed event not triggered after .NET 10 update, so unwire the size changed event for the current page of the Shell page. + shellPage.CurrentPage.SizeChanged -= this.OnMainPageSizeChanged; + } else { windowPage.SizeChanged -= OnMainPageSizeChanged; diff --git a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Layout/SfPopupUnitTest.cs b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Layout/SfPopupUnitTest.cs index 4c6e9bcb..c3b474bc 100644 --- a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Layout/SfPopupUnitTest.cs +++ b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Layout/SfPopupUnitTest.cs @@ -688,7 +688,7 @@ public void TestSfPopupShow(bool value) } [Theory] [InlineData(false, false, false)] - [InlineData(true, true, true)] + [InlineData(true, true, false)] [InlineData(false, true, false)] public void TestSfPopupDismiss(bool isOpen, bool staysOpen, bool Open) {