Skip to content

Commit 21945b8

Browse files
committed
Implement eraseItem
1 parent a83e062 commit 21945b8

File tree

1 file changed

+51
-22
lines changed

1 file changed

+51
-22
lines changed

Sources/OpenSwiftUICore/Layout/Dynamic/DynamicContainer.swift

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ private struct DynamicPreferenceCombiner<K>: Rule, AsyncAttribute, CustomStringC
239239
}
240240
}
241241

242-
// MARK: - DynamicContainerInfo [WIP]
242+
// MARK: - DynamicContainerInfo
243243

244244
struct DynamicContainerInfo<Adapter>: StatefulRule, AsyncAttribute, ObservedAttribute, CustomStringConvertible where Adapter: DynamicContainerAdaptor {
245245
@Attribute var asyncSignal: Void
@@ -582,37 +582,34 @@ struct DynamicContainerInfo<Adapter>: StatefulRule, AsyncAttribute, ObservedAttr
582582
at index: Int,
583583
disableTransitions: Bool
584584
) -> Bool {
585-
let items = info.items
586-
guard let phase = items[index].phase else {
585+
guard let phase = info.items[index].phase else {
587586
return false
588587
}
589588
switch phase {
590589
case .willAppear:
591590
preconditionFailure("")
592591
case .identity:
593-
guard !disableTransitions, items[index].needsTransitions else {
592+
guard !disableTransitions, info.items[index].needsTransitions else {
594593
eraseItem(at: index)
595594
return true
596595
}
597596
lastRemoved = max(lastRemoved &+ 1, 1)
598-
items[index].removalOrder = lastRemoved
597+
info.items[index].removalOrder = lastRemoved
599598
info.removedCount &+= 1
600-
items[index].phase = .didDisappear
601-
if let listener = items[index].listener {
602-
listener.viewGraph = nil
603-
}
599+
info.items[index].phase = .didDisappear
600+
info.items[index].listener?.viewGraph = nil
604601
let newListener = DynamicAnimationListener(
605602
viewGraph: .current,
606603
asyncSignal: WeakAttribute($asyncSignal)
607604
)
608-
items[index].listener = newListener
605+
info.items[index].listener = newListener
609606
newListener.animationWasAdded()
610607
Update.enqueueAction { // TODO: reason
611608
newListener.animationWasRemoved()
612609
}
613610
return false
614611
case .didDisappear:
615-
let listener = items[index].listener!
612+
let listener = info.items[index].listener!
616613
guard listener.count == 0 else {
617614
return false
618615
}
@@ -622,25 +619,24 @@ struct DynamicContainerInfo<Adapter>: StatefulRule, AsyncAttribute, ObservedAttr
622619
}
623620

624621
mutating func unremoveItem(at index: Int) {
625-
let items = info.items
626622
let phase: TransitionPhase
627-
switch items[index].phase {
623+
switch info.items[index].phase {
628624
case .willAppear, .identity:
629-
items[index].resetSeed &-= 1
625+
info.items[index].resetSeed &-= 1
630626
phase = .identity
631627
case .didDisappear:
632628
info.removedCount &-= 1
633-
items[index].removalOrder = 0
629+
info.items[index].removalOrder = 0
634630
phase = .identity
635631
case nil:
636632
info.unusedCount &-= 1
637-
let subgraph = items[index].subgraph
633+
let subgraph = info.items[index].subgraph
638634
parentSubgraph.addChild(subgraph)
639635
subgraph.didReinsert()
640636
phase = .willAppear
641637
}
642-
let newPhase = items[index].needsTransitions ? phase : .identity
643-
items[index].phase = newPhase
638+
let newPhase = info.items[index].needsTransitions ? phase : .identity
639+
info.items[index].phase = newPhase
644640
guard newPhase == .willAppear else {
645641
return
646642
}
@@ -654,11 +650,44 @@ struct DynamicContainerInfo<Adapter>: StatefulRule, AsyncAttribute, ObservedAttr
654650
}
655651
}
656652

657-
func eraseItem(at index: Int) {
658-
_openSwiftUIUnimplementedWarning()
653+
mutating func eraseItem(at index: Int) {
654+
let phase = info.items[index].phase
655+
switch phase {
656+
case .identity, nil:
657+
preconditionFailure("")
658+
case .willAppear:
659+
break
660+
case .didDisappear:
661+
info.removedCount &-= 1
662+
}
663+
let unusedCount = info.unusedCount
664+
let maxUnusedItems = Adapter.maxUnusedItems
665+
let subgraph = info.items[index].subgraph
666+
let item = info.items[index].for(Adapter.self)
667+
if unusedCount < maxUnusedItems {
668+
info.items.remove(at: index)
669+
item.removalOrder = 0
670+
item.resetSeed &+= 1
671+
item.phase = nil
672+
item.listener?.viewGraph = nil
673+
item.listener = nil
674+
info.items.append(item)
675+
info.unusedCount = unusedCount &+ 1
676+
subgraph.willRemove()
677+
parentSubgraph.removeChild(subgraph)
678+
} else {
679+
adaptor.removeItemLayout(
680+
uniqueId: item.uniqueId,
681+
itemLayout: item.itemLayout
682+
)
683+
item.listener?.viewGraph = nil
684+
info.items.remove(at: index)
685+
subgraph.willInvalidate(isInserted: true)
686+
subgraph.invalidate()
687+
}
659688
}
660689

661-
// DynamicPreferenceCombiner + ObservedAttribute
690+
// MARK: - DynamicContainerInfo + ObservedAttribute
662691

663692
mutating func destroy() {
664693
for item in info.items {
@@ -671,7 +700,7 @@ struct DynamicContainerInfo<Adapter>: StatefulRule, AsyncAttribute, ObservedAttr
671700
}
672701
}
673702

674-
// DynamicPreferenceCombiner + CustomStringConvertible
703+
// MARK: - DynamicContainerInfo + CustomStringConvertible
675704

676705
var description: String {
677706
"DynamicContainer<\(Adapter.self)>"

0 commit comments

Comments
 (0)