committed by
GitHub
549 changed files with 12142 additions and 9792 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,14 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Avalonia.Android |
||||
|
{ |
||||
|
public interface IActivityNavigationService |
||||
|
{ |
||||
|
event EventHandler<AndroidBackRequestedEventArgs> BackRequested; |
||||
|
} |
||||
|
|
||||
|
public class AndroidBackRequestedEventArgs : EventArgs |
||||
|
{ |
||||
|
public bool Handled { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -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,28 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace Avalonia.Android.Platform |
||||
|
{ |
||||
|
internal class AndroidSystemNavigationManager : ISystemNavigationManager |
||||
|
{ |
||||
|
public event EventHandler<RoutedEventArgs> BackRequested; |
||||
|
|
||||
|
public AndroidSystemNavigationManager(IActivityNavigationService? navigationService) |
||||
|
{ |
||||
|
if(navigationService != null) |
||||
|
{ |
||||
|
navigationService.BackRequested += OnBackRequested; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void OnBackRequested(object sender, AndroidBackRequestedEventArgs e) |
||||
|
{ |
||||
|
var routedEventArgs = new RoutedEventArgs(); |
||||
|
|
||||
|
BackRequested?.Invoke(this, routedEventArgs); |
||||
|
|
||||
|
e.Handled = routedEventArgs.Handled; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue