diff --git a/DataSource.xcodeproj/project.pbxproj b/DataSource.xcodeproj/project.pbxproj index ab73915..657dcd5 100644 --- a/DataSource.xcodeproj/project.pbxproj +++ b/DataSource.xcodeproj/project.pbxproj @@ -51,6 +51,7 @@ 4C6076DF21490C80002E8BD1 /* SeparatedSectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6076DE21490C80002E8BD1 /* SeparatedSectionViewController.swift */; }; 4CA65F60214F952E004F2F19 /* UIView+AutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA65F5F214F952E004F2F19 /* UIView+AutoLayout.swift */; }; 5C61C91820AF0AB0003A08B8 /* SwipeActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C61C91720AF0AB0003A08B8 /* SwipeActionViewController.swift */; }; + 5F91D0C625091B8300CF5053 /* ContextMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F91D0C525091B8300CF5053 /* ContextMenuViewController.swift */; }; 5FD722022500F36800835AA1 /* Differ in Frameworks */ = {isa = PBXBuildFile; productRef = 5FD722012500F36800835AA1 /* Differ */; }; D8D61BEE21E4DD3E00937D1C /* SeparatorLineViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D61BED21E4DD3E00937D1C /* SeparatorLineViewModel.swift */; }; D8D61BF021E4E11300937D1C /* SeparatorCustomViewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D61BEF21E4E11300937D1C /* SeparatorCustomViewViewModel.swift */; }; @@ -154,6 +155,7 @@ 4C6076DE21490C80002E8BD1 /* SeparatedSectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatedSectionViewController.swift; sourceTree = ""; }; 4CA65F5F214F952E004F2F19 /* UIView+AutoLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+AutoLayout.swift"; sourceTree = ""; }; 5C61C91720AF0AB0003A08B8 /* SwipeActionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeActionViewController.swift; sourceTree = ""; }; + 5F91D0C525091B8300CF5053 /* ContextMenuViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuViewController.swift; sourceTree = ""; }; D8D61BED21E4DD3E00937D1C /* SeparatorLineViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorLineViewModel.swift; sourceTree = ""; }; D8D61BEF21E4E11300937D1C /* SeparatorCustomViewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorCustomViewViewModel.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -255,6 +257,7 @@ 5C61C91720AF0AB0003A08B8 /* SwipeActionViewController.swift */, 4C6076DE21490C80002E8BD1 /* SeparatedSectionViewController.swift */, 3903C1822428C7410094EF50 /* ExpandableCellViewController.swift */, + 5F91D0C525091B8300CF5053 /* ContextMenuViewController.swift */, ); name = Examples; sourceTree = ""; @@ -507,6 +510,7 @@ 3903C1852428C7DE0094EF50 /* TextCell.swift in Sources */, 396E02E020A1B0090072291F /* SwipeToDeleteViewController.swift in Sources */, 3968B9161E7C261600EE876F /* UILabel+Animation.swift in Sources */, + 5F91D0C625091B8300CF5053 /* ContextMenuViewController.swift in Sources */, 39E9E3AE1E659D7D00A3C300 /* SwitchCell.swift in Sources */, 3903C1832428C7410094EF50 /* ExpandableCellViewController.swift in Sources */, 39E9E3A91E6566AD00A3C300 /* TitleCell.swift in Sources */, diff --git a/DataSource/CellDescriptor.swift b/DataSource/CellDescriptor.swift index ed9c619..63440dc 100644 --- a/DataSource/CellDescriptor.swift +++ b/DataSource/CellDescriptor.swift @@ -9,24 +9,22 @@ import UIKit public enum SelectionResult { - case deselect case keepSelected } -// MARK - CellDescriptorType +// MARK: - CellDescriptorType public protocol CellDescriptorType { - var rowIdentifier: String { get } var cellIdentifier: String { get } var bundle: Bundle? { get } var cellClass: UITableViewCell.Type { get } - + // UITableViewDataSource var configureClosure: ((RowType, UITableViewCell, IndexPath) -> Void)? { get } - + var canEditClosure: ((RowType, IndexPath) -> Bool)? { get } var canMoveClosure: ((RowType, IndexPath) -> Bool)? { get } var commitEditingClosure: ((RowType, UITableViewCell.EditingStyle, IndexPath) -> Void)? { get } @@ -53,7 +51,7 @@ public protocol CellDescriptorType { var editActionsClosure: ((RowType, IndexPath) -> [UITableViewRowAction]?)? { get } var shouldIndentWhileEditingClosure: ((RowType, IndexPath) -> Bool)? { get } var willBeginEditingClosure: ((RowType, IndexPath) -> Void)? { get } - + var targetIndexPathForMoveClosure: ((RowType, (IndexPath, IndexPath)) -> IndexPath)? { get } var indentationLevelClosure: ((RowType, IndexPath) -> Int)? { get } var shouldShowMenuClosure: ((RowType, IndexPath) -> Bool)? { get } @@ -73,10 +71,14 @@ public protocol CellDescriptorTypeiOS11: CellDescriptorType { var trailingSwipeActionsClosure: ((RowType, IndexPath) -> UISwipeActionsConfiguration?)? { get } } -// MARK - CellDescriptor +@available(iOS 13.0, *) +public protocol CellDescriptorTypeiOS13: CellDescriptorType { + var configurationForMenuAtLocationClosure: ((RowType, IndexPath) -> UIContextMenuConfiguration?)? { get } +} + +// MARK: - CellDescriptor public class CellDescriptor: CellDescriptorType { - public let rowIdentifier: String public let cellIdentifier: String public let bundle: Bundle? @@ -104,7 +106,7 @@ public class CellDescriptor: CellDescriptorType { } return cell } - + // MARK: - UITableViewDataSource // MARK: configure @@ -112,7 +114,7 @@ public class CellDescriptor: CellDescriptorType { public private(set) var configureClosure: ((RowType, UITableViewCell, IndexPath) -> Void)? public func configure(_ closure: @escaping (Item, Cell, IndexPath) -> Void) -> CellDescriptor { - configureClosure = { [unowned self] (row, cell, indexPath) in + configureClosure = { [unowned self] row, cell, indexPath in closure(self.typedItem(row), self.typedCell(cell), indexPath) } return self @@ -123,14 +125,14 @@ public class CellDescriptor: CellDescriptorType { public private(set) var canEditClosure: ((RowType, IndexPath) -> Bool)? public func canEdit(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor { - canEditClosure = { [unowned self] (row, indexPath) in + canEditClosure = { [unowned self] row, indexPath in closure(self.typedItem(row), indexPath) } return self } public func canEdit(_ closure: @escaping () -> Bool) -> CellDescriptor { - canEditClosure = { (_, _) in + canEditClosure = { _, _ in closure() } return self @@ -141,14 +143,14 @@ public class CellDescriptor: CellDescriptorType { public private(set) var canMoveClosure: ((RowType, IndexPath) -> Bool)? public func canMove(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor { - canMoveClosure = { [unowned self] (row, indexPath) in + canMoveClosure = { [unowned self] row, indexPath in closure(self.typedItem(row), indexPath) } return self } public func canMove(_ closure: @escaping () -> Bool) -> CellDescriptor { - canMoveClosure = { (_, _) in + canMoveClosure = { _, _ in closure() } return self @@ -159,15 +161,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var heightClosure: ((RowType, IndexPath) -> CGFloat)? public func height(_ closure: @escaping (Item, IndexPath) -> CGFloat) -> CellDescriptor { - heightClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + heightClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func height(_ closure: @escaping () -> CGFloat) -> CellDescriptor { - heightClosure = { (_, _) in - return closure() + heightClosure = { _, _ in + closure() } return self } @@ -177,15 +179,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var estimatedHeightClosure: ((RowType, IndexPath) -> CGFloat)? public func estimatedHeight(_ closure: @escaping (Item, IndexPath) -> CGFloat) -> CellDescriptor { - estimatedHeightClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + estimatedHeightClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func estimatedHeight(_ closure: @escaping () -> CGFloat) -> CellDescriptor { - estimatedHeightClosure = { (_, _) in - return closure() + estimatedHeightClosure = { _, _ in + closure() } return self } @@ -195,8 +197,8 @@ public class CellDescriptor: CellDescriptorType { public private(set) var commitEditingClosure: ((RowType, UITableViewCell.EditingStyle, IndexPath) -> Void)? public func commitEditing(_ closure: @escaping (Item, UITableViewCell.EditingStyle, IndexPath) -> Void) -> CellDescriptor { - commitEditingClosure = { [unowned self] (row, editingStyle, indexPath) in - return closure(self.typedItem(row), editingStyle, indexPath) + commitEditingClosure = { [unowned self] row, editingStyle, indexPath in + closure(self.typedItem(row), editingStyle, indexPath) } return self } @@ -206,8 +208,8 @@ public class CellDescriptor: CellDescriptorType { public private(set) var moveRowClosure: ((RowType, (IndexPath, IndexPath)) -> Void)? public func moveRow(_ closure: @escaping (Item, (IndexPath, IndexPath)) -> Void) -> CellDescriptor { - moveRowClosure = { [unowned self] (row, indexPaths) in - return closure(self.typedItem(row), indexPaths) + moveRowClosure = { [unowned self] row, indexPaths in + closure(self.typedItem(row), indexPaths) } return self } @@ -219,15 +221,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var shouldHighlightClosure: ((RowType, IndexPath) -> Bool)? public func shouldHighlight(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor { - shouldHighlightClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + shouldHighlightClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func shouldHighlight(_ closure: @escaping () -> Bool) -> CellDescriptor { - shouldHighlightClosure = { (_, _) in - return closure() + shouldHighlightClosure = { _, _ in + closure() } return self } @@ -237,15 +239,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var didHighlightClosure: ((RowType, IndexPath) -> Void)? public func didHighlight(_ closure: @escaping (Item, IndexPath) -> Void) -> CellDescriptor { - didHighlightClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + didHighlightClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func didHighlight(_ closure: @escaping () -> Void) -> CellDescriptor { - didHighlightClosure = { (_, _) in - return closure() + didHighlightClosure = { _, _ in + closure() } return self } @@ -255,15 +257,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var didUnhighlightClosure: ((RowType, IndexPath) -> Void)? public func didUnhighlight(_ closure: @escaping (Item, IndexPath) -> Void) -> CellDescriptor { - didUnhighlightClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + didUnhighlightClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func didUnhighlight(_ closure: @escaping () -> Void) -> CellDescriptor { - didUnhighlightClosure = { (_, _) in - return closure() + didUnhighlightClosure = { _, _ in + closure() } return self } @@ -273,15 +275,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var willSelectClosure: ((RowType, IndexPath) -> IndexPath?)? public func willSelect(_ closure: @escaping (Item, IndexPath) -> IndexPath?) -> CellDescriptor { - willSelectClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + willSelectClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func willSelect(_ closure: @escaping () -> IndexPath?) -> CellDescriptor { - willSelectClosure = { (_, _) in - return closure() + willSelectClosure = { _, _ in + closure() } return self } @@ -291,15 +293,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var willDeselectClosure: ((RowType, IndexPath) -> IndexPath?)? public func willDeselect(_ closure: @escaping (Item, IndexPath) -> IndexPath?) -> CellDescriptor { - willDeselectClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + willDeselectClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func willDeselect(_ closure: @escaping () -> IndexPath?) -> CellDescriptor { - willDeselectClosure = { (_, _) in - return closure() + willDeselectClosure = { _, _ in + closure() } return self } @@ -309,15 +311,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var didSelectClosure: ((RowType, IndexPath) -> SelectionResult)? public func didSelect(_ closure: @escaping (Item, IndexPath) -> SelectionResult) -> CellDescriptor { - didSelectClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + didSelectClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func didSelect(_ closure: @escaping () -> SelectionResult) -> CellDescriptor { - didSelectClosure = { (_, _) in - return closure() + didSelectClosure = { _, _ in + closure() } return self } @@ -327,15 +329,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var didDeselectClosure: ((RowType, IndexPath) -> Void)? public func didDeselect(_ closure: @escaping (Item, IndexPath) -> Void) -> CellDescriptor { - didDeselectClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + didDeselectClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func didDeselect(_ closure: @escaping () -> Void) -> CellDescriptor { - didDeselectClosure = { (_, _) in - return closure() + didDeselectClosure = { _, _ in + closure() } return self } @@ -345,8 +347,8 @@ public class CellDescriptor: CellDescriptorType { public private(set) var willDisplayClosure: ((RowType, UITableViewCell, IndexPath) -> Void)? public func willDisplay(_ closure: @escaping (Item, Cell, IndexPath) -> Void) -> CellDescriptor { - willDisplayClosure = { [unowned self] (row, cell, indexPath) in - return closure(self.typedItem(row), self.typedCell(cell), indexPath) + willDisplayClosure = { [unowned self] row, cell, indexPath in + closure(self.typedItem(row), self.typedCell(cell), indexPath) } return self } @@ -356,15 +358,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var editingStyleClosure: ((RowType, IndexPath) -> UITableViewCell.EditingStyle)? public func editingStyle(_ closure: @escaping (Item, IndexPath) -> UITableViewCell.EditingStyle) -> CellDescriptor { - editingStyleClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + editingStyleClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func editingStyle(_ closure: @escaping () -> UITableViewCell.EditingStyle) -> CellDescriptor { - editingStyleClosure = { (_, _) in - return closure() + editingStyleClosure = { _, _ in + closure() } return self } @@ -374,15 +376,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var titleForDeleteConfirmationButtonClosure: ((RowType, IndexPath) -> String?)? public func titleForDeleteConfirmationButton(_ closure: @escaping (Item, IndexPath) -> String?) -> CellDescriptor { - titleForDeleteConfirmationButtonClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + titleForDeleteConfirmationButtonClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func titleForDeleteConfirmationButton(_ closure: @escaping () -> String?) -> CellDescriptor { - titleForDeleteConfirmationButtonClosure = { (_, _) in - return closure() + titleForDeleteConfirmationButtonClosure = { _, _ in + closure() } return self } @@ -392,20 +394,24 @@ public class CellDescriptor: CellDescriptorType { private var _leadingSwipeActionsClosure: ((RowType, IndexPath) -> Any?)? private var _trailingSwipeActionsClosure: ((RowType, IndexPath) -> Any?)? + // MARK: contextMenu + + public var _configurationForMenuAtLocationClosure: ((RowType, IndexPath) -> Any)? + // MARK: editActions public private(set) var editActionsClosure: ((RowType, IndexPath) -> [UITableViewRowAction]?)? public func editActions(_ closure: @escaping (Item, IndexPath) -> [UITableViewRowAction]?) -> CellDescriptor { - editActionsClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + editActionsClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func editActions(_ closure: @escaping () -> [UITableViewRowAction]?) -> CellDescriptor { - editActionsClosure = { (_, _) in - return closure() + editActionsClosure = { _, _ in + closure() } return self } @@ -415,15 +421,15 @@ public class CellDescriptor: CellDescriptorType { public private(set) var shouldIndentWhileEditingClosure: ((RowType, IndexPath) -> Bool)? public func shouldIndentWhileEditing(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor { - shouldIndentWhileEditingClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + shouldIndentWhileEditingClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } public func shouldIndentWhileEditing(_ closure: @escaping () -> Bool) -> CellDescriptor { - shouldIndentWhileEditingClosure = { (_, _) in - return closure() + shouldIndentWhileEditingClosure = { _, _ in + closure() } return self } @@ -433,14 +439,14 @@ public class CellDescriptor: CellDescriptorType { public private(set) var willBeginEditingClosure: ((RowType, IndexPath) -> Void)? public func willBeginEditing(_ closure: @escaping (Item, IndexPath) -> Void) -> CellDescriptor { - willBeginEditingClosure = { [unowned self] (row, indexPath) in + willBeginEditingClosure = { [unowned self] row, indexPath in closure(self.typedItem(row), indexPath) } return self } public func willBeginEditing(_ closure: @escaping () -> Void) -> CellDescriptor { - willBeginEditingClosure = { (_, _) in + willBeginEditingClosure = { _, _ in closure() } return self @@ -451,7 +457,7 @@ public class CellDescriptor: CellDescriptorType { public private(set) var targetIndexPathForMoveClosure: ((RowType, (IndexPath, IndexPath)) -> IndexPath)? public func targetIndexPathForMove(_ closure: @escaping (Item, (IndexPath, IndexPath)) -> IndexPath) -> CellDescriptor { - targetIndexPathForMoveClosure = { [unowned self] (row, indexPaths) in + targetIndexPathForMoveClosure = { [unowned self] row, indexPaths in closure(self.typedItem(row), indexPaths) } return self @@ -462,14 +468,14 @@ public class CellDescriptor: CellDescriptorType { public private(set) var indentationLevelClosure: ((RowType, IndexPath) -> Int)? public func indentationLevel(_ closure: @escaping (Item, IndexPath) -> Int) -> CellDescriptor { - indentationLevelClosure = { [unowned self] (row, indexPath) in + indentationLevelClosure = { [unowned self] row, indexPath in closure(self.typedItem(row), indexPath) } return self } public func indentationLevel(_ closure: @escaping () -> Int) -> CellDescriptor { - indentationLevelClosure = { (_, _) in + indentationLevelClosure = { _, _ in closure() } return self @@ -480,14 +486,14 @@ public class CellDescriptor: CellDescriptorType { public private(set) var shouldShowMenuClosure: ((RowType, IndexPath) -> Bool)? public func shouldShowMenu(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor { - shouldShowMenuClosure = { [unowned self] (row, indexPath) in + shouldShowMenuClosure = { [unowned self] row, indexPath in closure(self.typedItem(row), indexPath) } return self } public func shouldShowMenu(_ closure: @escaping () -> Bool) -> CellDescriptor { - shouldShowMenuClosure = { (_, _) in + shouldShowMenuClosure = { _, _ in closure() } return self @@ -498,14 +504,14 @@ public class CellDescriptor: CellDescriptorType { public private(set) var canPerformActionClosure: ((RowType, Selector, Any?, IndexPath) -> Bool)? public func canPerformAction(_ closure: @escaping (Item, Selector, Any?, IndexPath) -> Bool) -> CellDescriptor { - canPerformActionClosure = { [unowned self] (row, selector, sender, indexPath) in + canPerformActionClosure = { [unowned self] row, selector, sender, indexPath in closure(self.typedItem(row), selector, sender, indexPath) } return self } public func canPerformAction(_ closure: @escaping (Selector, Any?) -> Bool) -> CellDescriptor { - canPerformActionClosure = { (_, selector, sender, _) in + canPerformActionClosure = { _, selector, sender, _ in closure(selector, sender) } return self @@ -516,14 +522,14 @@ public class CellDescriptor: CellDescriptorType { public private(set) var performActionClosure: ((RowType, Selector, Any?, IndexPath) -> Void)? public func performAction(_ closure: @escaping (Item, Selector, Any?, IndexPath) -> Void) -> CellDescriptor { - performActionClosure = { [unowned self] (row, selector, sender, indexPath) in + performActionClosure = { [unowned self] row, selector, sender, indexPath in closure(self.typedItem(row), selector, sender, indexPath) } return self } public func performAction(_ closure: @escaping (Selector, Any?) -> Void) -> CellDescriptor { - performActionClosure = { (_, selector, sender, _) in + performActionClosure = { _, selector, sender, _ in closure(selector, sender) } return self @@ -534,14 +540,14 @@ public class CellDescriptor: CellDescriptorType { public private(set) var canFocusClosure: ((RowType, IndexPath) -> Bool)? public func canFocus(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor { - canFocusClosure = { [unowned self] (row, indexPath) in + canFocusClosure = { [unowned self] row, indexPath in closure(self.typedItem(row), indexPath) } return self } public func canFocus(_ closure: @escaping () -> Bool) -> CellDescriptor { - canFocusClosure = { (_, _) in + canFocusClosure = { _, _ in closure() } return self @@ -554,14 +560,14 @@ public class CellDescriptor: CellDescriptorType { public private(set) var isHiddenClosure: ((RowType, IndexPath) -> Bool)? public func isHidden(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor { - isHiddenClosure = { [unowned self] (row, indexPath) in + isHiddenClosure = { [unowned self] row, indexPath in closure(self.typedItem(row), indexPath) } return self } public func isHidden(_ closure: @escaping () -> Bool) -> CellDescriptor { - isHiddenClosure = { (_, _) in + isHiddenClosure = { _, _ in closure() } return self @@ -572,7 +578,7 @@ public class CellDescriptor: CellDescriptorType { public private(set) var updateClosure: ((RowType, UITableViewCell, IndexPath) -> Void)? public func update(_ closure: @escaping (Item, Cell, IndexPath) -> Void) -> CellDescriptor { - updateClosure = { [unowned self] (row, cell, indexPath) in + updateClosure = { [unowned self] row, cell, indexPath in closure(self.typedItem(row), self.typedCell(cell), indexPath) } return self @@ -581,41 +587,36 @@ public class CellDescriptor: CellDescriptorType { @available(iOS 11, *) extension CellDescriptor: CellDescriptorTypeiOS11 { - public var leadingSwipeActionsClosure: ((RowType, IndexPath) -> UISwipeActionsConfiguration?)? { - get { - if _leadingSwipeActionsClosure == nil { - return nil - } - - return { [weak self] (rowType, indexPath) in - return self?._leadingSwipeActionsClosure?(rowType, indexPath) as? UISwipeActionsConfiguration - } + if _leadingSwipeActionsClosure == nil { + return nil + } + + return { [weak self] rowType, indexPath in + self?._leadingSwipeActionsClosure?(rowType, indexPath) as? UISwipeActionsConfiguration } } public var trailingSwipeActionsClosure: ((RowType, IndexPath) -> UISwipeActionsConfiguration?)? { - get { - if _trailingSwipeActionsClosure == nil { - return nil - } - - return { [weak self] (rowType, indexPath) in - return self?._trailingSwipeActionsClosure?(rowType, indexPath) as? UISwipeActionsConfiguration - } + if _trailingSwipeActionsClosure == nil { + return nil + } + + return { [weak self] rowType, indexPath in + self?._trailingSwipeActionsClosure?(rowType, indexPath) as? UISwipeActionsConfiguration } } public func leadingSwipeAction(_ closure: @escaping ((Item, IndexPath) -> UISwipeActionsConfiguration?)) -> CellDescriptor { - _leadingSwipeActionsClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + _leadingSwipeActionsClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } - + public func trailingSwipeAction(_ closure: @escaping ((Item, IndexPath) -> UISwipeActionsConfiguration?)) -> CellDescriptor { - _trailingSwipeActionsClosure = { [unowned self] (row, indexPath) in - return closure(self.typedItem(row), indexPath) + _trailingSwipeActionsClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) } return self } @@ -628,3 +629,23 @@ extension CellDescriptor: CellDescriptorTypeiOS11 { return _trailingSwipeActionsClosure != nil } } + +@available(iOS 13, *) +extension CellDescriptor: CellDescriptorTypeiOS13 { + public var configurationForMenuAtLocationClosure: ((RowType, IndexPath) -> UIContextMenuConfiguration?)? { + if _configurationForMenuAtLocationClosure == nil { + return nil + } + + return { [weak self] rowType, indexPath in + self?._configurationForMenuAtLocationClosure?(rowType, indexPath) as? UIContextMenuConfiguration + } + } + + public func configurationForMenuAtLocation(_ closure: @escaping ((Item, IndexPath) -> UIContextMenuConfiguration)) -> CellDescriptor { + _configurationForMenuAtLocationClosure = { [unowned self] row, indexPath in + closure(self.typedItem(row), indexPath) + } + return self + } +} diff --git a/DataSource/DataSource+UITableViewDelegate.swift b/DataSource/DataSource+UITableViewDelegate.swift index 9291a76..16b1eed 100644 --- a/DataSource/DataSource+UITableViewDelegate.swift +++ b/DataSource/DataSource+UITableViewDelegate.swift @@ -6,11 +6,10 @@ // Copyright © 2017 aaa - all about apps GmbH. All rights reserved. // -import UIKit import Differ +import UIKit extension DataSource: UITableViewDelegate { - // MARK: Highlighting public func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { @@ -42,7 +41,7 @@ extension DataSource: UITableViewDelegate { closure(visibleRow(at: indexPath), indexPath) return } - + fallbackDelegate?.tableView?(tableView, didUnhighlightRowAt: indexPath) } @@ -73,7 +72,6 @@ extension DataSource: UITableViewDelegate { public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let cellDescriptor = self.cellDescriptor(at: indexPath) - if let closure = cellDescriptor.didSelectClosure ?? didSelect { let selectionResult = closure(visibleRow(at: indexPath), indexPath) @@ -151,13 +149,13 @@ extension DataSource: UITableViewDelegate { return fallbackDelegate?.tableView?(tableView, heightForRowAt: indexPath) ?? tableView.rowHeight } - + public func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { let index = indexPath.section let section = visibleSection(at: index) - // Do not get the CellDescriptor if we are dealing with a LazySection because it would instaniate all the rows, - // i.e. estimatedHeightClosure will not be called for LazySections. Instead, use the estimatedHeight on the + // Do not get the CellDescriptor if we are dealing with a LazySection because it would instantiate all the rows, + // i.e. estimatedHeightClosure will not be called for LazySections. Instead, use the estimatedHeight on the // DataSource, the fallback delegate or a constant. if !(section is LazySectionType) { @@ -185,12 +183,12 @@ extension DataSource: UITableViewDelegate { public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { let sectionDescriptor = self.sectionDescriptor(at: section) - + if let closure = sectionDescriptor?.headerHeightClosure ?? sectionHeaderHeight { return closure(visibleSection(at: section), section).floatValue(for: tableView.style) } - if let result = fallbackDelegate?.tableView?(tableView, heightForHeaderInSection: section) { + if let result = fallbackDelegate?.tableView?(tableView, heightForHeaderInSection: section) { return result } @@ -259,7 +257,7 @@ extension DataSource: UITableViewDelegate { return } - fallbackDelegate?.tableView?(tableView, willDisplay:cell, forRowAt:indexPath) + fallbackDelegate?.tableView?(tableView, willDisplay: cell, forRowAt: indexPath) } public func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { @@ -270,7 +268,7 @@ extension DataSource: UITableViewDelegate { return } - fallbackDelegate?.tableView?(tableView, willDisplayHeaderView:view, forSection:section) + fallbackDelegate?.tableView?(tableView, willDisplayHeaderView: view, forSection: section) } public func tableView(_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) { @@ -281,7 +279,7 @@ extension DataSource: UITableViewDelegate { return } - fallbackDelegate?.tableView?(tableView, willDisplayFooterView:view, forSection:section) + fallbackDelegate?.tableView?(tableView, willDisplayFooterView: view, forSection: section) } // the didEnd delegate methods are only supported on a "fallback" level as we may not have the row or section @@ -293,7 +291,7 @@ extension DataSource: UITableViewDelegate { return } - fallbackDelegate?.tableView?(tableView, didEndDisplaying:cell, forRowAt:indexPath) + fallbackDelegate?.tableView?(tableView, didEndDisplaying: cell, forRowAt: indexPath) } public func tableView(_ tableView: UITableView, didEndDisplayingHeaderView view: UIView, forSection section: Int) { @@ -302,7 +300,7 @@ extension DataSource: UITableViewDelegate { return } - fallbackDelegate?.tableView?(tableView, didEndDisplayingHeaderView:view, forSection:section) + fallbackDelegate?.tableView?(tableView, didEndDisplayingHeaderView: view, forSection: section) } public func tableView(_ tableView: UITableView, didEndDisplayingFooterView view: UIView, forSection section: Int) { @@ -311,7 +309,7 @@ extension DataSource: UITableViewDelegate { return } - fallbackDelegate?.tableView?(tableView, didEndDisplayingFooterView:view, forSection:section) + fallbackDelegate?.tableView?(tableView, didEndDisplayingFooterView: view, forSection: section) } // MARK: Editing @@ -323,7 +321,7 @@ extension DataSource: UITableViewDelegate { return closure(visibleRow(at: indexPath), indexPath) } - if let result = fallbackDelegate?.tableView?(tableView, editingStyleForRowAt:indexPath) { + if let result = fallbackDelegate?.tableView?(tableView, editingStyleForRowAt: indexPath) { return result } @@ -341,7 +339,7 @@ extension DataSource: UITableViewDelegate { return closure(visibleRow(at: indexPath), indexPath) } - return fallbackDelegate?.tableView?(tableView, titleForDeleteConfirmationButtonForRowAt:indexPath) + return fallbackDelegate?.tableView?(tableView, titleForDeleteConfirmationButtonForRowAt: indexPath) } public func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { @@ -351,7 +349,7 @@ extension DataSource: UITableViewDelegate { return closure(visibleRow(at: indexPath), indexPath) } - return fallbackDelegate?.tableView?(tableView, editActionsForRowAt:indexPath) + return fallbackDelegate?.tableView?(tableView, editActionsForRowAt: indexPath) } public func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool { @@ -361,7 +359,7 @@ extension DataSource: UITableViewDelegate { return closure(visibleRow(at: indexPath), indexPath) } - return fallbackDelegate?.tableView?(tableView, shouldIndentWhileEditingRowAt:indexPath) + return fallbackDelegate?.tableView?(tableView, shouldIndentWhileEditingRowAt: indexPath) ?? true } @@ -373,7 +371,7 @@ extension DataSource: UITableViewDelegate { return } - fallbackDelegate?.tableView?(tableView, willBeginEditingRowAt:indexPath) + fallbackDelegate?.tableView?(tableView, willBeginEditingRowAt: indexPath) } public func tableView(_ tableView: UITableView, didEndEditingRowAt indexPath: IndexPath?) { @@ -382,9 +380,9 @@ extension DataSource: UITableViewDelegate { return } - fallbackDelegate?.tableView?(tableView, didEndEditingRowAt:indexPath) + fallbackDelegate?.tableView?(tableView, didEndEditingRowAt: indexPath) } - + // MARK: Moving & Reordering public func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath { @@ -394,11 +392,10 @@ extension DataSource: UITableViewDelegate { return closure(visibleRow(at: sourceIndexPath), (sourceIndexPath, proposedDestinationIndexPath)) } - return fallbackDelegate?.tableView?(tableView, targetIndexPathForMoveFromRowAt:sourceIndexPath, toProposedIndexPath: proposedDestinationIndexPath) + return fallbackDelegate?.tableView?(tableView, targetIndexPathForMoveFromRowAt: sourceIndexPath, toProposedIndexPath: proposedDestinationIndexPath) ?? proposedDestinationIndexPath } - // MARK: Indentation public func tableView(_ tableView: UITableView, indentationLevelForRowAt indexPath: IndexPath) -> Int { @@ -450,23 +447,22 @@ extension DataSource: UITableViewDelegate { // MARK: Focus public func tableView(_ tableView: UITableView, canFocusRowAt indexPath: IndexPath) -> Bool { - return fallbackDelegate?.tableView?(tableView, canFocusRowAt:indexPath) + return fallbackDelegate?.tableView?(tableView, canFocusRowAt: indexPath) ?? true } public func tableView(_ tableView: UITableView, shouldUpdateFocusIn context: UITableViewFocusUpdateContext) -> Bool { - return fallbackDelegate?.tableView?(tableView, shouldUpdateFocusIn:context) + return fallbackDelegate?.tableView?(tableView, shouldUpdateFocusIn: context) ?? true } public func tableView(_ tableView: UITableView, didUpdateFocusIn context: UITableViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { - fallbackDelegate?.tableView?(tableView, didUpdateFocusIn:context, with:coordinator) + fallbackDelegate?.tableView?(tableView, didUpdateFocusIn: context, with: coordinator) } public func indexPathForPreferredFocusedView(in tableView: UITableView) -> IndexPath? { return fallbackDelegate?.indexPathForPreferredFocusedView?(in: tableView) } - } @available(iOS 11,*) @@ -489,3 +485,16 @@ extension DataSource { } } } + +@available(iOS 13,*) +extension DataSource { + public func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { + let cellDescriptor = self.cellDescriptor(at: indexPath) as? CellDescriptorTypeiOS13 + + if let closure = cellDescriptor?.configurationForMenuAtLocationClosure { + return closure(visibleRow(at: indexPath), indexPath) + } else { + return fallbackDelegate?.tableView?(tableView, contextMenuConfigurationForRowAt: indexPath, point: CGPoint(x: 0, y: 0)) + } + } +} diff --git a/DataSource/DataSource.swift b/DataSource/DataSource.swift index 7b8d2ce..f88f379 100644 --- a/DataSource/DataSource.swift +++ b/DataSource/DataSource.swift @@ -6,88 +6,90 @@ // Copyright © 2017 aaa - all about apps GmbH. All rights reserved. // -import UIKit import Differ +import UIKit public class DataSource: NSObject { - public var sections: [SectionType] = [] public internal(set) var visibleSections: [SectionType] = [] // MARK: UITableViewDataSource - public var configure: ((RowType, UITableViewCell, IndexPath) -> Void)? = nil - public var canEdit: ((RowType, IndexPath) -> Bool)? = nil - public var canMove: ((RowType, IndexPath) -> Bool)? = nil - public var sectionIndexTitles: (() -> [String]?)? = nil - public var sectionForSectionIndex: ((String, Int) -> Int)? = nil - public var commitEditing: ((RowType, UITableViewCell.EditingStyle, IndexPath) -> Void)? = nil - public var moveRow: ((RowType, (IndexPath, IndexPath)) -> Void)? = nil + public var configure: ((RowType, UITableViewCell, IndexPath) -> Void)? + public var canEdit: ((RowType, IndexPath) -> Bool)? + public var canMove: ((RowType, IndexPath) -> Bool)? + public var sectionIndexTitles: (() -> [String]?)? + public var sectionForSectionIndex: ((String, Int) -> Int)? + public var commitEditing: ((RowType, UITableViewCell.EditingStyle, IndexPath) -> Void)? + public var moveRow: ((RowType, (IndexPath, IndexPath)) -> Void)? - public var fallbackDataSource: UITableViewDataSource? = nil + public var fallbackDataSource: UITableViewDataSource? // MARK: UITableViewDelegate - public var height: ((RowType, IndexPath) -> CGFloat)? = nil + public var height: ((RowType, IndexPath) -> CGFloat)? // no RowType parameter for estimatedHeight because we do not want to potentially instantiate // a LazyRow just to get the height estimate - public var estimatedHeight: ((IndexPath) -> CGFloat)? = nil + public var estimatedHeight: ((IndexPath) -> CGFloat)? - public var shouldHighlight: ((RowType, IndexPath) -> Bool)? = nil - public var didHighlight: ((RowType, IndexPath) -> Void)? = nil - public var didUnhighlight: ((RowType, IndexPath) -> Void)? = nil + public var shouldHighlight: ((RowType, IndexPath) -> Bool)? + public var didHighlight: ((RowType, IndexPath) -> Void)? + public var didUnhighlight: ((RowType, IndexPath) -> Void)? - public var willSelect: ((RowType, IndexPath) -> IndexPath?)? = nil - public var willDeselect: ((RowType, IndexPath) -> IndexPath?)? = nil - public var didSelect: ((RowType, IndexPath) -> SelectionResult)? = nil - public var didDeselect: ((RowType, IndexPath) -> Void)? = nil + public var willSelect: ((RowType, IndexPath) -> IndexPath?)? + public var willDeselect: ((RowType, IndexPath) -> IndexPath?)? + public var didSelect: ((RowType, IndexPath) -> SelectionResult)? + public var didDeselect: ((RowType, IndexPath) -> Void)? - public var willDisplay: ((RowType, UITableViewCell, IndexPath) -> Void)? = nil - public var didEndDisplaying: ((UITableViewCell, IndexPath) -> Void)? = nil + public var willDisplay: ((RowType, UITableViewCell, IndexPath) -> Void)? + public var didEndDisplaying: ((UITableViewCell, IndexPath) -> Void)? - public var editingStyle: ((RowType, IndexPath) -> UITableViewCell.EditingStyle)? = nil - public var titleForDeleteConfirmationButton: ((RowType, IndexPath) -> String?)? = nil - public var editActions: ((RowType, IndexPath) -> [UITableViewRowAction]?)? = nil - public var shouldIndentWhileEditing: ((RowType, IndexPath) -> Bool)? = nil - public var willBeginEditing: ((RowType, IndexPath) -> Void)? = nil - public var didEndEditing: ((IndexPath?) -> Void)? = nil + public var editingStyle: ((RowType, IndexPath) -> UITableViewCell.EditingStyle)? + public var titleForDeleteConfirmationButton: ((RowType, IndexPath) -> String?)? + public var editActions: ((RowType, IndexPath) -> [UITableViewRowAction]?)? + public var shouldIndentWhileEditing: ((RowType, IndexPath) -> Bool)? + public var willBeginEditing: ((RowType, IndexPath) -> Void)? + public var didEndEditing: ((IndexPath?) -> Void)? - public var sectionHeader: ((SectionType, Int) -> HeaderFooter)? = nil - public var sectionFooter: ((SectionType, Int) -> HeaderFooter)? = nil + public var sectionHeader: ((SectionType, Int) -> HeaderFooter)? + public var sectionFooter: ((SectionType, Int) -> HeaderFooter)? - public var sectionHeaderHeight: ((SectionType, Int) -> SectionHeight)? = nil - public var sectionFooterHeight: ((SectionType, Int) -> SectionHeight)? = nil + public var sectionHeaderHeight: ((SectionType, Int) -> SectionHeight)? + public var sectionFooterHeight: ((SectionType, Int) -> SectionHeight)? - public var willDisplaySectionHeader: ((SectionType, UIView, Int) -> Void)? = nil - public var willDisplaySectionFooter: ((SectionType, UIView, Int) -> Void)? = nil + public var willDisplaySectionHeader: ((SectionType, UIView, Int) -> Void)? + public var willDisplaySectionFooter: ((SectionType, UIView, Int) -> Void)? - public var didEndDisplayingSectionHeader: ((UIView, Int) -> Void)? = nil - public var didEndDisplayingSectionFooter: ((UIView, Int) -> Void)? = nil + public var didEndDisplayingSectionHeader: ((UIView, Int) -> Void)? + public var didEndDisplayingSectionFooter: ((UIView, Int) -> Void)? - public var targetIndexPathForMove: ((RowType, (IndexPath, IndexPath)) -> IndexPath)? = nil - public var indentationLevel: ((RowType, IndexPath) -> Int)? = nil - public var shouldShowMenu: ((RowType, IndexPath) -> Bool)? = nil - public var canPerformAction: ((RowType, Selector, Any?, IndexPath) -> Bool)? = nil - public var performAction: ((RowType, Selector, Any?, IndexPath) -> Void)? = nil - public var canFocus: ((RowType, IndexPath) -> Bool)? = nil + public var targetIndexPathForMove: ((RowType, (IndexPath, IndexPath)) -> IndexPath)? + public var indentationLevel: ((RowType, IndexPath) -> Int)? + public var shouldShowMenu: ((RowType, IndexPath) -> Bool)? + public var canPerformAction: ((RowType, Selector, Any?, IndexPath) -> Bool)? + public var performAction: ((RowType, Selector, Any?, IndexPath) -> Void)? + public var canFocus: ((RowType, IndexPath) -> Bool)? // MARK: Swipe Actions (iOS 11+ only) - private var _leadingSwipeActions: ((RowType, IndexPath) -> Any?)? = nil - private var _trailingSwipeActions: ((RowType, IndexPath) -> Any?)? = nil + + private var _leadingSwipeActions: ((RowType, IndexPath) -> Any?)? + private var _trailingSwipeActions: ((RowType, IndexPath) -> Any?)? + + public var _configurationForMenuAtLocationClosure: ((RowType, IndexPath) -> Any)? // MARK: UITableViewDataSourcePrefetching - public var prefetchRows: (([IndexPath]) -> Void)? = nil - public var cancelPrefetching: (([IndexPath]) -> Void)? = nil + public var prefetchRows: (([IndexPath]) -> Void)? + public var cancelPrefetching: (([IndexPath]) -> Void)? - public weak var fallbackDataSourcePrefetching: UITableViewDataSourcePrefetching? = nil + public weak var fallbackDataSourcePrefetching: UITableViewDataSourcePrefetching? // MARK: Fallback delegate /// Fallback used when DataSource doesn't handle delegate method itself. /// - Note: The fallback delegate needs to be set *before* setting the table view's delegate, otherwise certain delegate methods will never be called. - public weak var fallbackDelegate: UITableViewDelegate? = nil + public weak var fallbackDelegate: UITableViewDelegate? public override func forwardingTarget(for aSelector: Selector!) -> Any? { return fallbackDelegate @@ -135,11 +137,13 @@ public class DataSource: NSObject { return cellDescriptors.values.contains(where: { ($0 as? CellDescriptorTypeiOS11)?.trailingSwipeActionsClosure != nil }) } + // MARK: ContextMenu + // MARK: Additional - public var isRowHidden: ((RowType, IndexPath) -> Bool)? = nil - public var isSectionHidden: ((SectionType, Int) -> Bool)? = nil - public var update: ((RowType, UITableViewCell, IndexPath) -> Void)? = nil + public var isRowHidden: ((RowType, IndexPath) -> Bool)? + public var isSectionHidden: ((SectionType, Int) -> Bool)? + public var update: ((RowType, UITableViewCell, IndexPath) -> Void)? // MARK: Internal @@ -159,15 +163,15 @@ public class DataSource: NSObject { self.cellDescriptors[d.rowIdentifier] = d } - self.addDescriptorIfNotSet(SeparatorLineCell.descriptorLine) - self.addDescriptorIfNotSet(SeparatorLineCell.descriptorCustomView) + addDescriptorIfNotSet(SeparatorLineCell.descriptorLine) + addDescriptorIfNotSet(SeparatorLineCell.descriptorCustomView) let defaultSectionDescriptors: [SectionDescriptorType] = [ SectionDescriptor(), SectionDescriptor() - .header { (title, _) in + .header { title, _ in .title(title) - } + } ] for d in defaultSectionDescriptors { @@ -180,8 +184,8 @@ public class DataSource: NSObject { } private func addDescriptorIfNotSet(_ descriptor: CellDescriptorType) { - if self.cellDescriptors[descriptor.rowIdentifier] == nil { - self.cellDescriptors[descriptor.rowIdentifier] = descriptor + if cellDescriptors[descriptor.rowIdentifier] == nil { + cellDescriptors[descriptor.rowIdentifier] = descriptor } } @@ -244,7 +248,7 @@ public class DataSource: NSObject { return nil } } - + // MARK: Visibility internal func updateVisibility() { @@ -266,7 +270,7 @@ public class DataSource: NSObject { isHidden = false } - if isHidden == false && section.numberOfVisibleRows > 0 { + if isHidden == false, section.numberOfVisibleRows > 0 { visibleSections.append(section) } } @@ -300,8 +304,7 @@ public class DataSource: NSObject { rowReloadAnimation: UITableView.RowAnimation = .none, sectionDeletionAnimation: UITableView.RowAnimation = .fade, sectionInsertionAnimation: UITableView.RowAnimation = .fade - ) { - + ) { let oldSections = visibleSections.map { $0.diffableSection } let newSections = updateSectionVisiblity() let diffableNewSections = newSections.map { $0.diffableSection } @@ -309,7 +312,7 @@ public class DataSource: NSObject { let diff = computeDiff(oldSections: oldSections, newSections: diffableNewSections) let updates = computeUpdate(oldSections: oldSections, newSections: diffableNewSections) - self.visibleSections = newSections + visibleSections = newSections if rowReloadAnimation == .none { for update in updates { @@ -323,7 +326,8 @@ public class DataSource: NSObject { rowInsertionAnimation: rowInsertionAnimation, rowReloadAnimation: rowReloadAnimation, sectionDeletionAnimation: sectionDeletionAnimation, - sectionInsertionAnimation: sectionInsertionAnimation) + sectionInsertionAnimation: sectionInsertionAnimation + ) } public func updateRow(_ tableView: UITableView, row: RowType, at indexPath: IndexPath) { @@ -331,9 +335,9 @@ public class DataSource: NSObject { let closure = cellDescriptor.updateClosure - ?? update - ?? cellDescriptor.configureClosure - ?? configure + ?? update + ?? cellDescriptor.configureClosure + ?? configure if let cell = tableView.cellForRow(at: indexPath), let closure = closure { closure(row, cell, indexPath) @@ -349,8 +353,8 @@ extension DataSource { return nil } - return { [weak self] (rowType, indexPath) in - return self?._leadingSwipeActions?(rowType, indexPath) as? UISwipeActionsConfiguration + return { [weak self] rowType, indexPath in + self?._leadingSwipeActions?(rowType, indexPath) as? UISwipeActionsConfiguration } } set { @@ -364,14 +368,31 @@ extension DataSource { return nil } - return { [weak self] (rowType, indexPath) in - return self?._trailingSwipeActions?(rowType, indexPath) as? UISwipeActionsConfiguration + return { [weak self] rowType, indexPath in + self?._trailingSwipeActions?(rowType, indexPath) as? UISwipeActionsConfiguration } } set { _trailingSwipeActions = newValue } } - } +@available(iOS 13,*) +extension DataSource { + public var configurationForMenuAtLocationClosure: ((RowType, IndexPath) -> UIContextMenuConfiguration?)? { + get { + if _configurationForMenuAtLocationClosure == nil { + return nil + } + + return { [weak self] rowType, indexPath in + self?._configurationForMenuAtLocationClosure?(rowType, indexPath) as? UIContextMenuConfiguration + } + } + + set { + _configurationForMenuAtLocationClosure = newValue + } + } +} diff --git a/Example/Storyboards/Base.lproj/Main.storyboard b/Example/Storyboards/Base.lproj/Main.storyboard index 69eed35..4944c47 100644 --- a/Example/Storyboards/Base.lproj/Main.storyboard +++ b/Example/Storyboards/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -48,6 +48,7 @@ + @@ -215,7 +216,7 @@ - + @@ -360,7 +361,26 @@ - + + + + + + + + + + + + + + + + + + + + diff --git a/Example/ViewControllers/ContextMenuViewController.swift b/Example/ViewControllers/ContextMenuViewController.swift new file mode 100644 index 0000000..c4b23bc --- /dev/null +++ b/Example/ViewControllers/ContextMenuViewController.swift @@ -0,0 +1,67 @@ +// +// ContextMenuViewController.swift +// Example +// +// Created by Sandin Dulić on 09.09.20. +// Copyright © 2020 aaa - all about apps GmbH. All rights reserved. +// + +import UIKit +import DataSource + +@available(iOS 13.0, *) +class ContextMenuViewController: UITableViewController { + lazy var dataSource: DataSource = { + DataSource( + cellDescriptors: [ + CellDescriptor() + .configure { item, cell, _ in + cell.textLabel?.text = item + } + .configurationForMenuAtLocation { [weak self] _, indexPath -> UIContextMenuConfiguration in + guard let self = self else { return UIContextMenuConfiguration() } + let index = indexPath.row + + let identifier = "\(index)" as NSString + return self.createContextMenuConfiguration(with: identifier) + } + ]) + }() + + override func viewDidLoad() { + super.viewDidLoad() + + title = "Context menu example" + + tableView.dataSource = dataSource + tableView.delegate = dataSource + + dataSource.sections = createSections() + dataSource.reloadData(tableView, animated: false) + } + + func createSections() -> [Section] { + let items = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"] + + + return [ + Section(items: items) + ] + } + + private func createContextMenuConfiguration(with identifier: NSString) -> UIContextMenuConfiguration { + UIContextMenuConfiguration(identifier: identifier, previewProvider: nil) { _ in + let mapAction = UIAction( + title: "Some title", + image: UIImage(systemName: "map")) { _ in + } + + let shareAction = UIAction( + title: "Some title 2", + image: UIImage(systemName: "square.and.arrow.up")) { _ in + } + + return UIMenu(title: "", image: nil, children: [mapAction, shareAction]) + } + } +} diff --git a/Example/ViewControllers/Examples/DiffViewController.swift b/Example/ViewControllers/Examples/DiffViewController.swift index 914aced..819a05b 100644 --- a/Example/ViewControllers/Examples/DiffViewController.swift +++ b/Example/ViewControllers/Examples/DiffViewController.swift @@ -6,23 +6,22 @@ // Copyright © 2017 aaa - all about apps GmbH. All rights reserved. // -import UIKit import DataSource +import UIKit // MARK: - View Controller class DiffViewController: UITableViewController { - var counter = 0 lazy var dataSource: DataSource = { DataSource( cellDescriptors: [ CellDescriptor() - .configure { (item, cell, indexPath) in + .configure { item, cell, _ in cell.textLabel?.text = item.text } - .update { (item, cell, indexPath) in + .update { item, cell, _ in cell.textLabel?.update(text: item.text, animated: true) } ]) @@ -56,22 +55,21 @@ class DiffViewController: UITableViewController { }) ] } - + @IBAction func refresh(_ sender: Any) { counter += 1 dataSource.sections = createSections() dataSource.reloadDataAnimated(tableView, - rowDeletionAnimation: .automatic, - rowInsertionAnimation: .automatic, - rowReloadAnimation: .none) + rowDeletionAnimation: .automatic, + rowInsertionAnimation: .automatic, + rowReloadAnimation: .none) } } // MARK: - Diff Item struct DiffItem: Hashable { - let value: Int let text: String @@ -85,4 +83,4 @@ struct DiffItem: Hashable { } } -extension DiffItem: Diffable { } +extension DiffItem: Diffable {} diff --git a/Example/ViewControllers/StartViewController.swift b/Example/ViewControllers/StartViewController.swift index 2950738..ea37b48 100644 --- a/Example/ViewControllers/StartViewController.swift +++ b/Example/ViewControllers/StartViewController.swift @@ -41,6 +41,7 @@ class StartViewController: UITableViewController { Example(title: "Swipe To Delete", segue: "showSwipeToDelete"), Example(title: "Custom separators", segue: "showSeparatedSection"), Example(title: "Expandable Cell", segue: "showExpandableCell"), + Example(title: "Context Menu", segue: "showContextMenuExample") ] let separatorItems = [