diff --git a/Sources/ASCollectionView/Implementation/ASCollectionView.swift b/Sources/ASCollectionView/Implementation/ASCollectionView.swift index ba5f3634..08654704 100644 --- a/Sources/ASCollectionView/Implementation/ASCollectionView.swift +++ b/Sources/ASCollectionView/Implementation/ASCollectionView.swift @@ -794,6 +794,10 @@ public struct ASCollectionView: 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: @@ -864,6 +868,10 @@ public struct ASCollectionView: 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 diff --git a/Sources/ASCollectionView/Implementation/ASSectionDataSource.swift b/Sources/ASCollectionView/Implementation/ASSectionDataSource.swift index 80f0361a..b776c8ed 100644 --- a/Sources/ASCollectionView/Implementation/ASSectionDataSource.swift +++ b/Sources/ASCollectionView/Implementation/ASSectionDataSource.swift @@ -23,9 +23,11 @@ internal protocol ASSectionDataSourceProtocol func getItemID(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? @@ -98,6 +100,12 @@ internal struct ASSectionDataSource 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 } @@ -257,6 +265,11 @@ internal struct ASSectionDataSource Bool { // dragDropConfig.dataBinding?.wrappedValue.move(fromOffsets: [from], toOffset: to) //This is not behaving as expected @@ -280,9 +293,10 @@ internal struct ASSectionDataSource 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 @@ -310,6 +325,11 @@ internal struct ASSectionDataSource UIContextMenuConfiguration? { guard @@ -437,3 +457,14 @@ internal extension ASSectionDataSource selfSizingConfig = config } } + +// MARK: - Box + +private class Box +{ + var value: T + + init(_ value: T) { + self.value = value + } +} diff --git a/Sources/ASCollectionView/Implementation/ASTableView.swift b/Sources/ASCollectionView/Implementation/ASTableView.swift index 81e0b628..ec71580b 100644 --- a/Sources/ASCollectionView/Implementation/ASTableView.swift +++ b/Sources/ASCollectionView/Implementation/ASTableView.swift @@ -645,6 +645,10 @@ public struct ASTableView: 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: @@ -715,6 +719,10 @@ public struct ASTableView: 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