1- using System . Threading . Tasks ;
1+ using System ;
2+ using System . Threading . Tasks ;
23
34namespace ElectronNET . API
45{
@@ -32,11 +33,114 @@ internal static NativeTheme Instance
3233 }
3334
3435 /// <summary>
35- /// A `Boolean` for if the OS / Chromium currently has a dark mode enabled or is
36- /// being instructed to show a dark-style UI.If you want to modify this value you
37- /// should use `themeSource` below.
36+ /// Checks if the new ThemeSource is valid.
37+ /// </summary>
38+ /// <param name="themeSource">The new ThemeSource to check.</param>
39+ /// <returns>True, if is a valid ThemeSource.</returns>
40+ internal bool IsValidThemeSource ( string themeSource )
41+ {
42+ var result =
43+ string . Equals ( themeSource , "dark" , StringComparison . OrdinalIgnoreCase ) ||
44+ string . Equals ( themeSource , "light" , StringComparison . OrdinalIgnoreCase ) ||
45+ string . Equals ( themeSource , "system" , StringComparison . OrdinalIgnoreCase ) ;
46+
47+
48+ return result ;
49+ }
50+
51+ /// <summary>
52+ /// Setting this property to 'system' will remove the override and everything will be reset to the OS default. By default 'ThemeSource' is 'system'.
53+ /// <para/>
54+ /// Settings this property to 'dark' will have the following effects:
55+ /// <list type="bullet">
56+ /// <item>
57+ /// <description><see cref="ShouldUseDarkColorsAsync"/> will be <see langword="true"/> when accessed</description>
58+ /// </item>
59+ /// <item>
60+ /// <description>Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the dark UI.</description>
61+ /// </item>
62+ /// <item>
63+ /// <description>Any UI the OS renders on macOS including menus, window frames, etc. will use the dark UI.</description>
64+ /// </item>
65+ /// <item>
66+ /// <description>The 'prefers-color-scheme' CSS query will match 'dark' mode.</description>
67+ /// </item>
68+ /// <item>
69+ /// <description>The 'updated' event will be emitted</description>
70+ /// </item>
71+ /// </list>
72+ /// <para/>
73+ /// Settings this property to 'light' will have the following effects:
74+ /// <list type="bullet">
75+ /// <item>
76+ /// <description><see cref="ShouldUseDarkColorsAsync"/> will be <see langword="false"/> false when accessed</description>
77+ /// </item>
78+ /// <item>
79+ /// <description>Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the light UI.</description>
80+ /// </item>
81+ /// <item>
82+ /// <description>Any UI the OS renders on macOS including menus, window frames, etc. will use the light UI.</description>
83+ /// </item>
84+ /// <item>
85+ /// <description>The 'prefers-color-scheme' CSS query will match 'light' mode.</description>
86+ /// </item>
87+ /// <item>
88+ /// <description>The 'updated' event will be emitted</description>
89+ /// </item>
90+ /// </list>
91+ /// The usage of this property should align with a classic "dark mode" state machine in your application where the user has three options.
92+ /// <para/>
93+ /// <list type="bullet">
94+ /// <item>
95+ /// <description>Follow OS: SetThemeSource("system");</description>
96+ /// </item>
97+ /// <item>
98+ /// <description>Dark Mode: SetThemeSource("dark");</description>
99+ /// </item>
100+ /// <item>
101+ /// <description>Light Mode: SetThemeSource("light");</description>
102+ /// </item>
103+ /// </list>
104+ /// Your application should then always use <see cref="ShouldUseDarkColorsAsync"/> to determine what CSS to apply.
105+ /// </summary>
106+ /// <param name="themeSource">The new ThemeSource.</param>
107+ public void SetThemeSource ( string themeSource )
108+ {
109+ // Check for supported themeSource, otherwise it sets the default
110+ if ( ! IsValidThemeSource ( themeSource ) )
111+ {
112+ themeSource = "system" ;
113+ }
114+
115+ BridgeConnector . Socket . Emit ( "nativeTheme-themeSource" , themeSource . ToLower ( ) ) ;
116+ }
117+
118+ /// <summary>
119+ /// A <see cref="string"/> property that can be 'system', 'light' or 'dark'. It is used to override (<seealso cref="SetThemeSource"/>) and
120+ /// supercede the value that Chromium has chosen to use internally.
38121 /// </summary>
39122 /// <returns></returns>
123+ public Task < string > GetThemeSourceAsync ( )
124+ {
125+ var taskCompletionSource = new TaskCompletionSource < string > ( ) ;
126+
127+ BridgeConnector . Socket . On ( "nativeTheme-themeSource-getCompleted" , ( themeSource ) =>
128+ {
129+ BridgeConnector . Socket . Off ( "nativeTheme-themeSource-getCompleted" ) ;
130+
131+ taskCompletionSource . SetResult ( ( string ) themeSource ) ;
132+ } ) ;
133+
134+ BridgeConnector . Socket . Emit ( "nativeTheme-themeSource-get" ) ;
135+
136+ return taskCompletionSource . Task ;
137+ }
138+
139+ /// <summary>
140+ /// A <see cref="bool"/> for if the OS / Chromium currently has a dark mode enabled or is
141+ /// being instructed to show a dark-style UI.If you want to modify this value you
142+ /// should use 'themeSource' below.
143+ /// </summary>
40144 public Task < bool > ShouldUseDarkColorsAsync ( )
41145 {
42146 var taskCompletionSource = new TaskCompletionSource < bool > ( ) ;
@@ -51,5 +155,75 @@ public Task<bool> ShouldUseDarkColorsAsync()
51155
52156 return taskCompletionSource . Task ;
53157 }
158+
159+ /// <summary>
160+ /// A <see cref="bool"/> for if the OS / Chromium currently has high-contrast mode enabled or is
161+ /// being instructed to show a high-contrast UI.
162+ /// </summary>
163+ public Task < bool > ShouldUseHighContrastColorsAsync ( )
164+ {
165+ var taskCompletionSource = new TaskCompletionSource < bool > ( ) ;
166+
167+ BridgeConnector . Socket . On ( "nativeTheme-shouldUseHighContrastColors-completed" , ( shouldUseHighContrastColors ) => {
168+ BridgeConnector . Socket . Off ( "nativeTheme-shouldUseHighContrastColors-completed" ) ;
169+
170+ taskCompletionSource . SetResult ( ( bool ) shouldUseHighContrastColors ) ;
171+ } ) ;
172+
173+ BridgeConnector . Socket . Emit ( "nativeTheme-shouldUseHighContrastColors" ) ;
174+
175+ return taskCompletionSource . Task ;
176+ }
177+
178+ /// <summary>
179+ /// A <see cref="bool"/> for if the OS / Chromium currently has an inverted color scheme or is
180+ /// being instructed to use an inverted color scheme.
181+ /// </summary>
182+ public Task < bool > ShouldUseInvertedColorSchemeAsync ( )
183+ {
184+ var taskCompletionSource = new TaskCompletionSource < bool > ( ) ;
185+
186+ BridgeConnector . Socket . On ( "nativeTheme-shouldUseInvertedColorScheme-completed" , ( shouldUseInvertedColorScheme ) => {
187+ BridgeConnector . Socket . Off ( "nativeTheme-shouldUseInvertedColorScheme-completed" ) ;
188+
189+ taskCompletionSource . SetResult ( ( bool ) shouldUseInvertedColorScheme ) ;
190+ } ) ;
191+
192+ BridgeConnector . Socket . Emit ( "nativeTheme-shouldUseInvertedColorScheme" ) ;
193+
194+ return taskCompletionSource . Task ;
195+ }
196+
197+ /// <summary>
198+ /// Emitted when something in the underlying NativeTheme has changed. This normally means that either the value of <see cref="ShouldUseDarkColorsAsync"/>,
199+ /// <see cref="ShouldUseHighContrastColorsAsync"/> or <see cref="ShouldUseInvertedColorSchemeAsync"/> has changed. You will have to check them to determine which one has changed.
200+ /// </summary>
201+ public event Action Updated
202+ {
203+ add
204+ {
205+ if ( _updated == null )
206+ {
207+ BridgeConnector . Socket . On ( "nativeTheme-updated" + GetHashCode ( ) , ( ) =>
208+ {
209+ _updated ( ) ;
210+ } ) ;
211+
212+ BridgeConnector . Socket . Emit ( "register-nativeTheme-updated-event" , GetHashCode ( ) ) ;
213+ }
214+ _updated += value ;
215+ }
216+ remove
217+ {
218+ _updated -= value ;
219+
220+ if ( _updated == null )
221+ {
222+ BridgeConnector . Socket . Off ( "nativeTheme-updated" + GetHashCode ( ) ) ;
223+ }
224+ }
225+ }
226+
227+ private event Action _updated ;
54228 }
55229}
0 commit comments