-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Run] Fix dark mode detection code, plus refactor #37324
base: main
Are you sure you want to change the base?
Conversation
…support Registry access mocking.
This comment has been minimized.
This comment has been minimized.
/azp run |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run |
Azure Pipelines successfully started running 1 pipeline(s). |
{ | ||
newTheme = ThemeExtensions.GetCurrentTheme(); | ||
} | ||
Theme newTheme = _settings.Theme == Theme.System ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an issue with this change. In HC mode we load different background colors.
So if in Launcher settings you set either dark or light mode instead of System then in HC mode the colors will look differently.
You can test this by running in any of the 4 HC mode in Windows 11 and then in launcher settings change the App Theme.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review, @mantaionut
I can see that I need to immediately return the Contrast theme if one is active and matches one of the 4 defaults. I will update the code and add to the unit tests to cover the various cases.
However, even if I do that, I am not seeing the Light background applied if I change the setting to "Light" from "Windows default". I've checked both my new local build and an installed version of 0.88. It looks like there has been a change as part of the move to .NET 9, because 0.86 still works. I will raise this as a separate issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the separate Contrast theme issue: #37398
Summary of the Pull Request
Fixes an issue with Run's dark mode detection, which contained an int cast of a registry key value without checking its type, and lacked a graceful fallback if the cast or any surrounding code (such as the registry value retrieval call) fails.
Also includes refactor of ThemeExtensions and ThemeManager, plus additions to support unit testing the theme code.
PR Checklist
Detailed Description of the Pull Request / Additional comments
IsSystemDarkMode()
Prior to this fix, the code for detecting Dark mode looked like this:
The following line is flawed:
Specifically, the int cast on
registryValueObj
can fail if the object is not convertible to anint
.The boolean conversion is unnecessary, too, as the value can be compared to 0, which represents the Dark theme.
The method is called by GetCurrentTheme to determine what app theme is active, so there is actually no need to return a bool; we can simply return the theme directly. With this in mind, we can change the method to:
The method is renamed GetAppsTheme, which reflects its updated purpose. (Also the method was never about checking the System theme, but the Apps theme.) This now uses a pattern-matching
is
instead ofConvert
to better handle nulls and incompatible types. A defensive try/catch has been added becauseRegistry.GetValue()
may theoretically throw. The method is internal and registry access is done through a new service class because of the new unit testing additions, which are discussed later. Finally, the const registry key string is now declared earlier in the file, together with its counterpart for GetHighContrastBaseType.GetHighContrastBaseType()
Before this PR, the method looked like this:
There is a complicating factor here in that
Theme.Light
is being used as a return value to represent the case when no matching High Contrast theme was found. This makes GetCurrentTheme difficult to decipher, asTheme.Light
is used as both a guard/default value and as an actual valid value for the apps theme. To fix this, I changed the method to returnnull
if no match was found.I also replaced
with
because the values do represent actual file paths.
The
switch
code was replaced with a case-insensitive culture-invariant lookup into a Dictionary, and the method was renamed GetHighContrastTheme. The BaseType suffix from before didn't seem to reflect the return type.GetCurrentTheme()
The change to return
null
fromGetHighContrastTheme
and the actual theme value fromGetAppsTheme
means we can changeGetCurrentTheme
from:to
This more accurately represents what the method is doing - it looks for an active High Contrast theme, and if no match is found, it returns the preferred Dark/Light theme for apps.
ThemeManager Updates
UpdateTheme could be simplified by taking into account the fact that GetCurrentTheme already does a check for the High Contrast theme. It can be changed from:
to:
Some minor refactoring to ThemeManager.cs, including:
ManagedCommon
prefix from many places. There was already ausing
for this namespace, making them redundant.Theme
values to be straight equality comparisons, which is more idiomatic. For example:was changed to:
CurrentTheme
an auto property, as it doesn't need a backing field.ResourceDictionary test = new ResourceDictionary...
).Theme.Light
andTheme.Dark
mappings in theswitch
, as this is theelse
block after they are specifically checked for in theif
, so they will never match.Theme.Light
so issues are more visible should a new HC mode be added but not correctly matched.ThemeHelper
, as it's no longer a static class because of the updates for unit testing. Speaking of unit tests...Unit Tests
There were no tests for the theme-related methods, so this PR:
Finallly
Validation Steps Performed
New unit tests which exercise
ThemeHelper
methods directly.Manual tests
The application responds correctly when: