mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Use Windows high contrast black/white theme with MaterialApp themes (flutter/engine#39206)
* Check high contrast themes * Formatting * Test message sending * Assert channel name * Formatting * Calculate luminance * Refactor brightness check * Formatting * Formatting
This commit is contained in:
parent
f9f8c2f67a
commit
ce15fbec0e
@ -668,6 +668,7 @@ void FlutterWindowsEngine::UpdateHighContrastEnabled(bool enabled) {
|
||||
~FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast;
|
||||
}
|
||||
UpdateAccessibilityFeatures(static_cast<FlutterAccessibilityFeature>(flags));
|
||||
settings_plugin_->UpdateHighContrastMode(enabled);
|
||||
}
|
||||
|
||||
int FlutterWindowsEngine::EnabledAccessibilityFeatures() const {
|
||||
|
||||
@ -26,6 +26,32 @@ constexpr wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
|
||||
constexpr wchar_t kGetTextScaleFactorRegKey[] =
|
||||
L"Software\\Microsoft\\Accessibility";
|
||||
constexpr wchar_t kGetTextScaleFactorRegValue[] = L"TextScaleFactor";
|
||||
|
||||
// Return an approximation of the apparent luminance of a given color.
|
||||
int GetLuminance(DWORD color) {
|
||||
int r = GetRValue(color);
|
||||
int g = GetGValue(color);
|
||||
int b = GetBValue(color);
|
||||
return (r + r + r + b + (g << 2)) >> 3;
|
||||
}
|
||||
|
||||
// Return kLight if light mode for apps is selected, otherwise return kDark.
|
||||
SettingsPlugin::PlatformBrightness GetThemeBrightness() {
|
||||
DWORD use_light_theme;
|
||||
DWORD use_light_theme_size = sizeof(use_light_theme);
|
||||
LONG result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
|
||||
kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD,
|
||||
nullptr, &use_light_theme, &use_light_theme_size);
|
||||
|
||||
if (result == 0) {
|
||||
return use_light_theme ? SettingsPlugin::PlatformBrightness::kLight
|
||||
: SettingsPlugin::PlatformBrightness::kDark;
|
||||
} else {
|
||||
// The current OS does not support dark mode. (Older Windows 10 or before
|
||||
// Windows 10)
|
||||
return SettingsPlugin::PlatformBrightness::kLight;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SettingsPlugin::SettingsPlugin(BinaryMessenger* messenger,
|
||||
@ -103,19 +129,13 @@ float SettingsPlugin::GetTextScaleFactor() {
|
||||
}
|
||||
|
||||
SettingsPlugin::PlatformBrightness SettingsPlugin::GetPreferredBrightness() {
|
||||
DWORD use_light_theme;
|
||||
DWORD use_light_theme_size = sizeof(use_light_theme);
|
||||
LONG result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
|
||||
kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD,
|
||||
nullptr, &use_light_theme, &use_light_theme_size);
|
||||
|
||||
if (result == 0) {
|
||||
return use_light_theme ? SettingsPlugin::PlatformBrightness::kLight
|
||||
: SettingsPlugin::PlatformBrightness::kDark;
|
||||
if (is_high_contrast_) {
|
||||
DWORD window_color = GetSysColor(COLOR_WINDOW);
|
||||
int luminance = GetLuminance(window_color);
|
||||
return luminance >= 127 ? SettingsPlugin::PlatformBrightness::kLight
|
||||
: SettingsPlugin::PlatformBrightness::kDark;
|
||||
} else {
|
||||
// The current OS does not support dark mode. (Older Windows 10 or before
|
||||
// Windows 10)
|
||||
return SettingsPlugin::PlatformBrightness::kLight;
|
||||
return GetThemeBrightness();
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,4 +166,9 @@ void SettingsPlugin::WatchTextScaleFactorChanged() {
|
||||
text_scale_factor_changed_watcher_->GetHandle(), TRUE);
|
||||
}
|
||||
|
||||
void SettingsPlugin::UpdateHighContrastMode(bool is_high_contrast) {
|
||||
is_high_contrast_ = is_high_contrast;
|
||||
SendSettings();
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@ -23,6 +23,8 @@ namespace flutter {
|
||||
// These are typically set in the control panel.
|
||||
class SettingsPlugin {
|
||||
public:
|
||||
enum struct PlatformBrightness { kDark, kLight };
|
||||
|
||||
explicit SettingsPlugin(BinaryMessenger* messenger, TaskRunner* task_runner);
|
||||
|
||||
virtual ~SettingsPlugin();
|
||||
@ -37,9 +39,10 @@ class SettingsPlugin {
|
||||
// this automatically.
|
||||
virtual void StopWatching();
|
||||
|
||||
protected:
|
||||
enum struct PlatformBrightness { kDark, kLight };
|
||||
// Update the high contrast status of the system.
|
||||
virtual void UpdateHighContrastMode(bool is_high_contrast);
|
||||
|
||||
protected:
|
||||
// Returns `true` if the user uses 24 hour time.
|
||||
virtual bool GetAlwaysUse24HourFormat();
|
||||
|
||||
@ -55,6 +58,8 @@ class SettingsPlugin {
|
||||
// Starts watching text scale factor changes.
|
||||
virtual void WatchTextScaleFactorChanged();
|
||||
|
||||
bool is_high_contrast_ = false;
|
||||
|
||||
private:
|
||||
std::unique_ptr<BasicMessageChannel<rapidjson::Document>> channel_;
|
||||
|
||||
|
||||
@ -21,6 +21,8 @@ class MockSettingsPlugin : public SettingsPlugin {
|
||||
|
||||
virtual ~MockSettingsPlugin() = default;
|
||||
|
||||
bool is_high_contrast() { return is_high_contrast_; }
|
||||
|
||||
// |SettingsPlugin|
|
||||
MOCK_METHOD0(GetAlwaysUse24HourFormat, bool());
|
||||
MOCK_METHOD0(GetTextScaleFactor, float());
|
||||
@ -70,5 +72,24 @@ TEST(SettingsPluginTest, StartWatchingStartsWatchingChanges) {
|
||||
settings_plugin.StartWatching();
|
||||
}
|
||||
|
||||
TEST(SettingsPluginTest, HighContrastModeHonored) {
|
||||
int times = 0;
|
||||
TestBinaryMessenger messenger(
|
||||
[×](const std::string& channel, const uint8_t* message,
|
||||
size_t message_size, BinaryReply reply) {
|
||||
ASSERT_EQ(channel, "flutter/settings");
|
||||
times++;
|
||||
});
|
||||
::testing::NiceMock<MockSettingsPlugin> settings_plugin(&messenger, nullptr);
|
||||
|
||||
settings_plugin.UpdateHighContrastMode(true);
|
||||
EXPECT_TRUE(settings_plugin.is_high_contrast());
|
||||
|
||||
settings_plugin.UpdateHighContrastMode(false);
|
||||
EXPECT_FALSE(settings_plugin.is_high_contrast());
|
||||
|
||||
EXPECT_EQ(times, 2);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user