Repository navigation
Allow setting ThemeVariant to Default to reset theme to system on android - #16340
Conversation
c790620 to
a5b7801
Compare
a5b7801 to
8f7eb32
Compare
8f7eb32 to
91348e2
Compare
| AppCompatDelegate.DefaultNightMode = themeVariant == null ? AppCompatDelegate.ModeNightFollowSystem : | ||
| themeVariant == PlatformThemeVariant.Light ? AppCompatDelegate.ModeNightNo : AppCompatDelegate.ModeNightYes; | ||
|
|
||
| if (AppCompatDelegate.DefaultNightMode == AppCompatDelegate.ModeNightFollowSystem && _view.Context is { } context |
There was a problem hiding this comment.
Can you add some brief comments on this part of the code? Just so reasoning will be kept in the code as well.
|
|
||
| static Application() | ||
| { | ||
| RequestedThemeVariantProperty.OverrideDefaultValue<Application>(ThemeVariant.Default); |
There was a problem hiding this comment.
nit: RequestedThemeVariantProperty should already have Default as a default value.
There was a problem hiding this comment.
Currently, it doesn't. AddOwner doesn't inherit the default value of the property.
| if ((RequestedThemeVariant ?? ThemeVariant.Default) == ThemeVariant.Default) | ||
| SetCurrentValue(ActualThemeVariantProperty, (ThemeVariant)e.ThemeVariant); |
There was a problem hiding this comment.
With this change, we break theme switching (at least on desktop), when:
- Apps opens with default Dark variant.
- User switches to non-default Dark variant.
- OS changes global theme variant to Light variant. - at this point Application won't receive any changes about system theme because of this condition.
- User switches back to Default variant. But app won't be changed, because previous OnColorValuesChanged was ignored.
We probably need to save latest value in the field. And use it when user changes to Default.
There was a problem hiding this comment.
@emmauss I pushed a commit that changes 372 line. When user switches to the Default variant - we now read GetColorValues(). Works on Windows well.
Let me know if it still works on android as expected.
There was a problem hiding this comment.
The changes on 372 prevent Default from ever being sent to the toplevel impl, which we need on the android side.
There was a problem hiding this comment.
@emmauss I pushed a commit that changes 372 line. When user switches to the Default variant - we now read GetColorValues(). Works on Windows well.
Let me know if it still works on android as expected.
It doesn't really work. Since only Light or Dark is ever sent to the OS with your change, the OS never switches to FollowSystem.
We could pass both Actual variant and Requested variant. Requested for the OS to know what the app want, and Actual for the OS to update the system bars and nav bar
There was a problem hiding this comment.
Note: the exact scenario reported by Max above still fails on X11:
(Default Dark => Light => Default doesn't switch back to Dark).
|
|
||
| static ThemeVariantScope() | ||
| { | ||
| RequestedThemeVariantProperty.OverrideDefaultValue<ThemeVariantScope>(ThemeVariant.Default); |
There was a problem hiding this comment.
nit: again, it should be Default by default already. See https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Base/Styling/ThemeVariant.cs#L29-L31
There was a problem hiding this comment.
Same issue as Application
| private void GlobalActualThemeVariantChanged(object? sender, EventArgs e) | ||
| { | ||
| SetValue(ActualThemeVariantProperty, ((IThemeVariantHost)sender!).ActualThemeVariant, BindingPriority.Template); | ||
| SetCurrentValue(ActualThemeVariantProperty, ((IThemeVariantHost)sender!).ActualThemeVariant); |
There was a problem hiding this comment.
It seems to break when:
- User has Application.RequestedThemeVariant = Light
- User changes Window.RequestedThemeVariant = Dark
- User changes to Application.RequestedThemeVariant to Dark and then to Light again - Window now Light again, because SetCurrentValue has overridden value.
BindingPriority.Template is a lower priority than CurrentValue, so it was used to keep global variant lower priority than variant set by user on TopLevel directly.
|
You can test this PR using the following package version. |
|
You can test this PR using the following package version. |
3f31cdc to
40500db
Compare
|
You can test this PR using the following package version. |
|
You can test this PR using the following package version. |
|
There are still issues with this PR, we need more time to fix it for all platforms. I'm marking it as a draft for now since it's not ready in its current state. |
|
Rebased |
|
You can test this PR using the following package version. |
MrJul
left a comment
There was a problem hiding this comment.
I haven't retested all platforms yet, but switching back to the default theme is broken on at least X11.
9160440 to
22067ae
Compare
|
You can test this PR using the following package version. |
MrJul
left a comment
There was a problem hiding this comment.
All platforms are now working as expected.
LGTM!
|
You can test this PR using the following package version. |
What does the pull request do?
Changes
ITopLevelImpl.SetFrameThemeVariantto receive nullablePlatformThemeVariant. This is to enableThemeVariant.Defaultto be interpreted as System default on the platform level. On Android, this allows detecting theme changes triggered by the OS.What is the current behavior?
Android seems to have a weird behavior concerning theme "ownership".
A simple app(native android in this case) that doesn't change theme dynamically will always follow System theme. In this case, if the app is handling uiMode configuration changes to detect theme, both Activity.OnConfigurationChanged and View.OnConfigurationChanged will be called with the new ui mode.
If the app sets their app theme with AppCompatDelegate.DefaultNightMode to NightModeYes/No, the system no longer manages theming for the app, and only Activity.OnConfigurationChanged will be called for the app to detect system theme change.
In avalonia, we rely on View.OnConfigurationChanged to detect system theme change, but since we enforce ThemeVariant when the app launches, we no longer receive uiMode notifications through View.OnConfigurationChanged. We can listen to it on Activity level, but that wouldn't work when an avalonia view is embedded in an Activity we don't control.
Currently, we have 2 PlatformThemeVariants, Dark and Light. There is no Default or System variant that would reset the app theme to the system one. Android saves the last NightMode for the app and applies it when the Activity is created, unless the app is newly installed, the RequestedThemeVariant usually set in App.xaml. This is due to requesting the systems/app theme accents here;
Avalonia/src/Android/Avalonia.Android/AvaloniaView.cs
Line 34 in 9c6a2c9
which will also forward the saved NightMode to the app. We need the system accents, so we can't skip sending the current configuration.
What is the updated/expected behavior with this PR?
Setting App.RequestedThemeVariant to ThemeVariant.Default will set the app theme to the System on android, allowing app theme to change dynamically.
How was the solution implemented (if it's not obvious)?
Checklist
Breaking changes
Obsoletions / Deprecations
Fixed issues
Fixes #16241