Skip to content
This repository was archived by the owner on Nov 4, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,10 @@ public struct ASCollectionView<SectionID: Hashable>: UIViewControllerRepresentab
guard let oldSnapshot = dataSource?.currentSnapshot else { return }
var dragSnapshot = oldSnapshot

parent.sections.forEach { section in
section.dataSource.applyPrepare()
}

switch coordinator.proposal.operation
{
case .move:
Expand Down Expand Up @@ -864,6 +868,10 @@ public struct ASCollectionView<SectionID: Hashable>: UIViewControllerRepresentab
default: break
}

parent.sections.forEach { section in
section.dataSource.applyCommit()
}

if let dragItem = coordinator.items.first, let destination = coordinator.destinationIndexPath
{
if dragItem.sourceIndexPath != nil
Expand Down
41 changes: 36 additions & 5 deletions Sources/ASCollectionView/Implementation/ASSectionDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ internal protocol ASSectionDataSourceProtocol
func getItemID<SectionID: Hashable>(for dragItem: UIDragItem, withSectionID sectionID: SectionID) -> ASCollectionViewItemUniqueID?
func supportsMove(_ indexPath: IndexPath) -> Bool
func supportsMove(from sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) -> Bool
func applyPrepare()
func applyMove(from: IndexPath, to: IndexPath) -> Bool
func applyRemove(atOffsets offsets: IndexSet)
func applyInsert(items: [UIDragItem], at index: Int) -> Bool
func applyCommit()
func supportsDelete(at indexPath: IndexPath) -> Bool
func onDelete(indexPath: IndexPath) -> Bool
func getContextMenu(for indexPath: IndexPath) -> UIContextMenuConfiguration?
Expand Down Expand Up @@ -98,6 +100,12 @@ internal struct ASSectionDataSource<DataCollection: RandomAccessCollection, Data

var supplementaryViews: [String: AnyView] = [:]

/// Temporal boxed storage for not setting `dragDropConfig.dataBinding.wrappedValue`
/// multiple times during Drap & Drop.
/// For example, by having this storage, reordering 3 items will invoke "3 items -> 3 items" only once,
/// not "3 items --(removed)--> 2 items --(inserted)--> 3 items".
private let dragDroppingItems: Box<[DataCollection.Element]?> = Box(nil)

var dragEnabled: Bool { dragDropConfig.dragEnabled }
var dropEnabled: Bool { dragDropConfig.dropEnabled }
var reorderingEnabled: Bool { dragDropConfig.reorderingEnabled }
Expand Down Expand Up @@ -257,6 +265,11 @@ internal struct ASSectionDataSource<DataCollection: RandomAccessCollection, Data
dragDropConfig.reorderingEnabled && (dragDropConfig.canMoveItem?(sourceIndexPath, destinationIndexPath) ?? true)
}

func applyPrepare()
{
dragDroppingItems.value = dragDropConfig.dataBinding?.wrappedValue
}

func applyMove(from: IndexPath, to: IndexPath) -> Bool
{
// dragDropConfig.dataBinding?.wrappedValue.move(fromOffsets: [from], toOffset: to) //This is not behaving as expected
Expand All @@ -280,9 +293,10 @@ internal struct ASSectionDataSource<DataCollection: RandomAccessCollection, Data

func applyRemove(atOffsets offsets: IndexSet)
{
if let binding = dragDropConfig.dataBinding
if var items = dragDroppingItems.value
{
binding.wrappedValue.remove(atOffsets: offsets)
items.remove(atOffsets: offsets)
dragDroppingItems.value = items
}
else
{
Expand All @@ -293,15 +307,16 @@ internal struct ASSectionDataSource<DataCollection: RandomAccessCollection, Data
func applyInsert(items: [UIDragItem], at index: Int) -> Bool
{
let actualItems = items.compactMap(getDropItem(from:))
if let binding = dragDropConfig.dataBinding
if var items = dragDroppingItems.value
{
let allDataIDs = Set(binding.wrappedValue.map { $0[keyPath: dataIDKeyPath] })
let allDataIDs = Set(items.map { $0[keyPath: dataIDKeyPath] })
let noDuplicates = actualItems.filter { !allDataIDs.contains($0[keyPath: dataIDKeyPath]) }
#if DEBUG
// Notify during debug build if IDs are not unique (programmer error)
if noDuplicates.count != actualItems.count { print("ASCOLLECTIONVIEW/ASTABLEVIEW: Attempted to insert an item with the same ID as one already in the section. This may cause unexpected behaviour.") }
#endif
binding.wrappedValue.insert(contentsOf: noDuplicates, at: index)
items.insert(contentsOf: noDuplicates, at: index)
dragDroppingItems.value = items
return !noDuplicates.isEmpty
}
else
Expand All @@ -310,6 +325,11 @@ internal struct ASSectionDataSource<DataCollection: RandomAccessCollection, Data
}
}

func applyCommit()
{
dragDropConfig.dataBinding?.wrappedValue = dragDroppingItems.value ?? []
}

func getContextMenu(for indexPath: IndexPath) -> UIContextMenuConfiguration?
{
guard
Expand Down Expand Up @@ -437,3 +457,14 @@ internal extension ASSectionDataSource
selfSizingConfig = config
}
}

// MARK: - Box

private class Box<T>
{
var value: T

init(_ value: T) {
self.value = value
}
}
8 changes: 8 additions & 0 deletions Sources/ASCollectionView/Implementation/ASTableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,10 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
guard let oldSnapshot = dataSource?.currentSnapshot else { return }
var dragSnapshot = oldSnapshot

parent.sections.forEach { section in
section.dataSource.applyPrepare()
}

switch coordinator.proposal.operation
{
case .move:
Expand Down Expand Up @@ -715,6 +719,10 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
default: break
}

parent.sections.forEach { section in
section.dataSource.applyCommit()
}

dataSource?.applySnapshot(dragSnapshot, animated: false)
refreshVisibleCells(transaction: nil)
if let dragItem = coordinator.items.first, let destination = coordinator.destinationIndexPath
Expand Down