Skip to content

Commit 23632a0

Browse files
committed
Implement makePreferenceTransformer API
1 parent 4190920 commit 23632a0

File tree

5 files changed

+106
-17
lines changed

5 files changed

+106
-17
lines changed

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,8 @@ extension _UIHostingView: ViewRendererHost {
684684
}
685685

686686
package func rootTransform() -> ViewTransform {
687-
preconditionFailure("TODO")
687+
openSwiftUIUnimplementedWarning()
688+
return ViewTransform()
688689
}
689690

690691
public func preferencesDidChange() {

Sources/OpenSwiftUICore/Data/Preference/PreferenceTransformModifier.swift

Lines changed: 94 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
package import OpenGraphShims
99

10-
// MARK: - PreferenceTransformModifier [6.4.41] [WIP]
10+
// MARK: - PreferenceTransformModifier [6.4.41]
1111

1212
@available(OpenSwiftUI_v1_0, *)
1313
@frozen
@@ -52,29 +52,114 @@ extension View {
5252
}
5353
}
5454

55+
// MARK: - PreferencesOutputs + makePreferenceTransformer [6.0.87]
56+
5557
extension PreferencesOutputs {
5658
package mutating func makePreferenceTransformer<K>(
5759
inputs: PreferencesInputs,
58-
key _: K.Type,
60+
key: K.Type,
5961
transform: @autoclosure () -> Attribute<(inout K.Value) -> Void>
6062
) where K: PreferenceKey {
61-
openSwiftUIUnimplementedWarning()
63+
let contains = inputs.contains(K.self)
64+
let transformValue: Attribute<(inout K.Value) -> Void>!
65+
if contains {
66+
transformValue = transform()
67+
let transform = PreferenceTransform<K>(
68+
transform: transformValue,
69+
childValue: OptionalAttribute(self[key])
70+
)
71+
self[key] = Attribute(transform)
72+
} else {
73+
transformValue = nil
74+
}
75+
guard K._isReadableByHost, inputs.contains(HostPreferencesKey.self) else {
76+
return
77+
}
78+
let hostTransform = HostPreferencesTransform<K>(
79+
transform: transformValue ?? transform(),
80+
keys: inputs.hostKeys,
81+
childValues: OptionalAttribute(self[HostPreferencesKey.self]),
82+
keyRequested: false,
83+
wasEmpty: false,
84+
delta: 0,
85+
nodeId: HostPreferencesKey.makeNodeId()
86+
)
87+
self[HostPreferencesKey.self] = Attribute(hostTransform)
6288
}
6389
}
6490

65-
// TODO
66-
private struct PreferenceTransform<K> where K: PreferenceKey {
91+
// MARK: - PreferenceTransform [6.0.87]
92+
93+
private struct PreferenceTransform<K>: Rule, AsyncAttribute, CustomStringConvertible where K: PreferenceKey {
6794
@Attribute var transform: (inout K.Value) -> Void
6895
@OptionalAttribute var childValue: K.Value?
96+
97+
var value: K.Value {
98+
var value = childValue ?? K.defaultValue
99+
$transform.syncMainIfReferences { transform in
100+
// TODO: Observation support
101+
transform(&value)
102+
}
103+
return value
104+
}
105+
106+
var description: String {
107+
"Transform: \(K.readableName)"
108+
}
69109
}
70110

71-
// TODO
72-
private struct HostPreferencesTransform<K> where K: PreferenceKey {
111+
// MARK: - HostPreferencesTransform [6.0.87]
112+
113+
private struct HostPreferencesTransform<K>: StatefulRule, AsyncAttribute, CustomStringConvertible where K: PreferenceKey {
73114
@Attribute var transform: (inout K.Value) -> Void
74-
@Attribute var keys: Attribute<PreferenceKeys>
75-
@OptionalAttribute var childValues: PreferenceValues?
115+
@Attribute var keys: PreferenceKeys
116+
// FIXME: [6.4.41]
117+
// @OptionalAttribute var childValues: PreferenceValues?
118+
@OptionalAttribute var childValues: PreferenceList?
76119
var keyRequested: Bool
77120
var wasEmpty: Bool
78121
var delta: UInt32
79122
let nodeId: UInt32
123+
124+
typealias Value = PreferenceList
125+
126+
mutating func updateValue() {
127+
var values: PreferenceList
128+
let valuesChanged: Bool
129+
if let childValues = $childValues {
130+
(values, valuesChanged) = childValues.changedValue()
131+
wasEmpty = false
132+
} else {
133+
(values, valuesChanged) = (PreferenceList(), !wasEmpty)
134+
wasEmpty = true
135+
}
136+
var requiresUpdate = valuesChanged
137+
let (keys, keysChanged) = $keys.changedValue()
138+
139+
let keyContains = keysChanged ? keys.contains(K.self) : false
140+
if keyRequested != keyContains {
141+
keyRequested = keyContains
142+
requiresUpdate = true
143+
}
144+
if keyRequested {
145+
let anyInputsChanged = [_keys.identifier, _childValues.base.identifier].anyInputsChanged
146+
if anyInputsChanged {
147+
delta &+= 1
148+
requiresUpdate = true
149+
}
150+
if anyInputsChanged || requiresUpdate {
151+
$transform.syncMainIfReferences { transform in
152+
let transformValue = PreferenceList.Value(value: transform, seed: VersionSeed(nodeId: nodeId, viewSeed: delta))
153+
values.modifyValue(for: K.self, transform: transformValue)
154+
}
155+
}
156+
}
157+
if requiresUpdate || !hasValue {
158+
value = values
159+
}
160+
}
161+
162+
var description: String {
163+
"HostTransform: \(K.readableName)"
164+
}
80165
}

Sources/OpenSwiftUICore/Data/Preference/PreferencesInputs.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,11 @@ package struct PreferencesInputs {
3434

3535
@inlinable
3636
package func contains<K>(_ key: K.Type, includeHostPreferences: Bool) -> Bool where K: PreferenceKey {
37-
let result = keys.contains(key)
37+
let result = contains(key)
3838
guard !result, includeHostPreferences else {
3939
return result
4040
}
41-
guard K._isReadableByHost else {
42-
return false
43-
}
44-
return keys.contains(_AnyPreferenceKey<HostPreferencesKey>.self)
41+
return K._isReadableByHost && contains(HostPreferencesKey.self)
4542
}
4643

4744
package func makeIndirectOutputs() -> PreferencesOutputs {

Sources/OpenSwiftUICore/OpenGraph/Attribute/AnyAttributeFix.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,10 @@ extension Rule where Self: Hashable {
173173
preconditionFailure("#39")
174174
}
175175
}
176+
177+
extension [AnyAttribute] {
178+
package var anyInputsChanged: Bool {
179+
false
180+
}
181+
}
176182
#endif

0 commit comments

Comments
 (0)