|
7 | 7 |
|
8 | 8 | package import OpenGraphShims |
9 | 9 |
|
10 | | -// MARK: - PreferenceTransformModifier [6.4.41] [WIP] |
| 10 | +// MARK: - PreferenceTransformModifier [6.4.41] |
11 | 11 |
|
12 | 12 | @available(OpenSwiftUI_v1_0, *) |
13 | 13 | @frozen |
@@ -52,29 +52,114 @@ extension View { |
52 | 52 | } |
53 | 53 | } |
54 | 54 |
|
| 55 | +// MARK: - PreferencesOutputs + makePreferenceTransformer [6.0.87] |
| 56 | + |
55 | 57 | extension PreferencesOutputs { |
56 | 58 | package mutating func makePreferenceTransformer<K>( |
57 | 59 | inputs: PreferencesInputs, |
58 | | - key _: K.Type, |
| 60 | + key: K.Type, |
59 | 61 | transform: @autoclosure () -> Attribute<(inout K.Value) -> Void> |
60 | 62 | ) 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) |
62 | 88 | } |
63 | 89 | } |
64 | 90 |
|
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 { |
67 | 94 | @Attribute var transform: (inout K.Value) -> Void |
68 | 95 | @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 | + } |
69 | 109 | } |
70 | 110 |
|
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 { |
73 | 114 | @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? |
76 | 119 | var keyRequested: Bool |
77 | 120 | var wasEmpty: Bool |
78 | 121 | var delta: UInt32 |
79 | 122 | 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 | + } |
80 | 165 | } |
0 commit comments