Skip to content

Commit 05d48cd

Browse files
authored
Update ColorScheme (#165)
1 parent 2bb0f9d commit 05d48cd

File tree

3 files changed

+268
-37
lines changed

3 files changed

+268
-37
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// EnvironmentModifier.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for iOS 18.0
6+
// Status: TODO
7+
8+
package import OpenGraphShims
9+
10+
package protocol EnvironmentModifier: _GraphInputsModifier {
11+
static func makeEnvironment(modifier: Attribute<Self>, environment: inout EnvironmentValues)
12+
}
13+
14+
extension EnvironmentModifier {
15+
package static func _makeInputs(modifier: _GraphValue<Self>, inputs: inout _GraphInputs) {
16+
preconditionFailure("TODO")
17+
}
18+
}

Sources/OpenSwiftUICore/Graphic/Color/ColorSchema.swift

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
//
2+
// ColorScheme.swift
3+
// OpenSwiftUI
4+
//
5+
// Audited for iOS 18.0
6+
// Status: Complete
7+
// ID: 387C753F3FFD2899BCB77252214CFCC6 (SwiftUI)
8+
// ID: 0E72AB1FBE33AED1E73FF06F3DA3A071 (SwiftUICore)
9+
10+
package import OpenGraphShims
11+
12+
// MARK: - ColorScheme
13+
14+
/// The possible color schemes, corresponding to the light and dark appearances.
15+
///
16+
/// You receive a color scheme value when you read the
17+
/// ``EnvironmentValues/colorScheme`` environment value. The value tells you if
18+
/// a light or dark appearance currently applies to the view. OpenSwiftUI updates
19+
/// the value whenever the appearance changes, and redraws views that
20+
/// depend on the value. For example, the following ``Text`` view automatically
21+
/// updates when the user enables Dark Mode:
22+
///
23+
/// @Environment(\.colorScheme) private var colorScheme
24+
///
25+
/// var body: some View {
26+
/// Text(colorScheme == .dark ? "Dark" : "Light")
27+
/// }
28+
///
29+
/// Set a preferred appearance for a particular view hierarchy to override
30+
/// the user's Dark Mode setting using the ``View/preferredColorScheme(_:)``
31+
/// view modifier.
32+
public enum ColorScheme: CaseIterable, Sendable {
33+
/// The color scheme that corresponds to a light appearance.
34+
case light
35+
36+
/// The color scheme that corresponds to a dark appearance.
37+
case dark
38+
}
39+
40+
// MARK: - ColorSchemeContrast
41+
42+
/// The contrast between the app's foreground and background colors.
43+
///
44+
/// You receive a contrast value when you read the
45+
/// ``EnvironmentValues/colorSchemeContrast`` environment value. The value
46+
/// tells you if a standard or increased contrast currently applies to the view.
47+
/// OpenSwiftUI updates the value whenever the contrast changes, and redraws
48+
/// views that depend on the value. For example, the following ``Text`` view
49+
/// automatically updates when the user enables increased contrast:
50+
///
51+
/// @Environment(\.colorSchemeContrast) private var colorSchemeContrast
52+
///
53+
/// var body: some View {
54+
/// Text(colorSchemeContrast == .standard ? "Standard" : "Increased")
55+
/// }
56+
///
57+
/// The user sets the contrast by selecting the Increase Contrast option in
58+
/// Accessibility > Display in System Preferences on macOS, or
59+
/// Accessibility > Display & Text Size in the Settings app on iOS.
60+
/// Your app can't override the user's choice. For
61+
/// information about using color and contrast in your app, see
62+
/// [Accessibility](https://developer.apple.com/design/human-interface-guidelines/accessibility#Color-and-effects).
63+
/// in the Human Interface Guidelines.
64+
public enum ColorSchemeContrast: CaseIterable, Sendable {
65+
66+
/// OpenSwiftUI displays views with standard contrast between the app's
67+
/// foreground and background colors.
68+
case standard
69+
70+
/// OpenSwiftUI displays views with increased contrast between the app's
71+
/// foreground and background colors.
72+
case increased
73+
}
74+
75+
// MARK: - View + ColorScheme
76+
77+
extension View {
78+
/// Sets this view's color scheme.
79+
///
80+
/// Use `colorScheme(_:)` to set the color scheme for the view to which you
81+
/// apply it and any subviews. If you want to set the color scheme for all
82+
/// views in the presentation, use ``View/preferredColorScheme(_:)``
83+
/// instead.
84+
///
85+
/// - Parameter colorScheme: The color scheme for this view.
86+
///
87+
/// - Returns: A view that sets this view's color scheme.
88+
@inlinable
89+
nonisolated public func colorScheme(_ colorScheme: ColorScheme) -> some View {
90+
environment(\.colorScheme, colorScheme)
91+
}
92+
}
93+
94+
// MARK: - ColorScheme + EnvironmentValues
95+
96+
extension EnvironmentValues {
97+
/// The color scheme of this environment.
98+
///
99+
/// Read this environment value from within a view to find out if OpenSwiftUI
100+
/// is currently displaying the view using the ``ColorScheme/light`` or
101+
/// ``ColorScheme/dark`` appearance. The value that you receive depends on
102+
/// whether the user has enabled Dark Mode, possibly superseded by
103+
/// the configuration of the current presentation's view hierarchy.
104+
///
105+
/// @Environment(\.colorScheme) private var colorScheme
106+
///
107+
/// var body: some View {
108+
/// Text(colorScheme == .dark ? "Dark" : "Light")
109+
/// }
110+
///
111+
/// You can set the `colorScheme` environment value directly,
112+
/// but that usually isn't what you want. Doing so changes the color
113+
/// scheme of the given view and its child views but *not* the views
114+
/// above it in the view hierarchy. Instead, set a color scheme using the
115+
/// ``View/preferredColorScheme(_:)`` modifier, which also propagates the
116+
/// value up through the view hierarchy to the enclosing presentation, like
117+
/// a sheet or a window.
118+
///
119+
/// When adjusting your app's user interface to match the color scheme,
120+
/// consider also checking the ``EnvironmentValues/colorSchemeContrast``
121+
/// property, which reflects a system-wide contrast setting that the user
122+
/// controls. For information, see
123+
/// [Accessibility](https://developer.apple.com/design/human-interface-guidelines/accessibility#Color-and-effects).
124+
/// in the Human Interface Guidelines.
125+
///
126+
/// > Note: If you only need to provide different colors or
127+
/// images for different color scheme and contrast settings, do that in
128+
/// your app's Asset Catalog. See
129+
/// [Asset management](https://developer.apple.com/documentation/xcode/asset-management).
130+
public var colorScheme: ColorScheme {
131+
get { self[ColorSchemeKey.self] }
132+
set { self[ColorSchemeKey.self] = newValue }
133+
}
134+
135+
package var explicitPreferredColorScheme: ColorScheme? {
136+
get { self[ExplicitPreferredColorSchemeKey.self] }
137+
set { self[ExplicitPreferredColorSchemeKey.self] = newValue }
138+
}
139+
140+
package var systemColorScheme: ColorScheme {
141+
get { self[SystemColorSchemeKey.self] }
142+
set { self[SystemColorSchemeKey.self] = newValue }
143+
}
144+
145+
/// The contrast associated with the color scheme of this environment.
146+
///
147+
/// Read this environment value from within a view to find out if OpenSwiftUI
148+
/// is currently displaying the view using ``ColorSchemeContrast/standard``
149+
/// or ``ColorSchemeContrast/increased`` contrast. The value that you read
150+
/// depends entirely on user settings, and you can't change it.
151+
///
152+
/// @Environment(\.colorSchemeContrast) private var colorSchemeContrast
153+
///
154+
/// var body: some View {
155+
/// Text(colorSchemeContrast == .standard ? "Standard" : "Increased")
156+
/// }
157+
///
158+
/// When adjusting your app's user interface to match the contrast,
159+
/// consider also checking the ``EnvironmentValues/colorScheme`` property
160+
/// to find out if OpenSwiftUI is displaying the view with a light or dark
161+
/// appearance. For information, see
162+
/// [Accessibility](https://developer.apple.com/design/human-interface-guidelines/accessibility#Color-and-effects).
163+
/// in the Human Interface Guidelines.
164+
///
165+
/// > Note: If you only need to provide different colors or
166+
/// images for different color scheme and contrast settings, do that in
167+
/// your app's Asset Catalog. See
168+
/// [Asset management](https://developer.apple.com/documentation/xcode/asset-management).
169+
public var colorSchemeContrast: ColorSchemeContrast {
170+
self[ColorSchemeContrastKey.self]
171+
}
172+
173+
public var _colorSchemeContrast: ColorSchemeContrast {
174+
get { self[ColorSchemeContrastKey.self] }
175+
set { self[ColorSchemeContrastKey.self] = newValue }
176+
}
177+
}
178+
179+
private struct ColorSchemeKey: EnvironmentKey {
180+
static let defaultValue: ColorScheme = .light
181+
}
182+
183+
private struct SystemColorSchemeKey: EnvironmentKey {
184+
static let defaultValue: ColorScheme = .light
185+
}
186+
187+
private struct ExplicitPreferredColorSchemeKey: EnvironmentKey {
188+
static let defaultValue: ColorScheme? = nil
189+
}
190+
191+
private struct ColorSchemeContrastKey: EnvironmentKey {
192+
static var defaultValue: ColorSchemeContrast = .standard
193+
}
194+
195+
// MARK: - SystemColorSchemeModifier
196+
197+
@MainActor
198+
@preconcurrency
199+
package struct SystemColorSchemeModifier: ViewModifier, PrimitiveViewModifier, EnvironmentModifier {
200+
package var isEnabled: Bool
201+
202+
package init(isEnabled: Bool) {
203+
self.isEnabled = isEnabled
204+
}
205+
206+
nonisolated package static func makeEnvironment(modifier: Attribute<SystemColorSchemeModifier>, environment: inout EnvironmentValues) {
207+
guard modifier.value.isEnabled else { return }
208+
environment.colorScheme = environment.systemColorScheme
209+
}
210+
211+
package typealias Body = Never
212+
}
213+
214+
// MARK: - ColorScheme + ProtobufEnum
215+
216+
extension ColorScheme: ProtobufEnum {
217+
package var protobufValue: UInt {
218+
switch self {
219+
case .light: return 0
220+
case .dark: return 1
221+
}
222+
}
223+
224+
package init?(protobufValue: UInt) {
225+
switch protobufValue {
226+
case 0: self = .light
227+
case 1: self = .dark
228+
default: return nil
229+
}
230+
}
231+
}
232+
233+
// MARK: - ColorSchemeContrast + ProtobufEnum
234+
235+
extension ColorSchemeContrast: ProtobufEnum {
236+
package var protobufValue: UInt {
237+
switch self {
238+
case .standard: return 0
239+
case .increased: return 1
240+
}
241+
}
242+
243+
package init?(protobufValue: UInt) {
244+
switch protobufValue {
245+
case 0: self = .standard
246+
case 1: self = .increased
247+
default: return nil
248+
}
249+
}
250+
}

0 commit comments

Comments
 (0)