Commit 234c0080 authored by Toby Brennan's avatar Toby Brennan
Browse files

Tableview: fix content insets on initial start

Tableview: fix display of select/reorder accessories where a cell cannot be selected/moved
OnswipetoDelete closure type changed (now returns bool instead of using a callback)
Fix safe-area bug in swiftUI
parent a49af3dc
Showing with 182 additions and 119 deletions
+182 -119
......@@ -22,11 +22,11 @@ struct TableViewDragAndDropScreen: View
data: groupA,
dataID: \.self,
dragDropConfig: ASDragDropConfig(dataBinding: $groupA).enableReordering(),
onSwipeToDelete: { index, _, callback in
onSwipeToDelete: { index, _ -> Bool in
withAnimation {
self.groupA.remove(at: index)
callback(true)
_ = self.groupA.remove(at: index)
}
return true
})
{ item, _ in
Text(item)
......@@ -41,11 +41,11 @@ struct TableViewDragAndDropScreen: View
data: groupB,
dataID: \.self,
dragDropConfig: ASDragDropConfig(dataBinding: $groupB).enableReordering(),
onSwipeToDelete: { index, _, callback in
onSwipeToDelete: { index, _ -> Bool in
withAnimation {
self.groupB.remove(at: index)
callback(true)
_ = self.groupB.remove(at: index)
}
return true
})
{ item, _ in
Text(item)
......@@ -63,11 +63,11 @@ struct TableViewDragAndDropScreen: View
data: groupC,
dataID: \.self,
dragDropConfig: ASDragDropConfig(dataBinding: $groupC).enableReordering(),
onSwipeToDelete: { index, _, callback in
onSwipeToDelete: { index, _ -> Bool in
withAnimation {
self.groupC.remove(at: index)
callback(true)
_ = self.groupC.remove(at: index)
}
return true
})
{ item, _ in
Text(item)
......@@ -82,11 +82,11 @@ struct TableViewDragAndDropScreen: View
data: groupD,
dataID: \.self,
dragDropConfig: ASDragDropConfig(dataBinding: $groupD).enableReordering(),
onSwipeToDelete: { index, _, callback in
onSwipeToDelete: { index, _ -> Bool in
withAnimation {
self.groupD.remove(at: index)
callback(true)
_ = self.groupD.remove(at: index)
}
return true
})
{ item, _ in
Text(item)
......
......@@ -44,10 +44,11 @@ class ASCollectionViewCell: UICollectionViewCell, ASDataSourceConfigurableCell
alpha = 1.0
// skipNextRefresh = false
}
public override var safeAreaInsets: UIEdgeInsets {
return .zero
}
override public var safeAreaInsets: UIEdgeInsets
{
.zero
}
func setContent<Content: View>(itemID: ASCollectionViewItemUniqueID, content: Content)
{
......
......@@ -56,10 +56,11 @@ class ASCollectionViewSupplementaryView: UICollectionReusableView, ASDataSourceC
isEmpty = true
hostingController.setView(AnyView(EmptyView().id(supplementaryID)))
}
public override var safeAreaInsets: UIEdgeInsets {
return .zero
}
override public var safeAreaInsets: UIEdgeInsets
{
.zero
}
override func layoutSubviews()
{
......
......@@ -17,10 +17,8 @@ class ASTableViewCell: UITableViewCell, ASDataSourceConfigurableCell
backgroundColor = nil
selectionStyle = .default
showsReorderControl = true
let selectedBack = UIView()
selectedBack.backgroundColor = UIColor.systemGray.withAlphaComponent(0.2)
selectedBack.backgroundColor = UIColor.systemGray.withAlphaComponent(0.1)
selectedBackgroundView = selectedBack
contentView.addSubview(hostingController.viewController.view)
......@@ -58,10 +56,11 @@ class ASTableViewCell: UITableViewCell, ASDataSourceConfigurableCell
self.itemID = itemID
hostingController.setView(AnyView(content.id(itemID)))
}
public override var safeAreaInsets: UIEdgeInsets {
return .zero
}
override public var safeAreaInsets: UIEdgeInsets
{
.zero
}
override func layoutSubviews()
{
......
......@@ -56,10 +56,11 @@ class ASTableViewSupplementaryView: UITableViewHeaderFooterView, ASDataSourceCon
hostingController.setView(AnyView(EmptyView().id(supplementaryID)))
}
public override var safeAreaInsets: UIEdgeInsets {
return .zero
}
override public var safeAreaInsets: UIEdgeInsets
{
.zero
}
override func layoutSubviews()
{
super.layoutSubviews()
......
......@@ -14,7 +14,7 @@ public struct ASDragDropConfig<Data>
var reorderingEnabled: Bool = false
var dragItemProvider: ((_ item: Data) -> NSItemProvider?)?
var shouldMoveItem: ((_ sourceIndexPath: IndexPath, _ destinationIndexPath: IndexPath) -> Bool)?
var shouldMoveItem: ((_ sourceIndexPath: Int, _ destinationIndexPath: Int) -> Bool)?
/// An optional closure that you can use to decide what to do with a dropped item.
/// Return nil if you want to ignore the drop.
......
......@@ -26,7 +26,7 @@ public typealias OnCellEvent<Data> = ((_ event: CellEvent<Data>) -> Void)
public typealias ShouldAllowSwipeToDelete = ((_ index: Int) -> Bool)
@available(iOS 13.0, *)
public typealias OnSwipeToDelete<Data> = ((_ index: Int, _ item: Data, _ completionHandler: (Bool) -> Void) -> Void)
public typealias OnSwipeToDelete<Data> = ((_ index: Int, _ item: Data) -> Bool)
@available(iOS 13.0, *)
public typealias ContextMenuProvider<Data> = ((_ index: Int, _ item: Data) -> UIContextMenuConfiguration?)
......
......@@ -14,8 +14,11 @@ class ASDiffableDataSourceTableView<SectionID: Hashable>: ASDiffableDataSource<S
private let cellProvider: CellProvider
private var indexTitles: [(Int, String)] = []
var onDelete: ((_ indexPath: IndexPath) -> Void)?
var onMove: ((_ source: IndexPath, _ destination: IndexPath) -> Void)?
var canSelect: ((_ indexPath: IndexPath) -> Bool)?
var canDelete: ((_ indexPath: IndexPath) -> Bool)?
var onDelete: ((_ indexPath: IndexPath) -> Bool)?
var canMove: ((_ source: IndexPath) -> Bool)?
var onMove: ((_ source: IndexPath, _ destination: IndexPath) -> Bool)?
public init(tableView: UITableView, cellProvider: @escaping CellProvider)
{
......@@ -108,30 +111,36 @@ class ASDiffableDataSourceTableView<SectionID: Hashable>: ASDiffableDataSource<S
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
{
true
canSelect?(indexPath) ?? false || canMove?(indexPath) ?? false || canDelete?(indexPath) ?? false
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
{
guard let onDelete = onDelete else { return }
var deleteSnapshot = currentSnapshot
deleteSnapshot.removeItems(fromSectionIndex: indexPath.section, atOffsets: [indexPath.row])
applySnapshot(deleteSnapshot, animated: true, completion: nil)
onDelete(indexPath)
let didDelete = onDelete(indexPath)
if didDelete
{
var deleteSnapshot = currentSnapshot
deleteSnapshot.removeItems(fromSectionIndex: indexPath.section, atOffsets: [indexPath.row])
applySnapshot(deleteSnapshot, animated: true, completion: nil)
}
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool
{
onMove != nil
canMove?(indexPath) ?? (onMove != nil)
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
{
guard let onMove = onMove else { return }
var moveSnapshot = currentSnapshot
moveSnapshot.moveItem(fromIndexPath: sourceIndexPath, toIndexPath: destinationIndexPath)
applySnapshot(moveSnapshot, animated: true, completion: nil)
onMove(sourceIndexPath, destinationIndexPath)
let didMove = onMove(sourceIndexPath, destinationIndexPath)
if didMove
{
var moveSnapshot = currentSnapshot
moveSnapshot.moveItem(fromIndexPath: sourceIndexPath, toIndexPath: destinationIndexPath)
applySnapshot(moveSnapshot, animated: true, completion: nil)
}
}
// MARK: Index titles support
......
......@@ -292,20 +292,10 @@ public struct ASCollectionView<SectionID: Hashable>: UIViewControllerRepresentab
collectionViewController?.collectionViewLayout.invalidateLayout()
invalidateLayoutOnNextUpdate = false
}
dataSource?.applySnapshot(snapshot, animated: animated) {
if let scrollPositionToSet = self.parent.scrollPositionSetter?.wrappedValue
{
self.scrollToPosition(scrollPositionToSet, animated: animated)
DispatchQueue.main.async {
self.parent.scrollPositionSetter?.wrappedValue = nil
}
}
}
dataSource?.applySnapshot(snapshot, animated: animated)
collectionViewController.map { updateSelectionBindings($0.collectionView) }
refreshVisibleCells(transaction: transaction, updateAll: false)
collectionViewController.map { self.didUpdateContentSize($0.collectionView.contentSize) }
}
func updateContent(_ cv: UICollectionView, transaction: Transaction?)
......@@ -502,6 +492,16 @@ public struct ASCollectionView<SectionID: Hashable>: UIViewControllerRepresentab
collectionViewController?.collectionView.scrollToItem(at: indexPath, at: position, animated: true)
CATransaction.commit()
}
func applyScrollPosition(animated: Bool) {
if let scrollPositionToSet = self.parent.scrollPositionSetter?.wrappedValue
{
self.scrollToPosition(scrollPositionToSet, animated: animated)
DispatchQueue.main.async {
self.parent.scrollPositionSetter?.wrappedValue = nil
}
}
}
func scrollToPosition(_ scrollPosition: ASCollectionViewScrollPosition, animated: Bool = false)
{
......@@ -805,11 +805,13 @@ public struct ASCollectionView<SectionID: Hashable>: UIViewControllerRepresentab
return destinationSection.dataSource.getItemID(for: item.dragItem, withSectionID: destinationSection.id)
}
}
dragSnapshot.insertItems(itemsToInsertIDs, atSectionIndex: destinationIndexPath.section, atOffset: destinationIndexPath.item)
destinationSection.dataSource.applyInsert(items: itemsToInsert.map { $0.dragItem }, at: destinationIndexPath.item)
if destinationSection.dataSource.applyInsert(items: itemsToInsert.map { $0.dragItem }, at: destinationIndexPath.item)
{
dragSnapshot.insertItems(itemsToInsertIDs, atSectionIndex: destinationIndexPath.section, atOffset: destinationIndexPath.item)
}
case .copy:
destinationSection.dataSource.applyInsert(items: coordinator.items.map { $0.dragItem }, at: destinationIndexPath.item)
_ = destinationSection.dataSource.applyInsert(items: coordinator.items.map { $0.dragItem }, at: destinationIndexPath.item)
default: break
}
......@@ -836,17 +838,20 @@ public struct ASCollectionView<SectionID: Hashable>: UIViewControllerRepresentab
var lastContentSize: CGSize = .zero
func didUpdateContentSize(_ size: CGSize)
{
guard let cv = collectionViewController?.collectionView, cv.contentSize.width != .zero, cv.contentSize.height != .zero else { return }
if cv.contentSize != lastContentSize {
let firstSize = lastContentSize == .zero
lastContentSize = cv.contentSize
parent.contentSizeTracker?.contentSize = size
DispatchQueue.main.async {
self.parent.invalidateParentCellLayout?(!firstSize)
}
}
guard let cv = collectionViewController?.collectionView, cv.contentSize.width != .zero, cv.contentSize.height != .zero else { return }
if cv.contentSize != lastContentSize
{
let firstSize = lastContentSize == .zero
lastContentSize = cv.contentSize
parent.contentSizeTracker?.contentSize = size
DispatchQueue.main.async {
self.parent.invalidateParentCellLayout?(!firstSize)
}
applyScrollPosition(animated: false)
}
#warning("TODO: get animation state")
}
// MARK: Variables used for the custom prefetching implementation
......
......@@ -21,11 +21,12 @@ internal protocol ASSectionDataSourceProtocol
func willAcceptDropItem(from dragItem: UIDragItem) -> Bool
func getDragItem(for indexPath: IndexPath) -> UIDragItem?
func getItemID<SectionID: Hashable>(for dragItem: UIDragItem, withSectionID sectionID: SectionID) -> ASCollectionViewItemUniqueID?
func applyMove(from: Int, to: Int)
func supportsMove(_ indexPath: IndexPath) -> Bool
func applyMove(from: Int, to: Int) -> Bool
func applyRemove(atOffsets offsets: IndexSet)
func applyInsert(items: [UIDragItem], at index: Int)
func applyInsert(items: [UIDragItem], at index: Int) -> Bool
func supportsDelete(at indexPath: IndexPath) -> Bool
func onDelete(indexPath: IndexPath, completionHandler: (Bool) -> Void)
func onDelete(indexPath: IndexPath) -> Bool
func getContextMenu(for indexPath: IndexPath) -> UIContextMenuConfiguration?
func getSelfSizingSettings(context: ASSelfSizingContext) -> ASSelfSizingConfig?
......@@ -192,10 +193,11 @@ internal struct ASSectionDataSource<DataCollection: RandomAccessCollection, Data
return shouldAllowSwipeToDelete?(indexPath.item) ?? true
}
func onDelete(indexPath: IndexPath, completionHandler: (Bool) -> Void)
func onDelete(indexPath: IndexPath) -> Bool
{
guard let item = data[safe: indexPath.item] else { return }
onSwipeToDelete?(indexPath.item, item, completionHandler)
guard let item = data[safe: indexPath.item], let onDelete = onSwipeToDelete else { return false }
let didDelete = onDelete(indexPath.item, item)
return didDelete
}
func getDragItem(for indexPath: IndexPath) -> UIDragItem?
......@@ -228,14 +230,23 @@ internal struct ASSectionDataSource<DataCollection: RandomAccessCollection, Data
return getItemID(for: item, withSectionID: sectionID)
}
func applyMove(from: Int, to: Int)
func supportsMove(_ indexPath: IndexPath) -> Bool
{
dragDropConfig.reorderingEnabled
}
func applyMove(from: Int, to: Int) -> Bool
{
// NOTE: Binding seemingly not updated until next runloop. Any change must be done in one move; hence the var array
// dragDropConfig.dataBinding?.wrappedValue.move(fromOffsets: [from], toOffset: to) //This is not behaving as expected
guard from != to, var array = dragDropConfig.dataBinding?.wrappedValue else { return }
guard from != to,
dragDropConfig.shouldMoveItem?(from, to) ?? true,
var array = dragDropConfig.dataBinding?.wrappedValue
else { return false }
let value = array.remove(at: from)
array.insert(value, at: to)
dragDropConfig.dataBinding?.wrappedValue = array
return true
}
func applyRemove(atOffsets offsets: IndexSet)
......@@ -243,7 +254,7 @@ internal struct ASSectionDataSource<DataCollection: RandomAccessCollection, Data
dragDropConfig.dataBinding?.wrappedValue.remove(atOffsets: offsets)
}
func applyInsert(items: [UIDragItem], at index: Int)
func applyInsert(items: [UIDragItem], at index: Int) -> Bool
{
let actualItems = items.compactMap(getDropItem(from:))
let allDataIDs = Set(dragDropConfig.dataBinding?.wrappedValue.map { $0[keyPath: dataIDKeyPath] } ?? [])
......@@ -253,6 +264,7 @@ internal struct ASSectionDataSource<DataCollection: RandomAccessCollection, Data
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
dragDropConfig.dataBinding?.wrappedValue.insert(contentsOf: noDuplicates, at: index)
return !noDuplicates.isEmpty
}
func getContextMenu(for indexPath: IndexPath) -> UIContextMenuConfiguration?
......
......@@ -146,6 +146,8 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
assignIfChanged(tableView, \.showsVerticalScrollIndicator, newValue: parent.scrollIndicatorEnabled)
assignIfChanged(tableView, \.showsHorizontalScrollIndicator, newValue: parent.scrollIndicatorEnabled)
assignIfChanged(tableView, \.keyboardDismissMode, newValue: .interactive)
updateTableViewContentInsets(tableView)
assignIfChanged(tableView, \.allowsSelection, newValue: true)
assignIfChanged(tableView, \.allowsMultipleSelectionDuringEditing, newValue: true)
......@@ -216,11 +218,20 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
return cell
}
dataSource?.onDelete = { [weak self] indexPath in
self?.onDeleteAction(indexPath: indexPath, completionHandler: { _ in })
dataSource?.canSelect = { [weak self] indexPath -> Bool in
self?.canSelect(indexPath) ?? false
}
dataSource?.canDelete = { [weak self] indexPath -> Bool in
self?.canDelete(indexPath) ?? false
}
dataSource?.onDelete = { [weak self] indexPath -> Bool in
self?.onDeleteAction(indexPath: indexPath) ?? false
}
dataSource?.canMove = { [weak self] indexPath -> Bool in
self?.canMove(indexPath) ?? false
}
dataSource?.onMove = { [weak self] from, to in
self?.onMoveAction(from: from, to: to)
self?.onMoveAction(from: from, to: to) ?? false
}
}
......@@ -239,29 +250,10 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
}
)
dataSource?.applySnapshot(snapshot, animated: animated) {
if let scrollPositionToSet = self.parent.scrollPositionSetter?.wrappedValue
{
switch scrollPositionToSet
{
case let .indexPath(indexPath):
self.tableViewController?.tableView.scrollToRow(at: indexPath, at: .none, animated: animated)
case .top:
let contentInsets = self.tableViewController?.tableView.contentInset ?? .zero
self.tableViewController?.tableView.setContentOffset(CGPoint(x: 0, y: contentInsets.top), animated: animated)
case .bottom:
let contentSize = self.tableViewController?.tableView.contentSizePlusInsets ?? .zero
self.tableViewController?.tableView.scrollRectToVisible(CGRect(origin: .init(x: 0, y: contentSize.height), size: .zero), animated: animated)
}
DispatchQueue.main.async {
self.parent.scrollPositionSetter?.wrappedValue = nil
}
}
}
dataSource?.applySnapshot(snapshot, animated: animated)
tableViewController.map { updateSelectionBindings($0.tableView) }
refreshVisibleCells(transaction: transaction, updateAll: false)
tableViewController.map { self.didUpdateContentSize($0.tableView.contentSize) }
}
func updateContent(_ tv: UITableView, transaction: Transaction?)
......@@ -299,16 +291,10 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
let itemID = cell.itemID,
let section = section(forItemID: itemID)
else { return }
// if cell.skipNextRefresh, !forceUpdate
// {
// cell.skipNextRefresh = false
// }
// else
// {
cell.setContent(itemID: itemID, content: section.dataSource.content(forItemID: itemID, isSelected: cell.isSelected, isHighlighted: cell.isHighlighted))
cell.disableSwiftUIDropInteraction = section.dataSource.dropEnabled
cell.disableSwiftUIDragInteraction = section.dataSource.dragEnabled
// }
}
func invalidateLayout(animated: Bool, cell: ASTableViewCell?)
......@@ -320,6 +306,27 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
{
tableViewController?.tableView.scrollToRow(at: indexPath, at: position, animated: true)
}
func applyScrollPosition(animated: Bool) {
if let scrollPositionToSet = self.parent.scrollPositionSetter?.wrappedValue
{
switch scrollPositionToSet
{
case let .indexPath(indexPath):
self.tableViewController?.tableView.scrollToRow(at: indexPath, at: .none, animated: animated)
case .top:
let contentInsets = self.tableViewController?.tableView.contentInset ?? .zero
self.tableViewController?.tableView.setContentOffset(CGPoint(x: 0, y: contentInsets.top), animated: animated)
case .bottom:
let contentSize = self.tableViewController?.tableView.contentSizePlusInsets ?? .zero
let visibleHeight = self.tableViewController?.tableView.frame.height ?? .zero
self.tableViewController?.tableView.setContentOffset(CGPoint(x: 0, y: contentSize.height - visibleHeight), animated: animated)
}
DispatchQueue.main.async {
self.parent.scrollPositionSetter?.wrappedValue = nil
}
}
}
func onMoveToParent()
{
......@@ -348,6 +355,9 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
DispatchQueue.main.async {
self.parent.invalidateParentCellLayout?(!firstSize)
}
applyScrollPosition(animated: false)
#warning("TODO: get animation state")
}
func configureRefreshControl(for tv: UITableView)
......@@ -432,7 +442,8 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
{
guard parent.sections[safe: indexPath.section]?.dataSource.supportsDelete(at: indexPath) == true else { return nil }
let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { [weak self] _, _, completionHandler in
self?.onDeleteAction(indexPath: indexPath, completionHandler: completionHandler)
let didDelete = self?.onDeleteAction(indexPath: indexPath) ?? false
completionHandler(didDelete)
}
return UISwipeActionsConfiguration(actions: [deleteAction])
}
......@@ -446,36 +457,56 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
return .none
}
private func onDeleteAction(indexPath: IndexPath, completionHandler: (Bool) -> Void)
private func canDelete(_ indexPath: IndexPath) -> Bool
{
parent.sections[safe: indexPath.section]?.dataSource.supportsDelete(at: indexPath) ?? false
}
private func onDeleteAction(indexPath: IndexPath) -> Bool
{
parent.sections[safe: indexPath.section]?.dataSource.onDelete(indexPath: indexPath, completionHandler: completionHandler)
parent.sections[safe: indexPath.section]?.dataSource.onDelete(indexPath: indexPath) ?? false
}
private func onMoveAction(from: IndexPath, to: IndexPath)
private func canMove(_ indexPath: IndexPath) -> Bool
{
parent.sections[safe: indexPath.section]?.dataSource.supportsMove(indexPath) ?? false
}
private func onMoveAction(from: IndexPath, to: IndexPath) -> Bool
{
guard let sourceSection = parent.sections[safe: from.section],
let destinationSection = parent.sections[safe: to.section]
else { return }
else { return false }
if from.section == to.section
{
sourceSection.dataSource.applyMove(from: from.item, to: to.item)
return sourceSection.dataSource.applyMove(from: from.item, to: to.item)
}
else
{
if let item = sourceSection.dataSource.getDragItem(for: from)
{
sourceSection.dataSource.applyRemove(atOffsets: [from.item])
destinationSection.dataSource.applyInsert(items: [item], at: to.item)
return destinationSection.dataSource.applyInsert(items: [item], at: to.item)
}
else
{
return false
}
}
}
// MARK: Cell Selection
private func canSelect(_ indexPath: IndexPath) -> Bool
{
parent.sections[safe: indexPath.section]?.dataSource.shouldSelect(indexPath) ?? false
}
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if parent.editMode
{
updateSelectionBindings(tableView)
tableView.cellForRow(at: indexPath).map { refreshCell($0, forceUpdate: true) }
}
else
......@@ -487,6 +518,7 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
public func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath)
{
updateSelectionBindings(tableView)
tableView.cellForRow(at: indexPath).map { refreshCell($0, forceUpdate: true) }
}
......@@ -656,11 +688,14 @@ public struct ASTableView<SectionID: Hashable>: UIViewControllerRepresentable, C
}
}
let safeDestinationIndex = min(destinationIndexPath.item, dragSnapshot.sections[destinationIndexPath.section].elements.endIndex)
dragSnapshot.insertItems(itemsToInsertIDs, atSectionIndex: destinationIndexPath.section, atOffset: destinationIndexPath.item)
destinationSection.dataSource.applyInsert(items: itemsToInsert.map { $0.dragItem }, at: safeDestinationIndex)
if destinationSection.dataSource.applyInsert(items: itemsToInsert.map { $0.dragItem }, at: safeDestinationIndex)
{
dragSnapshot.insertItems(itemsToInsertIDs, atSectionIndex: destinationIndexPath.section, atOffset: destinationIndexPath.item)
}
case .copy:
destinationSection.dataSource.applyInsert(items: coordinator.items.map { $0.dragItem }, at: destinationIndexPath.item)
_ = destinationSection.dataSource.applyInsert(items: coordinator.items.map { $0.dragItem }, at: destinationIndexPath.item)
default: break
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment