committed by
GitHub
44 changed files with 3659 additions and 41 deletions
@ -0,0 +1,113 @@ |
|||||
|
#include "common.h" |
||||
|
|
||||
|
@interface CocoaThemeObserver : NSObject |
||||
|
-(id)initWithCallback:(IAvnActionCallback *)callback; |
||||
|
@end |
||||
|
|
||||
|
class PlatformSettings : public ComSingleObject<IAvnPlatformSettings, &IID_IAvnPlatformSettings> |
||||
|
{ |
||||
|
CocoaThemeObserver* observer; |
||||
|
|
||||
|
public: |
||||
|
FORWARD_IUNKNOWN() |
||||
|
virtual AvnPlatformThemeVariant GetPlatformTheme() override |
||||
|
{ |
||||
|
@autoreleasepool |
||||
|
{ |
||||
|
if (@available(macOS 10.14, *)) |
||||
|
{ |
||||
|
if (NSApplication.sharedApplication.effectiveAppearance.name == NSAppearanceNameAqua |
||||
|
|| NSApplication.sharedApplication.effectiveAppearance.name == NSAppearanceNameVibrantLight) { |
||||
|
return AvnPlatformThemeVariant::Light; |
||||
|
} else if (NSApplication.sharedApplication.effectiveAppearance.name == NSAppearanceNameDarkAqua |
||||
|
|| NSApplication.sharedApplication.effectiveAppearance.name == NSAppearanceNameVibrantDark) { |
||||
|
return AvnPlatformThemeVariant::Dark; |
||||
|
} else if (NSApplication.sharedApplication.effectiveAppearance.name == NSAppearanceNameAccessibilityHighContrastAqua |
||||
|
|| NSApplication.sharedApplication.effectiveAppearance.name == NSAppearanceNameAccessibilityHighContrastVibrantLight) { |
||||
|
return AvnPlatformThemeVariant::HighContrastLight; |
||||
|
} else if (NSApplication.sharedApplication.effectiveAppearance.name == NSAppearanceNameAccessibilityHighContrastDarkAqua |
||||
|
|| NSApplication.sharedApplication.effectiveAppearance.name == NSAppearanceNameAccessibilityHighContrastVibrantDark) { |
||||
|
return AvnPlatformThemeVariant::HighContrastDark; |
||||
|
} |
||||
|
} |
||||
|
return AvnPlatformThemeVariant::Light; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual unsigned int GetAccentColor() override |
||||
|
{ |
||||
|
@autoreleasepool |
||||
|
{ |
||||
|
if (@available(macOS 10.14, *)) |
||||
|
{ |
||||
|
auto color = [NSColor controlAccentColor]; |
||||
|
return to_argb(color); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual void RegisterColorsChange(IAvnActionCallback *callback) override |
||||
|
{ |
||||
|
if (@available(macOS 10.14, *)) |
||||
|
{ |
||||
|
observer = [[CocoaThemeObserver alloc] initWithCallback: callback]; |
||||
|
[[NSApplication sharedApplication] addObserver:observer forKeyPath:@"effectiveAppearance" options:NSKeyValueObservingOptionNew context:nil]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
unsigned int to_argb(NSColor* color) |
||||
|
{ |
||||
|
const CGFloat* components = CGColorGetComponents(color.CGColor); |
||||
|
unsigned int alpha = static_cast<unsigned int>(CGColorGetAlpha(color.CGColor) * 0xFF); |
||||
|
unsigned int red = static_cast<unsigned int>(components[0] * 0xFF); |
||||
|
unsigned int green = static_cast<unsigned int>(components[1] * 0xFF); |
||||
|
unsigned int blue = static_cast<unsigned int>(components[2] * 0xFF); |
||||
|
return (alpha << 24) + (red << 16) + (green << 8) + blue; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
@implementation CocoaThemeObserver |
||||
|
{ |
||||
|
ComPtr<IAvnActionCallback> _callback; |
||||
|
} |
||||
|
- (id) initWithCallback:(IAvnActionCallback *)callback{ |
||||
|
self = [super init]; |
||||
|
if (self) { |
||||
|
_callback = callback; |
||||
|
} |
||||
|
return self; |
||||
|
} |
||||
|
|
||||
|
/*- (void)didChangeValueForKey:(NSString *)key { |
||||
|
if([key isEqualToString:@"effectiveAppearance"]) { |
||||
|
_callback->Run(); |
||||
|
} |
||||
|
else { |
||||
|
[super didChangeValueForKey:key]; |
||||
|
} |
||||
|
}*/ |
||||
|
|
||||
|
- (void)observeValueForKeyPath:(NSString *)keyPath |
||||
|
ofObject:(id)object |
||||
|
change:(NSDictionary *)change |
||||
|
context:(void *)context { |
||||
|
if([keyPath isEqualToString:@"effectiveAppearance"]) { |
||||
|
_callback->Run(); |
||||
|
} else { |
||||
|
[super observeValueForKeyPath:keyPath |
||||
|
ofObject:object |
||||
|
change:change |
||||
|
context:context]; |
||||
|
} |
||||
|
} |
||||
|
@end |
||||
|
|
||||
|
extern IAvnPlatformSettings* CreatePlatformSettings() |
||||
|
{ |
||||
|
return new PlatformSettings(); |
||||
|
} |
||||
@ -0,0 +1,94 @@ |
|||||
|
using System; |
||||
|
using Android; |
||||
|
using Android.Content; |
||||
|
using Android.Content.Res; |
||||
|
using Android.Graphics; |
||||
|
using Android.Provider; |
||||
|
using Android.Views.Accessibility; |
||||
|
using AndroidX.Core.Content.Resources; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Platform; |
||||
|
using Color = Avalonia.Media.Color; |
||||
|
|
||||
|
namespace Avalonia.Android.Platform; |
||||
|
|
||||
|
// TODO: ideally should be created per view/activity.
|
||||
|
internal class AndroidPlatformSettings : DefaultPlatformSettings |
||||
|
{ |
||||
|
private PlatformColorValues _latestValues; |
||||
|
|
||||
|
public AndroidPlatformSettings() |
||||
|
{ |
||||
|
_latestValues = base.GetColorValues(); |
||||
|
} |
||||
|
|
||||
|
public override PlatformColorValues GetColorValues() |
||||
|
{ |
||||
|
return _latestValues; |
||||
|
} |
||||
|
|
||||
|
internal void OnViewConfigurationChanged(Context context) |
||||
|
{ |
||||
|
if (context.Resources?.Configuration is null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var systemTheme = (context.Resources.Configuration.UiMode & UiMode.NightMask) switch |
||||
|
{ |
||||
|
UiMode.NightYes => PlatformThemeVariant.Dark, |
||||
|
UiMode.NightNo => PlatformThemeVariant.Light, |
||||
|
_ => throw new ArgumentOutOfRangeException() |
||||
|
}; |
||||
|
|
||||
|
if (OperatingSystem.IsAndroidVersionAtLeast(31)) |
||||
|
{ |
||||
|
// See https://developer.android.com/reference/android/R.color
|
||||
|
var accent1 = context.Resources.GetColor(17170494, context.Theme); // Resource.Color.SystemAccent1500
|
||||
|
var accent2 = context.Resources.GetColor(17170507, context.Theme); // Resource.Color.SystemAccent2500
|
||||
|
var accent3 = context.Resources.GetColor(17170520, context.Theme); // Resource.Color.SystemAccent3500
|
||||
|
|
||||
|
_latestValues = new PlatformColorValues |
||||
|
{ |
||||
|
ThemeVariant = systemTheme, |
||||
|
ContrastPreference = IsHighContrast(context), |
||||
|
AccentColor1 = new Color(accent1.A, accent1.R, accent1.G, accent1.B), |
||||
|
AccentColor2 = new Color(accent2.A, accent2.R, accent2.G, accent2.B), |
||||
|
AccentColor3 = new Color(accent3.A, accent3.R, accent3.G, accent3.B), |
||||
|
}; |
||||
|
} |
||||
|
else if (OperatingSystem.IsAndroidVersionAtLeast(23)) |
||||
|
{ |
||||
|
// See https://developer.android.com/reference/android/R.attr
|
||||
|
var array = context.Theme.ObtainStyledAttributes(new[] { 16843829 }); // Resource.Attribute.ColorAccent
|
||||
|
var accent = array.GetColor(0, 0); |
||||
|
|
||||
|
_latestValues = new PlatformColorValues |
||||
|
{ |
||||
|
ThemeVariant = systemTheme, |
||||
|
ContrastPreference = IsHighContrast(context), |
||||
|
AccentColor1 = new Color(accent.A, accent.R, accent.G, accent.B) |
||||
|
}; |
||||
|
array.Recycle(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_latestValues = _latestValues with { ThemeVariant = systemTheme }; |
||||
|
} |
||||
|
|
||||
|
OnColorValuesChanged(_latestValues); |
||||
|
} |
||||
|
|
||||
|
private static ColorContrastPreference IsHighContrast(Context context) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
return Settings.Secure.GetInt(context.ContentResolver, "high_text_contrast_enabled", 0) == 1 |
||||
|
? ColorContrastPreference.High : ColorContrastPreference.NoPreference; |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
return ColorContrastPreference.NoPreference; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,68 @@ |
|||||
|
using Avalonia.Media; |
||||
|
|
||||
|
namespace Avalonia.Platform; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// System theme variant or mode.
|
||||
|
/// </summary>
|
||||
|
public enum PlatformThemeVariant |
||||
|
{ |
||||
|
Light, |
||||
|
Dark |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// System high contrast preference.
|
||||
|
/// </summary>
|
||||
|
public enum ColorContrastPreference |
||||
|
{ |
||||
|
NoPreference, |
||||
|
High |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Information about current system color values, including information about dark mode and accent colors.
|
||||
|
/// </summary>
|
||||
|
public record PlatformColorValues |
||||
|
{ |
||||
|
private static Color DefaultAccent => new(255, 0, 120, 215); |
||||
|
private Color _accentColor2, _accentColor3; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// System theme variant or mode.
|
||||
|
/// </summary>
|
||||
|
public PlatformThemeVariant ThemeVariant { get; init; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// System high contrast preference.
|
||||
|
/// </summary>
|
||||
|
public ColorContrastPreference ContrastPreference { get; init; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Primary system accent color.
|
||||
|
/// </summary>
|
||||
|
public Color AccentColor1 { get; init; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Secondary system accent color. On some platforms can return the same value as <see cref="AccentColor1"/>.
|
||||
|
/// </summary>
|
||||
|
public Color AccentColor2 |
||||
|
{ |
||||
|
get => _accentColor2 != default ? _accentColor2 : AccentColor1; |
||||
|
init => _accentColor2 = value; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Tertiary system accent color. On some platforms can return the same value as <see cref="AccentColor1"/>.
|
||||
|
/// </summary>
|
||||
|
public Color AccentColor3 |
||||
|
{ |
||||
|
get => _accentColor3 != default ? _accentColor3 : AccentColor1; |
||||
|
init => _accentColor3 = value; |
||||
|
} |
||||
|
|
||||
|
public PlatformColorValues() |
||||
|
{ |
||||
|
AccentColor1 = DefaultAccent; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,77 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Avalonia.Logging; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace Avalonia.FreeDesktop; |
||||
|
|
||||
|
internal class DBusPlatformSettings : DefaultPlatformSettings |
||||
|
{ |
||||
|
private readonly IDBusSettings? _settings; |
||||
|
private PlatformColorValues? _lastColorValues; |
||||
|
|
||||
|
public DBusPlatformSettings() |
||||
|
{ |
||||
|
_settings = DBusHelper.TryInitialize()? |
||||
|
.CreateProxy<IDBusSettings>("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop"); |
||||
|
|
||||
|
if (_settings is not null) |
||||
|
{ |
||||
|
_ = _settings.WatchSettingChangedAsync(SettingsChangedHandler); |
||||
|
|
||||
|
_ = TryGetInitialValue(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override PlatformColorValues GetColorValues() |
||||
|
{ |
||||
|
return _lastColorValues ?? base.GetColorValues(); |
||||
|
} |
||||
|
|
||||
|
private async Task TryGetInitialValue() |
||||
|
{ |
||||
|
var colorSchemeTask = _settings!.ReadAsync("org.freedesktop.appearance", "color-scheme"); |
||||
|
if (colorSchemeTask.Status == TaskStatus.RanToCompletion) |
||||
|
{ |
||||
|
_lastColorValues = GetColorValuesFromSetting(colorSchemeTask.Result); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var value = await colorSchemeTask; |
||||
|
_lastColorValues = GetColorValuesFromSetting(value); |
||||
|
OnColorValuesChanged(_lastColorValues); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
_lastColorValues = base.GetColorValues(); |
||||
|
Logger.TryGet(LogEventLevel.Error, LogArea.FreeDesktopPlatform)?.Log(this, "Unable to get setting value", ex); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void SettingsChangedHandler((string @namespace, string key, object value) tuple) |
||||
|
{ |
||||
|
if (tuple.@namespace == "org.freedesktop.appearance" |
||||
|
&& tuple.key == "color-scheme") |
||||
|
{ |
||||
|
/* |
||||
|
<member>0: No preference</member> |
||||
|
<member>1: Prefer dark appearance</member> |
||||
|
<member>2: Prefer light appearance</member> |
||||
|
*/ |
||||
|
_lastColorValues = GetColorValuesFromSetting(tuple.value); |
||||
|
OnColorValuesChanged(_lastColorValues); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static PlatformColorValues GetColorValuesFromSetting(object value) |
||||
|
{ |
||||
|
var isDark = value?.ToString() == "1"; |
||||
|
return new PlatformColorValues |
||||
|
{ |
||||
|
ThemeVariant = isDark ? PlatformThemeVariant.Dark : PlatformThemeVariant.Light |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Tmds.DBus; |
||||
|
|
||||
|
namespace Avalonia.FreeDesktop; |
||||
|
|
||||
|
[DBusInterface("org.freedesktop.portal.Settings")] |
||||
|
internal interface IDBusSettings : IDBusObject |
||||
|
{ |
||||
|
Task<(string @namespace, IDictionary<string, object>)> ReadAllAsync(string[] namespaces); |
||||
|
|
||||
|
Task<object> ReadAsync(string @namespace, string key); |
||||
|
|
||||
|
Task<IDisposable> WatchSettingChangedAsync(Action<(string @namespace, string key, object value)> handler, Action<Exception>? onError = null); |
||||
|
} |
||||
@ -0,0 +1,77 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Native.Interop; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace Avalonia.Native; |
||||
|
|
||||
|
internal class NativePlatformSettings : DefaultPlatformSettings |
||||
|
{ |
||||
|
private readonly IAvnPlatformSettings _platformSettings; |
||||
|
private PlatformColorValues _lastColorValues; |
||||
|
|
||||
|
public NativePlatformSettings(IAvnPlatformSettings platformSettings) |
||||
|
{ |
||||
|
_platformSettings = platformSettings; |
||||
|
platformSettings.RegisterColorsChange(new ColorsChangeCallback(this)); |
||||
|
} |
||||
|
|
||||
|
public override PlatformColorValues GetColorValues() |
||||
|
{ |
||||
|
var (theme, contrast) = _platformSettings.PlatformTheme switch |
||||
|
{ |
||||
|
AvnPlatformThemeVariant.Dark => (PlatformThemeVariant.Dark, ColorContrastPreference.NoPreference), |
||||
|
AvnPlatformThemeVariant.Light => (PlatformThemeVariant.Light, ColorContrastPreference.NoPreference), |
||||
|
AvnPlatformThemeVariant.HighContrastDark => (PlatformThemeVariant.Dark, ColorContrastPreference.High), |
||||
|
AvnPlatformThemeVariant.HighContrastLight => (PlatformThemeVariant.Dark, ColorContrastPreference.High), |
||||
|
_ => throw new ArgumentOutOfRangeException() |
||||
|
}; |
||||
|
var color = _platformSettings.AccentColor; |
||||
|
|
||||
|
if (color > 0) |
||||
|
{ |
||||
|
_lastColorValues = new PlatformColorValues |
||||
|
{ |
||||
|
ThemeVariant = theme, |
||||
|
ContrastPreference = contrast, |
||||
|
AccentColor1 = Color.FromUInt32(color) |
||||
|
}; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_lastColorValues = new PlatformColorValues |
||||
|
{ |
||||
|
ThemeVariant = theme, |
||||
|
ContrastPreference = contrast |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
return _lastColorValues; |
||||
|
} |
||||
|
|
||||
|
public void OnColorValuesChanged() |
||||
|
{ |
||||
|
var oldColorValues = _lastColorValues; |
||||
|
var colorValues = GetColorValues(); |
||||
|
|
||||
|
if (oldColorValues != colorValues) |
||||
|
{ |
||||
|
OnColorValuesChanged(colorValues); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private class ColorsChangeCallback : NativeCallbackBase, IAvnActionCallback |
||||
|
{ |
||||
|
private readonly NativePlatformSettings _settings; |
||||
|
|
||||
|
public ColorsChangeCallback(NativePlatformSettings settings) |
||||
|
{ |
||||
|
_settings = settings; |
||||
|
} |
||||
|
|
||||
|
public void Run() |
||||
|
{ |
||||
|
_settings.OnColorValuesChanged(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using Avalonia.Browser.Interop; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace Avalonia.Browser; |
||||
|
|
||||
|
internal class BrowserPlatformSettings : DefaultPlatformSettings |
||||
|
{ |
||||
|
private bool _isDarkMode; |
||||
|
private bool _isHighContrast; |
||||
|
|
||||
|
public BrowserPlatformSettings() |
||||
|
{ |
||||
|
var obj = DomHelper.ObserveDarkMode((isDarkMode, isHighContrast) => |
||||
|
{ |
||||
|
_isDarkMode = isDarkMode; |
||||
|
_isHighContrast = isHighContrast; |
||||
|
OnColorValuesChanged(GetColorValues()); |
||||
|
}); |
||||
|
_isDarkMode = obj.GetPropertyAsBoolean("isDarkMode"); |
||||
|
_isHighContrast = obj.GetPropertyAsBoolean("isHighContrast"); |
||||
|
} |
||||
|
|
||||
|
public override PlatformColorValues GetColorValues() |
||||
|
{ |
||||
|
return base.GetColorValues() with |
||||
|
{ |
||||
|
ThemeVariant = _isDarkMode ? PlatformThemeVariant.Dark : PlatformThemeVariant.Light, |
||||
|
ContrastPreference = _isHighContrast ? ColorContrastPreference.High : ColorContrastPreference.NoPreference |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,89 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Platform; |
||||
|
using Avalonia.Win32.Interop; |
||||
|
using Avalonia.Win32.WinRT; |
||||
|
using static Avalonia.Win32.Interop.UnmanagedMethods; |
||||
|
|
||||
|
namespace Avalonia.Win32; |
||||
|
|
||||
|
internal class Win32PlatformSettings : DefaultPlatformSettings |
||||
|
{ |
||||
|
private PlatformColorValues _lastColorValues; |
||||
|
|
||||
|
public override Size GetTapSize(PointerType type) |
||||
|
{ |
||||
|
return type switch |
||||
|
{ |
||||
|
PointerType.Touch => new(10, 10), |
||||
|
_ => new(GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CXDRAG), GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CYDRAG)), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public override Size GetDoubleTapSize(PointerType type) |
||||
|
{ |
||||
|
return type switch |
||||
|
{ |
||||
|
PointerType.Touch => new(16, 16), |
||||
|
_ => new(GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CXDOUBLECLK), GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CYDOUBLECLK)), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public override TimeSpan GetDoubleTapTime(PointerType type) => TimeSpan.FromMilliseconds(GetDoubleClickTime()); |
||||
|
|
||||
|
public override PlatformColorValues GetColorValues() |
||||
|
{ |
||||
|
if (Win32Platform.WindowsVersion.Major < 10) |
||||
|
{ |
||||
|
return base.GetColorValues(); |
||||
|
} |
||||
|
|
||||
|
var uiSettings = NativeWinRTMethods.CreateInstance<IUISettings3>("Windows.UI.ViewManagement.UISettings"); |
||||
|
var accent = uiSettings.GetColorValue(UIColorType.Accent).ToAvalonia(); |
||||
|
|
||||
|
var accessibilitySettings = NativeWinRTMethods.CreateInstance<IAccessibilitySettings>("Windows.UI.ViewManagement.AccessibilitySettings"); |
||||
|
if (accessibilitySettings.HighContrast == 1) |
||||
|
{ |
||||
|
// Windows 11 has 4 different high contrast schemes:
|
||||
|
// - Aquatic - High Contrast Black
|
||||
|
// - Desert - High Contrast White
|
||||
|
// - Dusk - High Contrast #1
|
||||
|
// - Night sky - High Contrast #2
|
||||
|
// Only "Desert" one can be considered a "light" preference.
|
||||
|
using var highContrastScheme = new HStringInterop(accessibilitySettings.HighContrastScheme); |
||||
|
return _lastColorValues = new PlatformColorValues |
||||
|
{ |
||||
|
ThemeVariant = highContrastScheme.Value?.Contains("White") == true ? |
||||
|
PlatformThemeVariant.Light : |
||||
|
PlatformThemeVariant.Dark, |
||||
|
ContrastPreference = ColorContrastPreference.High, |
||||
|
// Windows provides more than one accent color for the HighContrast themes, but with no API for that (at least not in the WinRT)
|
||||
|
AccentColor1 = accent |
||||
|
}; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var background = uiSettings.GetColorValue(UIColorType.Background).ToAvalonia(); |
||||
|
return _lastColorValues = new PlatformColorValues |
||||
|
{ |
||||
|
ThemeVariant = background.R + background.G + background.B < (255 * 3 - background.R - background.G - background.B) ? |
||||
|
PlatformThemeVariant.Dark : |
||||
|
PlatformThemeVariant.Light, |
||||
|
ContrastPreference = ColorContrastPreference.NoPreference, |
||||
|
AccentColor1 = accent |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal void OnColorValuesChanged() |
||||
|
{ |
||||
|
var oldColorValues = _lastColorValues; |
||||
|
var colorValues = GetColorValues(); |
||||
|
|
||||
|
if (oldColorValues != colorValues) |
||||
|
{ |
||||
|
OnColorValuesChanged(colorValues); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Platform; |
||||
|
using Foundation; |
||||
|
using UIKit; |
||||
|
|
||||
|
namespace Avalonia.iOS; |
||||
|
|
||||
|
// TODO: ideally should be created per view/activity.
|
||||
|
internal class PlatformSettings : DefaultPlatformSettings |
||||
|
{ |
||||
|
private PlatformColorValues _lastColorValues; |
||||
|
|
||||
|
public override PlatformColorValues GetColorValues() |
||||
|
{ |
||||
|
var themeVariant = UITraitCollection.CurrentTraitCollection.UserInterfaceStyle == UIUserInterfaceStyle.Dark ? |
||||
|
PlatformThemeVariant.Dark : |
||||
|
PlatformThemeVariant.Light; |
||||
|
|
||||
|
|
||||
|
var contrastPreference = UITraitCollection.CurrentTraitCollection.AccessibilityContrast == UIAccessibilityContrast.High ? |
||||
|
ColorContrastPreference.High : |
||||
|
ColorContrastPreference.NoPreference; |
||||
|
|
||||
|
UIColor? tintColor = null; |
||||
|
if (OperatingSystem.IsIOSVersionAtLeast(14)) |
||||
|
{ |
||||
|
tintColor = UIConfigurationColorTransformer.PreferredTint(UIColor.Clear); |
||||
|
} |
||||
|
|
||||
|
if (tintColor is not null) |
||||
|
{ |
||||
|
tintColor.GetRGBA(out var red, out var green, out var blue, out var alpha); |
||||
|
return _lastColorValues = new PlatformColorValues |
||||
|
{ |
||||
|
ThemeVariant = themeVariant, |
||||
|
ContrastPreference = contrastPreference, |
||||
|
AccentColor1 = new Color( |
||||
|
(byte)(alpha * 255), |
||||
|
(byte)(red * 255), |
||||
|
(byte)(green * 255), |
||||
|
(byte)(blue * 255)) |
||||
|
}; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return _lastColorValues = new PlatformColorValues |
||||
|
{ |
||||
|
ThemeVariant = themeVariant, ContrastPreference = contrastPreference |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void TraitCollectionDidChange() |
||||
|
{ |
||||
|
var oldColorValues = _lastColorValues; |
||||
|
var colorValues = GetColorValues(); |
||||
|
|
||||
|
if (oldColorValues != colorValues) |
||||
|
{ |
||||
|
OnColorValuesChanged(colorValues); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
Loading…
Reference in new issue