11using System ;
22using System . ComponentModel ;
33using System . IO ;
4- using System . Windows ;
54using System . Windows . Media ;
6- using Microsoft . Win32 ;
75using Newtonsoft . Json ;
6+ using DesktopClock . Utilities ;
87using WpfWindowPlacement ;
98
109namespace DesktopClock . Properties ;
1110
1211public sealed class Settings : INotifyPropertyChanged , IDisposable
1312{
1413 private readonly FileSystemWatcher _watcher ;
15- private bool _followSystemTheme ;
16- private bool _systemThemeIsLight = true ;
17- private Color _systemAccentColor = DefaultAccentColor ;
18- private Color _textColor = Color . FromRgb ( 33 , 33 , 33 ) ;
19- private Color _outerColor = Color . FromRgb ( 247 , 247 , 247 ) ;
2014
2115 private static readonly Lazy < Settings > _default = new ( LoadAndAttemptSave ) ;
2216
@@ -32,12 +26,6 @@ public sealed class Settings : INotifyPropertyChanged, IDisposable
3226 public static readonly double MaxSizeLog = 6.5 ;
3327
3428 public static readonly double MinSizeLog = 2.7 ;
35- private static readonly Color DefaultAccentColor = Color . FromRgb ( 0 , 120 , 215 ) ;
36- private static readonly Color LightThemeOuterColor = Color . FromRgb ( 247 , 247 , 247 ) ;
37- private static readonly Color DarkThemeOuterColor = Color . FromRgb ( 32 , 32 , 32 ) ;
38- private const string PersonalizeKeyPath = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" ;
39- private const string AppsUseLightThemeValueName = "AppsUseLightTheme" ;
40-
4129 static Settings ( )
4230 {
4331 // Settings file path from the same directory as the executable.
@@ -54,10 +42,6 @@ private Settings()
5442 EnableRaisingEvents = true ,
5543 } ;
5644 _watcher . Changed += FileChanged ;
57-
58- RefreshSystemThemeColors ( notifyIfFollowing : false ) ;
59- SystemEvents . UserPreferenceChanged += SystemEvents_UserPreferenceChanged ;
60- SystemParameters . StaticPropertyChanged += SystemParameters_StaticPropertyChanged ;
6145 }
6246
6347#pragma warning disable CS0067 // The event 'Settings.PropertyChanged' is never used. Handled by Fody.
@@ -138,19 +122,7 @@ private Settings()
138122 /// <summary>
139123 /// Text color for the clock's text.
140124 /// </summary>
141- public Color TextColor
142- {
143- get => _textColor ;
144- set
145- {
146- if ( _textColor . Equals ( value ) )
147- return ;
148-
149- _textColor = value ;
150- NotifyPropertyChanged ( nameof ( TextColor ) ) ;
151- NotifyEffectiveThemeChanged ( ) ;
152- }
153- }
125+ public Color TextColor { get ; set ; } = Color . FromRgb ( 33 , 33 , 33 ) ;
154126
155127 /// <summary>
156128 /// Opacity of the text.
@@ -160,51 +132,7 @@ public Color TextColor
160132 /// <summary>
161133 /// The outer color, for either the background or the outline.
162134 /// </summary>
163- public Color OuterColor
164- {
165- get => _outerColor ;
166- set
167- {
168- if ( _outerColor . Equals ( value ) )
169- return ;
170-
171- _outerColor = value ;
172- NotifyPropertyChanged ( nameof ( OuterColor ) ) ;
173- NotifyEffectiveThemeChanged ( ) ;
174- }
175- }
176-
177- /// <summary>
178- /// Follow the system theme and accent color.
179- /// </summary>
180- public bool FollowSystemTheme
181- {
182- get => _followSystemTheme ;
183- set
184- {
185- if ( _followSystemTheme == value )
186- return ;
187-
188- _followSystemTheme = value ;
189- NotifyPropertyChanged ( nameof ( FollowSystemTheme ) ) ;
190- RefreshSystemThemeColors ( notifyIfFollowing : false ) ;
191- NotifyEffectiveThemeChanged ( ) ;
192- }
193- }
194-
195- /// <summary>
196- /// Effective text color based on theme-following preference.
197- /// </summary>
198- [ JsonIgnore ]
199- public Color EffectiveTextColor => FollowSystemTheme ? _systemAccentColor : TextColor ;
200-
201- /// <summary>
202- /// Effective outer color based on theme-following preference.
203- /// </summary>
204- [ JsonIgnore ]
205- public Color EffectiveOuterColor => FollowSystemTheme
206- ? ( _systemThemeIsLight ? LightThemeOuterColor : DarkThemeOuterColor )
207- : OuterColor ;
135+ public Color OuterColor { get ; set ; } = Color . FromRgb ( 247 , 247 , 247 ) ;
208136
209137 /// <summary>
210138 /// Shows a solid background instead of an outline.
@@ -421,6 +349,11 @@ private static Settings LoadAndAttemptSave()
421349 {
422350 var settings = LoadFromFile ( ) ;
423351
352+ if ( ! File . Exists ( FilePath ) )
353+ {
354+ settings . ApplySystemThemeDefaultsIfAvailable ( ) ;
355+ }
356+
424357 CanBeSaved = settings . Save ( ) ;
425358
426359 return settings ;
@@ -454,82 +387,13 @@ public void ScaleHeight(double steps)
454387 Height = ( int ) exp ;
455388 }
456389
457- private void SystemEvents_UserPreferenceChanged ( object sender , UserPreferenceChangedEventArgs e )
390+ private void ApplySystemThemeDefaultsIfAvailable ( )
458391 {
459- if ( ! FollowSystemTheme )
392+ if ( ! SystemThemeService . TryGetThemeDefaults ( out var textColor , out var outerColor ) )
460393 return ;
461394
462- if ( e . Category == UserPreferenceCategory . General ||
463- e . Category == UserPreferenceCategory . Color ||
464- e . Category == UserPreferenceCategory . VisualStyle )
465- {
466- RefreshSystemThemeColors ( notifyIfFollowing : true ) ;
467- }
468- }
469-
470- private void SystemParameters_StaticPropertyChanged ( object sender , PropertyChangedEventArgs e )
471- {
472- if ( ! FollowSystemTheme )
473- return ;
474-
475- if ( e . PropertyName == nameof ( SystemParameters . WindowGlassColor ) )
476- {
477- RefreshSystemThemeColors ( notifyIfFollowing : true ) ;
478- }
479- }
480-
481- private void RefreshSystemThemeColors ( bool notifyIfFollowing )
482- {
483- var dispatcher = Application . Current ? . Dispatcher ;
484- if ( dispatcher != null && ! dispatcher . CheckAccess ( ) )
485- {
486- dispatcher . BeginInvoke ( new Action ( ( ) => RefreshSystemThemeColors ( notifyIfFollowing ) ) ) ;
487- return ;
488- }
489-
490- var isLightTheme = GetSystemThemeIsLight ( ) ;
491- var accentColor = GetSystemAccentColor ( ) ;
492- var themeChanged = isLightTheme != _systemThemeIsLight ;
493- var accentChanged = ! _systemAccentColor . Equals ( accentColor ) ;
494-
495- _systemThemeIsLight = isLightTheme ;
496- _systemAccentColor = accentColor ;
497-
498- if ( notifyIfFollowing && ( themeChanged || accentChanged ) && FollowSystemTheme )
499- {
500- NotifyEffectiveThemeChanged ( ) ;
501- }
502- }
503-
504- private static bool GetSystemThemeIsLight ( )
505- {
506- var value = Registry . GetValue ( PersonalizeKeyPath , AppsUseLightThemeValueName , 1 ) ;
507- return value switch
508- {
509- int intValue => intValue > 0 ,
510- byte byteValue => byteValue > 0 ,
511- _ => true ,
512- } ;
513- }
514-
515- private static Color GetSystemAccentColor ( )
516- {
517- var accent = SystemParameters . WindowGlassColor ;
518- if ( accent . A == 0 )
519- return DefaultAccentColor ;
520-
521- return Color . FromArgb ( 255 , accent . R , accent . G , accent . B ) ;
522- }
523-
524- private void NotifyEffectiveThemeChanged ( )
525- {
526- NotifyPropertyChanged ( nameof ( EffectiveTextColor ) ) ;
527- NotifyPropertyChanged ( nameof ( EffectiveOuterColor ) ) ;
528- }
529-
530- private void NotifyPropertyChanged ( string propertyName )
531- {
532- PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( propertyName ) ) ;
395+ TextColor = textColor ;
396+ OuterColor = outerColor ;
533397 }
534398
535399 public void Dispose ( )
0 commit comments