Skip to content

Commit 806de8e

Browse files
committed
Implement DynamicLayoutViewAdaptor
1 parent 143be32 commit 806de8e

File tree

2 files changed

+163
-4
lines changed

2 files changed

+163
-4
lines changed

Sources/OpenSwiftUICore/Data/Util/StrongHash.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import CommonCrypto
1212
#endif
1313

1414
import Foundation
15+
import OpenAttributeGraphShims
1516
import OpenRenderBoxShims
1617

1718
package protocol StronglyHashable {
@@ -149,9 +150,15 @@ package struct StrongHasher {
149150
}
150151

151152
package mutating func combineType(_ type: any Any.Type) {
152-
// let signature = OAGTypeGetSignature
153-
// CC_SHA1_Update(&state, signature, 20)
154-
preconditionFailure("Blocked by latest OAGTypeGetSignature")
153+
let signature = Metadata(type).signature
154+
_ = withUnsafePointer(to: signature.bytes) { ptr in
155+
#if OPENSWIFTUI_SWIFT_CRYPTO
156+
// TODO: Auditd signature API design
157+
_openSwiftUIUnimplementedFailure()
158+
#else
159+
CC_SHA1_Update(&state, ptr, 20)
160+
#endif
161+
}
155162
}
156163
}
157164

Sources/OpenSwiftUICore/Layout/Dynamic/DynamicLayoutView.swift

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,159 @@ private struct DynamicLayoutViewChildGeometry: StatefulRule, AsyncAttribute {
8686
}
8787
}
8888

89-
// TODO: - DynamicLayoutViewAdaptor
89+
// MARK: - DynamicLayoutViewAdaptor [WIP] ContentTransition
90+
91+
struct DynamicLayoutViewAdaptor: DynamicContainerAdaptor {
92+
private struct MakeTransition: TransitionVisitor {
93+
var containerInfo: Attribute<DynamicContainer.Info>
94+
var uniqueId: UInt32
95+
var item: DynamicViewListItem
96+
var inputs: _ViewInputs
97+
var makeElt: (_ViewInputs) -> _ViewOutputs
98+
var outputs: _ViewOutputs?
99+
var isArchived: Bool
100+
101+
mutating func visit<T>(_ transition: T) where T: Transition {
102+
let helper = TransitionHelper(
103+
list: .init(item.list),
104+
info: containerInfo,
105+
uniqueID: uniqueId,
106+
transition: transition,
107+
phase: .identity
108+
)
109+
if isArchived {
110+
makeArchivedTransition(helper: helper)
111+
} else {
112+
let transition = Attribute(
113+
ViewListTransition(helper: helper)
114+
)
115+
let makeElt = self.makeElt
116+
outputs = T.makeView(
117+
view: .init(transition),
118+
inputs: inputs,
119+
body: { _, inputs in
120+
makeElt(inputs)
121+
}
122+
)
123+
}
124+
}
125+
126+
mutating func makeArchivedTransition<T>(helper: TransitionHelper<T>) where T: Transition {
127+
guard helper.transition.hasContentTransition else {
128+
outputs = makeElt(inputs)
129+
return
130+
}
131+
// TODO: archived transition
132+
_openSwiftUIUnimplementedFailure()
133+
}
134+
}
135+
136+
struct ItemLayout {
137+
var release: ViewList.Elements.Release?
138+
}
139+
140+
@Attribute var items: ViewList
141+
@OptionalAttribute var childGeometries: [ViewGeometry]?
142+
var mutateLayoutMap: ((inout DynamicLayoutMap) -> ()) -> ()
143+
144+
func updatedItems() -> ViewList? {
145+
let (items, itemsChanged) = $items.changedValue()
146+
guard itemsChanged else {
147+
return nil
148+
}
149+
return items
150+
}
151+
152+
func foreachItem(
153+
items: any ViewList,
154+
_ body: (DynamicViewListItem) -> Void
155+
) {
156+
var index = 0
157+
items.applySublists(from: &index, list: $items) { sublist in
158+
body(.init(
159+
id: sublist.id,
160+
elements: sublist.elements,
161+
traits: sublist.traits,
162+
list: sublist.list
163+
))
164+
return true
165+
}
166+
}
167+
168+
static func containsItem(
169+
_ items: any ViewList,
170+
_ item: DynamicViewListItem
171+
) -> Bool {
172+
var index = 0
173+
let result = items.applySublists(from: &index, list: nil) { sublist in
174+
sublist.id != item.id
175+
}
176+
return !result
177+
}
178+
179+
func makeItemLayout(
180+
item: DynamicViewListItem,
181+
uniqueId: UInt32,
182+
inputs: _ViewInputs,
183+
containerInfo: Attribute<DynamicContainer.Info>,
184+
containerInputs: (inout _ViewInputs) -> ()
185+
) -> (_ViewOutputs, DynamicLayoutViewAdaptor.ItemLayout) {
186+
let isArchived = inputs.archivedView.isArchived
187+
let traits = item.traits
188+
let transition: AnyTransition?
189+
if let t = traits.optionalTransition(ignoringIdentity: !isArchived) {
190+
let prefersCrossFadeTransitions = Graph.withoutUpdate {
191+
inputs.environment.value.accessibilityPrefersCrossFadeTransitions
192+
}
193+
transition = t.adjustedForAccessibility(prefersCrossFade: prefersCrossFadeTransitions)
194+
} else {
195+
transition = nil
196+
}
197+
var containerID = DynamicContainerID(uniqueId: uniqueId, viewIndex: 0)
198+
let outputs = item.elements.makeAllElements(inputs: inputs) { elementInputs, body in
199+
var elementInputs = elementInputs
200+
if elementInputs.needsGeometry {
201+
let childGeometry = Attribute(
202+
DynamicLayoutViewChildGeometry(
203+
containerInfo: containerInfo,
204+
childGeometries: $childGeometries!,
205+
id: containerID
206+
)
207+
)
208+
elementInputs.size = childGeometry.size()
209+
elementInputs.position = childGeometry.origin()
210+
}
211+
let outputs: _ViewOutputs
212+
if let transition {
213+
var makeTransition = MakeTransition(
214+
containerInfo: containerInfo,
215+
uniqueId: uniqueId,
216+
item: item,
217+
inputs: elementInputs,
218+
makeElt: body,
219+
isArchived: isArchived
220+
)
221+
transition.visitBase(applying: &makeTransition)
222+
outputs = makeTransition.outputs!
223+
} else {
224+
outputs = body(elementInputs)
225+
}
226+
mutateLayoutMap({
227+
$0[containerID] = LayoutProxyAttributes(
228+
layoutComputer: .init(outputs.layoutComputer),
229+
traitsList: .init(item.list)
230+
)
231+
})
232+
containerID.viewIndex &+= 1
233+
return outputs
234+
}
235+
return (outputs ?? .init(), .init(release: item.elements.retain()))
236+
}
237+
238+
func removeItemLayout(uniqueId: UInt32, itemLayout: ItemLayout) {
239+
mutateLayoutMap({ $0.remove(uniqueId: uniqueId)})
240+
}
241+
}
90242

91243
// MARK: - DynamicLayoutComputer
92244

0 commit comments

Comments
 (0)