Skip to content

Commit 143be32

Browse files
committed
Add Layout.makeDynamicView
1 parent 888e3db commit 143be32

File tree

3 files changed

+195
-20
lines changed

3 files changed

+195
-20
lines changed

Sources/OpenSwiftUICore/Layout/Dynamic/DynamicContainer.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ package struct DynamicContainer {
6060

6161
@inline(__always)
6262
subscript(_ index: Int) -> ItemInfo {
63-
guard index >= 0 && index < items.count else {
64-
preconditionFailure("invalid view index")
65-
}
63+
precondition(index >= 0 && index < items.count, "invalid view index")
6664
return items[index]
6765
}
6866

Sources/OpenSwiftUICore/Layout/Dynamic/DynamicLayoutView.swift

Lines changed: 194 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,98 @@
22
// DynamicLayoutView.swift
33
// OpenSwiftUICore
44
//
5+
// Audited for 6.5.4
56
// Status: WIP
67
// ID: FF3C661D9D8317A1C8FE2B7FD4EDE12C (SwiftUICore)
78

89
import OpenAttributeGraphShims
910

10-
// MARK: - DynamicLayoutComputer
11+
// MARK: - Layout + makeDynamicView
1112

12-
private struct DynamicLayoutComputer<L>: StatefulRule, AsyncAttribute, CustomStringConvertible where L: Layout {
13-
@Attribute
14-
var layout: L
13+
extension Layout {
14+
static func makeDynamicView(
15+
root: _GraphValue<Self>,
16+
inputs: _ViewInputs,
17+
properties: LayoutProperties,
18+
list: Attribute<any ViewList>
19+
) -> _ViewOutputs {
20+
var inputs = inputs
21+
let containsScrollable = inputs.preferences.containsScrollable
22+
let containsScrollTargetRoleContent = inputs.preferences.containsScrollTargetRoleContent
23+
let scrollTargetRole = inputs.scrollTargetRole
24+
let scrollTargetRemovePreference = inputs.scrollTargetRemovePreference
25+
let withinAccessibilityRotor = inputs.withinAccessibilityRotor
26+
27+
// FIXME
28+
var layoutComputer: Attribute<LayoutComputer>!
29+
let childGeometry: Attribute<[ViewGeometry]>?
30+
let needLayout = inputs.requestsLayoutComputer || inputs.needsGeometry
31+
if needLayout || containsScrollable || withinAccessibilityRotor {
32+
layoutComputer = Attribute(
33+
DynamicLayoutComputer(
34+
layout: root.value,
35+
environment: inputs.environment,
36+
containerInfo: .init(),
37+
layoutMap: .init()
38+
)
39+
)
40+
childGeometry = Attribute(
41+
LayoutChildGeometries(
42+
parentSize: inputs.size,
43+
parentPosition: inputs.position,
44+
layoutComputer: layoutComputer
45+
)
46+
)
47+
} else {
48+
childGeometry = nil // .nil here
49+
}
50+
51+
// var context2
52+
var childInputs = inputs
53+
childInputs.requestsLayoutComputer = false
54+
55+
if containsScrollTargetRoleContent && scrollTargetRemovePreference {
56+
inputs.preferences.containsScrollTargetRoleContent = false
57+
inputs.preferences.containsScrollStateRequest = false
58+
}
59+
if let role = scrollTargetRole.attribute {
60+
childInputs.base.scrollTargetRole = .init()
61+
childInputs.base.scrollTargetRemovePreference = true
62+
childInputs.base.setScrollPosition(storage: nil, kind: .scrollContent)
63+
childInputs.base.setScrollPositionAnchor(.init(), kind: .scrollContent)
64+
}
65+
_openSwiftUIUnimplementedFailure()
66+
}
67+
}
68+
69+
// MARK: - DynamicLayoutViewChildGeometry
70+
71+
private struct DynamicLayoutViewChildGeometry: StatefulRule, AsyncAttribute {
72+
@Attribute var containerInfo: DynamicContainer.Info
73+
@Attribute var childGeometries: [ViewGeometry]
74+
let id: DynamicContainerID
75+
76+
typealias Value = ViewGeometry
77+
78+
func updateValue() {
79+
guard let index = containerInfo.viewIndex(id: id), index < childGeometries.count else {
80+
if !hasValue {
81+
value = .zero
82+
}
83+
return
84+
}
85+
value = childGeometries[index]
86+
}
87+
}
88+
89+
// TODO: - DynamicLayoutViewAdaptor
1590

16-
@Attribute
17-
var environment: EnvironmentValues
91+
// MARK: - DynamicLayoutComputer
1892

19-
@OptionalAttribute
20-
var containerInfo: DynamicContainer.Info?
93+
private struct DynamicLayoutComputer<L>: StatefulRule, AsyncAttribute, CustomStringConvertible where L: Layout {
94+
@Attribute var layout: L
95+
@Attribute var environment: EnvironmentValues
96+
@OptionalAttribute var containerInfo: DynamicContainer.Info?
2197

2298
var layoutMap: DynamicLayoutMap
2399

@@ -35,3 +111,113 @@ private struct DynamicLayoutComputer<L>: StatefulRule, AsyncAttribute, CustomStr
35111
"\(L.self) → LayoutComputer"
36112
}
37113
}
114+
115+
// TODO: DynamicLayoutScrollable
116+
117+
struct DynamicLayoutScrollable {}
118+
119+
// TODO: - ViewListContentTransition
120+
121+
// FIXME
122+
struct ContentTransitionEffect {}
123+
124+
private struct ViewListContentTransition<T>: StatefulRule, AsyncAttribute where T: Transition {
125+
var helper: TransitionHelper<T>
126+
@Attribute var size: ViewSize
127+
@Attribute var environment: EnvironmentValues
128+
129+
init(
130+
helper: TransitionHelper<T>,
131+
size: Attribute<ViewSize>,
132+
environment: Attribute<EnvironmentValues>
133+
) {
134+
self.helper = helper
135+
self._size = size
136+
self._environment = environment
137+
}
138+
139+
typealias Value = ContentTransitionEffect
140+
141+
func updateValue() {
142+
_openSwiftUIUnimplementedFailure()
143+
}
144+
}
145+
146+
// MARK: - ViewListArchivedAnimation
147+
148+
private struct ViewListArchivedAnimation: Rule, AsyncAttribute {
149+
struct Effect: _RendererEffect {
150+
var animation: Animation?
151+
var value: StrongHash?
152+
153+
func effectValue(size: CGSize) -> DisplayList.Effect {
154+
guard let value else {
155+
return .identity
156+
}
157+
return .interpolatorAnimation(
158+
.init(
159+
value: value,
160+
animation: animation
161+
)
162+
)
163+
}
164+
}
165+
166+
@OptionalAttribute var traitsList: (any ViewList)?
167+
168+
var value: Effect {
169+
guard let traitsList else {
170+
return .init()
171+
}
172+
guard let trait = traitsList.traits.archivedAnimationTrait else {
173+
return .init()
174+
}
175+
return Effect(animation: trait.animation, value: trait.hash)
176+
}
177+
}
178+
179+
// MARK: - TransitionHelper
180+
181+
private struct TransitionHelper<T> where T: Transition {
182+
@OptionalAttribute var list: (any ViewList)?
183+
@Attribute var info: DynamicContainer.Info
184+
let uniqueID: UInt32
185+
var transition: T
186+
var phase: TransitionPhase
187+
188+
mutating func update() -> Bool {
189+
var changed = false
190+
if let index = info.indexMap[uniqueID] {
191+
let itemInfo = info.items[index]
192+
if let itemPhase = itemInfo.phase {
193+
changed = phase != itemPhase
194+
phase = itemPhase
195+
}
196+
}
197+
guard phase != .didDisappear else {
198+
return changed
199+
}
200+
let traits = list?.traits ?? .init()
201+
traits.transition.base(as: T.self).map {
202+
transition = $0
203+
changed = true
204+
}
205+
return changed
206+
}
207+
}
208+
209+
// MARK: - ViewListTransition
210+
211+
private struct ViewListTransition<T>: StatefulRule, AsyncAttribute where T: Transition {
212+
var helper: TransitionHelper<T>
213+
214+
typealias Value = T.Body
215+
216+
mutating func updateValue() {
217+
let changed = helper.update()
218+
guard changed || !hasValue else {
219+
return
220+
}
221+
value = helper.transition.body(content: .init(), phase: helper.phase)
222+
}
223+
}

Sources/OpenSwiftUICore/Layout/LayoutView.swift

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,6 @@ extension Layout {
167167
return outputs
168168
}
169169
}
170-
171-
static func makeDynamicView(
172-
root: _GraphValue<Self>,
173-
inputs: _ViewInputs,
174-
properties: LayoutProperties,
175-
list: Attribute<any ViewList>
176-
) -> _ViewOutputs {
177-
_openSwiftUIUnimplementedFailure()
178-
}
179170
}
180171

181172
package struct LayoutChildGeometries: Rule, AsyncAttribute {

0 commit comments

Comments
 (0)