33// OpenSwiftUICore
44//
55// Audited for 6.5.4
6- // Status: WIP
6+ // Status: Blocked by Image
77// ID: 18671928047E57F039DC339288B6FAFB (SwiftUICore)
88
9+ // MARK: - RedactionReasons
10+
11+ /// The reasons to apply a redaction to data displayed on screen.
12+ @available ( OpenSwiftUI_v2_0, * )
13+ public struct RedactionReasons : OptionSet , Sendable {
14+ public let rawValue : Int
15+
16+ public init ( rawValue: Int ) {
17+ self . rawValue = rawValue
18+ }
19+
20+ /// Displayed data should appear as generic placeholders.
21+ ///
22+ /// Text and images will be automatically masked to appear as
23+ /// generic placeholders, though maintaining their original size and shape.
24+ /// Use this to create a placeholder UI without directly exposing
25+ /// placeholder data to users.
26+ public static let placeholder : RedactionReasons = . init( rawValue: 1 << 0 )
27+
28+ /// Displayed data should be obscured to protect private information.
29+ ///
30+ /// Views marked with `privacySensitive` will be automatically redacted
31+ /// using a standard styling. To apply a custom treatment the redaction
32+ /// reason can be read out of the environment.
33+ ///
34+ /// struct BankingContentView: View {
35+ /// @Environment(\.redactionReasons) var redactionReasons
36+ ///
37+ /// var body: some View {
38+ /// if redactionReasons.contains(.privacy) {
39+ /// FullAppCover()
40+ /// } else {
41+ /// AppContent()
42+ /// }
43+ /// }
44+ /// }
45+ @available ( OpenSwiftUI_v3_0, * )
46+ public static let privacy : RedactionReasons = . init( rawValue: 1 << 1 )
47+
48+ /// Displayed data should appear as invalidated and pending a new update.
49+ ///
50+ /// Views marked with `invalidatableContent` will be automatically
51+ /// redacted with a standard styling indicating the content is invalidated
52+ /// and new content will be available soon.
53+ @available ( OpenSwiftUI_v5_0, * )
54+ public static let invalidated : RedactionReasons = . init( rawValue: 1 << 2 )
55+
56+ @_spi ( Private)
57+ @available ( OpenSwiftUI_v6_0, * )
58+ public static let screencaptureProhibited : RedactionReasons = . init( rawValue: 1 << 3 )
59+ }
60+
61+ // MARK: - View + redacted
62+
63+ @available ( OpenSwiftUI_v2_0, * )
64+ extension View {
65+
66+ /// Adds a reason to apply a redaction to this view hierarchy.
67+ ///
68+ /// Adding a redaction is an additive process: any redaction
69+ /// provided will be added to the reasons provided by the parent.
70+ nonisolated public func redacted( reason: RedactionReasons ) -> some View {
71+ transformEnvironment ( \. redactionReasons) {
72+ $0. insert ( reason)
73+ }
74+ }
75+
76+ /// Removes any reason to apply a redaction to this view hierarchy.
77+ nonisolated public func unredacted( ) -> some View {
78+ environment ( \. redactionReasons, [ ] )
79+ }
80+ }
81+
982// MARK: - EnvironmentValues + RedactionReasons
1083
11- // TODO
84+ private struct RedactionReasonsKey : EnvironmentKey {
85+ static let defaultValue : RedactionReasons = [ ]
86+ }
87+
1288private struct ShouldRedactContentKey : DerivedEnvironmentKey {
1389 static func value( in environment: EnvironmentValues ) -> Bool {
14- // redaction
15- false
90+ let redactionReasons = environment. redactionReasons
91+ if redactionReasons. contains ( . placeholder) {
92+ return true
93+ } else if redactionReasons. contains ( . privacy) {
94+ return environment. sensitiveContent
95+ } else {
96+ return false
97+ }
98+ }
99+ }
100+
101+ private struct UnredactSymbolImage : EnvironmentKey {
102+ static let defaultValue : Bool = false
103+ }
104+
105+ private struct ShouldRedactSymbolImagesKey : DerivedEnvironmentKey {
106+ static func value( in environment: EnvironmentValues ) -> Bool {
107+ guard environment. shouldRedactContent else {
108+ return false
109+ }
110+ return !environment. unredactSymbolImage
16111 }
17112}
18113
@@ -21,3 +116,41 @@ extension EnvironmentValues {
21116 self [ ShouldRedactContentKey . self]
22117 }
23118}
119+
120+ @_spi ( Private)
121+ @available ( OpenSwiftUI_v6_0, * )
122+ extension EnvironmentValues {
123+
124+ public var unredactSymbolImage : Bool {
125+ get { self [ UnredactSymbolImage . self] }
126+ set { self [ UnredactSymbolImage . self] = newValue }
127+ }
128+
129+ package var shouldRedactSymbolImages : Bool {
130+ self [ ShouldRedactSymbolImagesKey . self]
131+ }
132+ }
133+
134+ @available ( OpenSwiftUI_v2_0, * )
135+ extension EnvironmentValues {
136+
137+ /// The current redaction reasons applied to the view hierarchy.
138+ public var redactionReasons : RedactionReasons {
139+ get { self [ RedactionReasonsKey . self] }
140+ set { self [ RedactionReasonsKey . self] = newValue }
141+ }
142+ }
143+
144+ // MARK: - Image + redacted [TODO]
145+
146+ extension GraphicsImage {
147+ package mutating func redact( in environment: EnvironmentValues ) {
148+ _openSwiftUIUnimplementedFailure ( )
149+ }
150+ }
151+
152+ extension Image {
153+ package static let redacted : Image = {
154+ _openSwiftUIUnimplementedFailure ( )
155+ } ( )
156+ }
0 commit comments