diff --git a/src/Controls/samples/Controls.Sample/Platforms/Android/MainActivity.cs b/src/Controls/samples/Controls.Sample/Platforms/Android/MainActivity.cs index 305d38ba1062..43a3f5a88751 100644 --- a/src/Controls/samples/Controls.Sample/Platforms/Android/MainActivity.cs +++ b/src/Controls/samples/Controls.Sample/Platforms/Android/MainActivity.cs @@ -14,7 +14,7 @@ namespace Maui.Controls.Sample.Platform | ConfigChanges.UiMode | ConfigChanges.SmallestScreenSize | ConfigChanges.KeyboardHidden - | ConfigChanges.Density + | ConfigChanges.Density )] [IntentFilter( new[] { Microsoft.Maui.ApplicationModel.Platform.Intent.ActionAppAction }, diff --git a/src/Controls/src/Core/Application.cs b/src/Controls/src/Core/Application.cs index 8a5680e7a203..85d611620bd6 100644 --- a/src/Controls/src/Core/Application.cs +++ b/src/Controls/src/Core/Application.cs @@ -52,7 +52,8 @@ internal Application(bool setCurrentApplication) _platformConfigurationRegistry = new Lazy>(() => new PlatformConfigurationRegistry(this)); - _lastAppTheme = PlatformAppTheme; + _platformAppTheme = AppInfo.RequestedTheme; + _lastAppTheme = _platformAppTheme; } /// @@ -169,15 +170,34 @@ public AppTheme UserAppTheme get => _userAppTheme; set { + if (_userAppTheme == value) + return; + _userAppTheme = value; + TriggerThemeChangedActual(); } } - public AppTheme PlatformAppTheme => AppInfo.RequestedTheme; + public AppTheme PlatformAppTheme + { + get => _platformAppTheme; + private set + { + if (_platformAppTheme == value) + return; + + _platformAppTheme = value; + + TriggerThemeChangedActual(); + } + } /// - public AppTheme RequestedTheme => UserAppTheme != AppTheme.Unspecified ? UserAppTheme : PlatformAppTheme; + public AppTheme RequestedTheme => + UserAppTheme != AppTheme.Unspecified + ? UserAppTheme + : PlatformAppTheme; static Color? _accentColor; public static Color? AccentColor @@ -216,6 +236,7 @@ public event EventHandler RequestedThemeChanged } bool _themeChangedFiring; + AppTheme _platformAppTheme = AppTheme.Unspecified; AppTheme _lastAppTheme = AppTheme.Unspecified; AppTheme _userAppTheme = AppTheme.Unspecified; diff --git a/src/Controls/src/Core/HandlerImpl/Application/Application.Impl.cs b/src/Controls/src/Core/HandlerImpl/Application/Application.Impl.cs index 68b6c2e6e717..bbe7584fcfe8 100644 --- a/src/Controls/src/Core/HandlerImpl/Application/Application.Impl.cs +++ b/src/Controls/src/Core/HandlerImpl/Application/Application.Impl.cs @@ -106,10 +106,7 @@ public virtual void CloseWindow(Window window) void IApplication.ThemeChanged() { - if (UserAppTheme != AppTheme.Unspecified) - return; - - TriggerThemeChangedActual(); + PlatformAppTheme = AppInfo.RequestedTheme; } protected virtual Window CreateWindow(IActivationState? activationState) diff --git a/src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs b/src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs index a77158de08cc..57a3cca89550 100644 --- a/src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs +++ b/src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Threading.Tasks; +using Microsoft.Maui.ApplicationModel; using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Graphics; @@ -555,7 +556,8 @@ private protected override void OnHandlerChangingCore(HandlerChangingEventArgs a if (FlowDirection == FlowDirection.MatchParent && mauiContext != null) { - FlowController.EffectiveFlowDirection = mauiContext.GetFlowDirection().ToEffectiveFlowDirection(true); + var flowDirection = AppInfo.Current.RequestedLayoutDirection.ToFlowDirection(); + FlowController.EffectiveFlowDirection = flowDirection.ToEffectiveFlowDirection(true); } } diff --git a/src/Controls/tests/Core.UnitTests/MockPlatformServices.cs b/src/Controls/tests/Core.UnitTests/MockPlatformServices.cs index 54acb4b253ef..c0589c7dbb37 100644 --- a/src/Controls/tests/Core.UnitTests/MockPlatformServices.cs +++ b/src/Controls/tests/Core.UnitTests/MockPlatformServices.cs @@ -84,6 +84,9 @@ public class MockApplication : Application public MockApplication() { } + + public void NotifyThemeChanged() => + (this as IApplication).ThemeChanged(); } internal class MockTicker : Ticker diff --git a/src/Controls/tests/Xaml.UnitTests/OnAppThemeTests.cs b/src/Controls/tests/Xaml.UnitTests/OnAppThemeTests.cs index 850029461134..0c500d0c837b 100644 --- a/src/Controls/tests/Xaml.UnitTests/OnAppThemeTests.cs +++ b/src/Controls/tests/Xaml.UnitTests/OnAppThemeTests.cs @@ -10,13 +10,14 @@ namespace Microsoft.Maui.Controls.Xaml.UnitTests public class OnAppThemeTests : BaseTestFixture { MockAppInfo mockAppInfo; + MockApplication mockApp; [SetUp] public override void Setup() { base.Setup(); AppInfo.SetCurrent(mockAppInfo = new MockAppInfo()); - Application.Current = new MockApplication(); + Application.Current = mockApp = new MockApplication(); } [TearDown] @@ -36,11 +37,11 @@ public void OnAppThemeExtensionLightDarkColor() xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml"" TextColor=""{AppThemeBinding Light = Green, Dark = Red} "">This text is green or red depending on Light (or default) or Dark"; - mockAppInfo.RequestedTheme = AppTheme.Light; + SetAppTheme(AppTheme.Light); var label = new Label().LoadFromXaml(xaml); Assert.AreEqual(Colors.Green, label.TextColor); - mockAppInfo.RequestedTheme = AppTheme.Dark; + SetAppTheme(AppTheme.Dark); label = new Label().LoadFromXaml(xaml); Assert.AreEqual(Colors.Red, label.TextColor); } @@ -58,11 +59,11 @@ public void OnAppThemeLightDarkColor() "; - mockAppInfo.RequestedTheme = AppTheme.Light; + SetAppTheme(AppTheme.Light); var label = new Label().LoadFromXaml(xaml); Assert.AreEqual(Colors.Green, label.TextColor); - mockAppInfo.RequestedTheme = AppTheme.Dark; + SetAppTheme(AppTheme.Dark); label = new Label().LoadFromXaml(xaml); Assert.AreEqual(Colors.Red, label.TextColor); } @@ -80,7 +81,7 @@ public void OnAppThemeUnspecifiedThemeDefaultsToLightColor() "; - mockAppInfo.RequestedTheme = AppTheme.Unspecified; + SetAppTheme(AppTheme.Unspecified); var label = new Label().LoadFromXaml(xaml); Assert.AreEqual(Colors.Green, label.TextColor); } @@ -98,7 +99,7 @@ public void OnAppThemeUnspecifiedLightColorDefaultsToDefault() "; - mockAppInfo.RequestedTheme = AppTheme.Light; + SetAppTheme(AppTheme.Light); var label = new Label().LoadFromXaml(xaml); Assert.AreEqual(Colors.Green, label.TextColor); } @@ -116,11 +117,11 @@ public void AppThemeColorLightDark() "; - mockAppInfo.RequestedTheme = AppTheme.Light; + SetAppTheme(AppTheme.Light); var label = new Label().LoadFromXaml(xaml); Assert.AreEqual(Colors.Green, label.TextColor); - mockAppInfo.RequestedTheme = AppTheme.Dark; + SetAppTheme(AppTheme.Dark); label = new Label().LoadFromXaml(xaml); Assert.AreEqual(Colors.Red, label.TextColor); } @@ -138,7 +139,7 @@ public void AppThemeColorUnspecifiedThemeDefaultsToLightColor() "; - mockAppInfo.RequestedTheme = AppTheme.Unspecified; + SetAppTheme(AppTheme.Unspecified); var label = new Label().LoadFromXaml(xaml); Assert.AreEqual(Colors.Green, label.TextColor); } @@ -156,9 +157,15 @@ public void AppThemeColorUnspecifiedLightColorDefaultsToDefault() "; - mockAppInfo.RequestedTheme = AppTheme.Unspecified; + SetAppTheme(AppTheme.Unspecified); var label = new Label().LoadFromXaml(xaml); Assert.AreEqual(Colors.Green, label.TextColor); } + + void SetAppTheme(AppTheme theme) + { + mockAppInfo.RequestedTheme = theme; + mockApp.NotifyThemeChanged(); + } } } \ No newline at end of file diff --git a/src/Core/src/MauiContextExtensions.cs b/src/Core/src/MauiContextExtensions.cs index 500c76cf778a..7bcf4ad192ab 100644 --- a/src/Core/src/MauiContextExtensions.cs +++ b/src/Core/src/MauiContextExtensions.cs @@ -75,15 +75,5 @@ public static void InitializeScopedServices(this IMauiContext scopedContext) foreach (var service in scopedServices) service.Initialize(scopedContext.Services); } - - public static FlowDirection GetFlowDirection(this IMauiContext mauiContext) - { - var appInfo = AppInfo.Current; - - if (appInfo.RequestedLayoutDirection == LayoutDirection.RightToLeft) - return FlowDirection.RightToLeft; - - return FlowDirection.LeftToRight; - } } } diff --git a/src/Essentials/src/AppInfo/AppInfo.android.cs b/src/Essentials/src/AppInfo/AppInfo.android.cs index e274e756826e..6b1e62908239 100644 --- a/src/Essentials/src/AppInfo/AppInfo.android.cs +++ b/src/Essentials/src/AppInfo/AppInfo.android.cs @@ -13,11 +13,9 @@ class AppInfoImplementation : IAppInfo { static readonly Lazy _name = new Lazy(() => Application.Context.ApplicationInfo.LoadLabel(Application.Context.PackageManager)); static readonly Lazy _packageName = new Lazy(() => Application.Context.PackageName); -#pragma warning disable 618 +#pragma warning disable CS0618, CA1416, CA1422 // Deprecated in API 33: https://developer.android.com/reference/android/content/pm/PackageManager#getPackageInfo(java.lang.String,%20int) static readonly Lazy _packageInfo = new Lazy(() => Application.Context.PackageManager.GetPackageInfo(_packageName.Value, PackageInfoFlags.MetaData)); -#pragma warning restore 618 - static readonly Lazy _requestedTheme = new Lazy(GetRequestedTheme); - static readonly Lazy _layoutDirection = new Lazy(GetLayoutDirection); +#pragma warning restore CS0618, CA1416, CA1422 public string PackageName => _packageName.Value; @@ -44,14 +42,21 @@ public void ShowSettingsUI() context.StartActivity(settingsIntent); } - static AppTheme GetRequestedTheme() => (Application.Context.Resources.Configuration.UiMode & UiMode.NightMask) switch + static AppTheme GetRequestedTheme() { - UiMode.NightYes => AppTheme.Dark, - UiMode.NightNo => AppTheme.Light, - _ => AppTheme.Unspecified - }; + var config = Application.Context.Resources?.Configuration; + if (config == null) + return AppTheme.Unspecified; + + return (config.UiMode & UiMode.NightMask) switch + { + UiMode.NightYes => AppTheme.Dark, + UiMode.NightNo => AppTheme.Light, + _ => AppTheme.Unspecified + }; + } - public AppTheme RequestedTheme => _requestedTheme.Value; + public AppTheme RequestedTheme => GetRequestedTheme(); public AppPackagingModel PackagingModel => AppPackagingModel.Packaged; @@ -61,10 +66,11 @@ static LayoutDirection GetLayoutDirection() if (config == null) return LayoutDirection.Unknown; - return (config.LayoutDirection == Android.Views.LayoutDirection.Rtl) ? LayoutDirection.RightToLeft : - LayoutDirection.LeftToRight; + return (config.LayoutDirection == Android.Views.LayoutDirection.Rtl) + ? LayoutDirection.RightToLeft + : LayoutDirection.LeftToRight; } - public LayoutDirection RequestedLayoutDirection => _layoutDirection.Value; + public LayoutDirection RequestedLayoutDirection => GetLayoutDirection(); } }