From 3ad11e6867c27225b73f0fb6d2796465a066a4b4 Mon Sep 17 00:00:00 2001 From: Mia Koring Date: Thu, 30 Oct 2025 00:52:20 +0100 Subject: [PATCH 1/2] added .environment modifiers to modify a predefined EnvironmentValue or set a value for an EnvironmentKey --- .../GreetingGeneratorApp.swift | 15 ++++++++++++++- .../SwiftCrossUI/Environment/Environment.swift | 14 ++++++++++++-- .../Environment/EnvironmentValues.swift | 8 ++++++++ .../Views/Modifiers/EnvironmentModifier.swift | 18 ++++++++++++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/Examples/Sources/GreetingGeneratorExample/GreetingGeneratorApp.swift b/Examples/Sources/GreetingGeneratorExample/GreetingGeneratorApp.swift index fa4b984eff..6438069423 100644 --- a/Examples/Sources/GreetingGeneratorExample/GreetingGeneratorApp.swift +++ b/Examples/Sources/GreetingGeneratorExample/GreetingGeneratorApp.swift @@ -29,7 +29,8 @@ struct GreetingGeneratorApp: App { Toggle("Selectable Greeting", active: $isGreetingSelectable) if let latest = greetings.last { - Text(latest) + EnvironmentDisplay() + .environment(key: TestKey.self, value: latest) .padding(.top, 5) .textSelectionEnabled(isGreetingSelectable) @@ -51,3 +52,15 @@ struct GreetingGeneratorApp: App { } } } + +struct EnvironmentDisplay: View { + @Environment(TestKey.self) var value: String? + var body: some View { + Text(value ?? "nil") + } +} + +struct TestKey: EnvironmentKey { + typealias Value = String? + static let defaultValue: Value = nil +} diff --git a/Sources/SwiftCrossUI/Environment/Environment.swift b/Sources/SwiftCrossUI/Environment/Environment.swift index 482dfb25f0..641518a6ae 100644 --- a/Sources/SwiftCrossUI/Environment/Environment.swift +++ b/Sources/SwiftCrossUI/Environment/Environment.swift @@ -36,14 +36,19 @@ /// ``` @propertyWrapper public struct Environment: DynamicProperty { - var keyPath: KeyPath + var keyPath: KeyPath? + var environmentKey: EnvironmentKey.Type? var value: Box public func update( with environment: EnvironmentValues, previousValue: Self? ) { - value.value = environment[keyPath: keyPath] + if let keyPath { + value.value = environment[keyPath: keyPath] + } else if let environmentKey { + value.value = environment[environmentKey] as! Value + } } public var wrappedValue: Value { @@ -63,4 +68,9 @@ public struct Environment: DynamicProperty { self.keyPath = keyPath value = Box(value: nil) } + + public init(_ type: Key.Type) where Value == Key.Value { + self.environmentKey = type + self.value = Box(value: nil) + } } diff --git a/Sources/SwiftCrossUI/Environment/EnvironmentValues.swift b/Sources/SwiftCrossUI/Environment/EnvironmentValues.swift index ffb03d5d94..8922ef82e0 100644 --- a/Sources/SwiftCrossUI/Environment/EnvironmentValues.swift +++ b/Sources/SwiftCrossUI/Environment/EnvironmentValues.swift @@ -221,6 +221,14 @@ public struct EnvironmentValues { environment[keyPath: keyPath] = newValue return environment } + + /// Returns a copy of the environment with the specified key set to the + /// provided new value. + public func with(key: T.Type, value: T.Value) -> Self { + var environment = self + environment[key] = value + return environment + } } /// A key that can be used to extend the environment with new properties. diff --git a/Sources/SwiftCrossUI/Views/Modifiers/EnvironmentModifier.swift b/Sources/SwiftCrossUI/Views/Modifiers/EnvironmentModifier.swift index 801354c213..c3c05a6fcc 100644 --- a/Sources/SwiftCrossUI/Views/Modifiers/EnvironmentModifier.swift +++ b/Sources/SwiftCrossUI/Views/Modifiers/EnvironmentModifier.swift @@ -37,3 +37,21 @@ package struct EnvironmentModifier: View { ) } } + +extension View { + /// Modifies the environment of the View its applied to. + public func environment(key: T.Type, value: T.Value) -> some View { + EnvironmentModifier(self) { environment in + environment.with(key: key, value: value) + } + } + + /// Modifies the environment of the View its applied to + public func environment(_ keyPath: WritableKeyPath, _ newValue: T) + -> some View + { + EnvironmentModifier(self) { environment in + environment.with(keyPath, newValue) + } + } +} From ae7430ecc3785cbe82928080aed8a9740b82c8eb Mon Sep 17 00:00:00 2001 From: Mia Koring Date: Mon, 3 Nov 2025 17:06:56 +0100 Subject: [PATCH 2/2] should fix CI issues caused by different swift version than I apparently use locally --- Sources/SwiftCrossUI/Environment/Environment.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/SwiftCrossUI/Environment/Environment.swift b/Sources/SwiftCrossUI/Environment/Environment.swift index 641518a6ae..9da46992aa 100644 --- a/Sources/SwiftCrossUI/Environment/Environment.swift +++ b/Sources/SwiftCrossUI/Environment/Environment.swift @@ -37,7 +37,7 @@ @propertyWrapper public struct Environment: DynamicProperty { var keyPath: KeyPath? - var environmentKey: EnvironmentKey.Type? + var environmentKey: (any EnvironmentKey.Type)? var value: Box public func update( @@ -47,7 +47,7 @@ public struct Environment: DynamicProperty { if let keyPath { value.value = environment[keyPath: keyPath] } else if let environmentKey { - value.value = environment[environmentKey] as! Value + value.value = (environment[environmentKey] as! Value) } } @@ -55,7 +55,7 @@ public struct Environment: DynamicProperty { guard let value = value.value else { fatalError( """ - Environment value \(keyPath) used before initialization. Don't \ + Environment value \(keyPath.debugDescription) used before initialization. Don't \ use @Environment properties before SwiftCrossUI requests the \ view's body. """