diff --git a/.swift-version b/.swift-version index 8012ebb..6e63660 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -4.2 \ No newline at end of file +5.0 \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 228c26b..570d984 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode10 +osx_image: xcode11 branches: only: - master @@ -7,17 +7,15 @@ env: global: - LC_CTYPE=en_US.UTF-8 - LANG=en_US.UTF-8 - - IOS_SDK=iphonesimulator12.0 + - IOS_SDK=iphonesimulator13.0 - SCHEME_IOS="TableKit" - PROJECT_FRAMEWORK="TableKit.xcodeproj" matrix: - - DESTINATION="OS=9.0,name=iPhone 6" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" - - DESTINATION="OS=9.1,name=iPhone 6 Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" - - DESTINATION="OS=9.2,name=iPhone 6S" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" - - DESTINATION="OS=9.3,name=iPhone 6S Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" - - DESTINATION="OS=10.0,name=iPhone 5" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" + - DESTINATION="OS=10.3.1,name=iPhone 5" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" + - DESTINATION="OS=11.1,name=iPhone 6" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" - DESTINATION="OS=12.0,name=iPhone 7 Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" + - DESTINATION="OS=13.0,name=iPhone 11" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" script: - set -o pipefail diff --git a/CHANGELOG.md b/CHANGELOG.md index ebb1a04..3eca5a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. +## [2.10.0](https://github.com/maxsokolov/TableKit/releases/tag/2.10.0) +Released on 2019-09-29. +- Swift 5.1 support. + +## [2.9.0](https://github.com/maxsokolov/TableKit/releases/tag/2.9.0) +Released on 2019-04-04. +- Swift 5.0 support. + ## [2.8.0](https://github.com/maxsokolov/TableKit/releases/tag/2.8.0) Released on 2018-09-30. - Swift 4.2 support. diff --git a/Demo/TableKitDemo.xcodeproj/project.pbxproj b/Demo/TableKitDemo.xcodeproj/project.pbxproj index 17885b9..eef710e 100644 --- a/Demo/TableKitDemo.xcodeproj/project.pbxproj +++ b/Demo/TableKitDemo.xcodeproj/project.pbxproj @@ -248,6 +248,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -377,7 +378,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -425,7 +426,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -443,7 +444,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo; PRODUCT_NAME = TableKitDemo; PROVISIONING_PROFILE = ""; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -460,7 +461,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo; PRODUCT_NAME = TableKitDemo; PROVISIONING_PROFILE = ""; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Release; }; diff --git a/Package.swift b/Package.swift index 35ee9ed..5ce7c3d 100644 --- a/Package.swift +++ b/Package.swift @@ -1,5 +1,20 @@ +// swift-tools-version:5.0 +// The swift-tools-version declares the minimum version of Swift required to build this package. + import PackageDescription let package = Package( - name: "TableKit" -) \ No newline at end of file + name: "TableKit", + + products: [ + .library( + name: "TableKit", + targets: ["TableKit"]), + ], + + targets: [ + .target( + name: "TableKit", + path: "Sources") + ] +) diff --git a/README.md b/README.md index a4583c0..626274c 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@

Build Status - Swift 4.2 compatible + Swift 5.1 compatible Carthage compatible - CocoaPods compatible + CocoaPods compatible Platform iOS License: MIT

@@ -204,7 +204,7 @@ tableDirector += rows Done, your table is ready. ## Automatic cell registration -TableKit can register your cells in a table view automatically. In case if your reusable cell id mathces cell's xib name: +TableKit can register your cells in a table view automatically. In case if your reusable cell id matches cell's xib name: ```ruby MyTableViewCell.swift diff --git a/Sources/Expandable.swift b/Sources/Expandable.swift index 6553e9c..e3cb3a1 100644 --- a/Sources/Expandable.swift +++ b/Sources/Expandable.swift @@ -40,7 +40,7 @@ extension Expandable where Self: UITableViewCell & ConfigurableCell { animationDuration: TimeInterval = .defaultExpandableAnimationDuration) { guard let viewModel = viewModel, - let stateIndex = viewModel.availableStates.index(where: { $0 == viewModel.expandableState }) else { + let stateIndex = viewModel.availableStates.firstIndex(where: { $0 == viewModel.expandableState }) else { return } diff --git a/Sources/TableDirector.swift b/Sources/TableDirector.swift index aa6473b..e269398 100644 --- a/Sources/TableDirector.swift +++ b/Sources/TableDirector.swift @@ -309,15 +309,71 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate { return indexPath } + open func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? { + if hasAction(.willDeselect, atIndexPath: indexPath) { + return invoke(action: .willDeselect, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? IndexPath + } + + return indexPath + } + + @available(iOS 13.0, *) + open func tableView( + _ tableView: UITableView, + shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath) -> Bool + { + invoke(action: .shouldBeginMultipleSelection, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? Bool ?? false + } + + @available(iOS 13.0, *) + open func tableView( + _ tableView: UITableView, + didBeginMultipleSelectionInteractionAt indexPath: IndexPath) + { + invoke(action: .didBeginMultipleSelection, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) + } + + @available(iOS 13.0, *) + open func tableView( + _ tableView: UITableView, + contextMenuConfigurationForRowAt indexPath: IndexPath, + point: CGPoint) -> UIContextMenuConfiguration? + { + invoke(action: .showContextMenu, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath, userInfo: [TableKitUserInfoKeys.ContextMenuInvokePoint: point]) as? UIContextMenuConfiguration + } + // MARK: - Row editing open func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return sections[indexPath.section].rows[indexPath.row].isEditingAllowed(forIndexPath: indexPath) } + @available(iOS, deprecated: 11, message: "Use leadingSwipeActionsConfigurationForRowAt(:_) and trailingSwipeActionsConfigurationForRowAt(:_) instead") open func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { return sections[indexPath.section].rows[indexPath.row].editingActions } + @available(iOS 11, *) + open func tableView(_ tableView: UITableView, + leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { + let currentRow = sections[indexPath.section].rows[indexPath.row] + let configuration = UISwipeActionsConfiguration(actions: currentRow.leadingContextualActions) + + configuration.performsFirstActionWithFullSwipe = currentRow.performsFirstActionWithFullSwipe + + return configuration + } + + @available(iOS 11, *) + open func tableView(_ tableView: UITableView, + trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { + let currentRow = sections[indexPath.section].rows[indexPath.row] + let configuration = UISwipeActionsConfiguration(actions: currentRow.trailingContextualActions) + + configuration.performsFirstActionWithFullSwipe = currentRow.performsFirstActionWithFullSwipe + + return configuration + } + open func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle { if invoke(action: .canDelete, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? Bool ?? false { return UITableViewCell.EditingStyle.delete @@ -347,6 +403,11 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate { open func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { invoke(action: .move, cell: tableView.cellForRow(at: sourceIndexPath), indexPath: sourceIndexPath, userInfo: [TableKitUserInfoKeys.CellMoveDestinationIndexPath: destinationIndexPath]) } + + open func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) { + let cell = tableView.cellForRow(at: indexPath) + invoke(action: .accessoryButtonTap, cell: cell, indexPath: indexPath) + } } // MARK: - Sections manipulation diff --git a/Sources/TableKit.swift b/Sources/TableKit.swift index 8206baf..1aba0bd 100644 --- a/Sources/TableKit.swift +++ b/Sources/TableKit.swift @@ -27,6 +27,7 @@ struct TableKitNotifications { public struct TableKitUserInfoKeys { public static let CellMoveDestinationIndexPath = "TableKitCellMoveDestinationIndexPath" public static let CellCanMoveProposedIndexPath = "CellCanMoveProposedIndexPath" + public static let ContextMenuInvokePoint = "ContextMenuInvokePoint" } public protocol RowConfigurable { @@ -37,7 +38,18 @@ public protocol RowConfigurable { public protocol RowActionable { + @available(iOS 11, *) + var leadingContextualActions: [UIContextualAction] { get } + + @available(iOS 11, *) + var trailingContextualActions: [UIContextualAction] { get } + + @available(iOS 11, *) + var performsFirstActionWithFullSwipe: Bool { get } + + @available(iOS, deprecated: 11, message: "Use leadingContextualActions, trailingContextualActions instead") var editingActions: [UITableViewRowAction]? { get } + func isEditingAllowed(forIndexPath indexPath: IndexPath) -> Bool func invoke( @@ -71,9 +83,12 @@ public enum TableRowActionType { case select case deselect case willSelect + case willDeselect case willDisplay case didEndDisplaying case shouldHighlight + case shouldBeginMultipleSelection + case didBeginMultipleSelection case height case canEdit case configure @@ -81,6 +96,8 @@ public enum TableRowActionType { case canMove case canMoveTo case move + case showContextMenu + case accessoryButtonTap case custom(String) var key: String { diff --git a/Sources/TableRow.swift b/Sources/TableRow.swift index 8a697fd..6679595 100644 --- a/Sources/TableRow.swift +++ b/Sources/TableRow.swift @@ -21,10 +21,27 @@ import UIKit open class TableRow: Row where CellType: UITableViewCell { - + public let item: CellType.CellData private lazy var actions = [String: [TableRowAction]]() - private(set) open var editingActions: [UITableViewRowAction]? + + @available(iOS, deprecated: 11, message: "Use leadingContextualActions, trailingContextualActions instead") + open private(set) var editingActions: [UITableViewRowAction]? + + @available(iOS 11, *) + open var leadingContextualActions: [UIContextualAction] { + [] + } + + @available(iOS 11, *) + open var trailingContextualActions: [UIContextualAction] { + [] + } + + @available(iOS 11, *) + open var performsFirstActionWithFullSwipe: Bool { + false + } open var hashValue: Int { return ObjectIdentifier(self).hashValue @@ -50,10 +67,23 @@ open class TableRow: Row where CellType: UITableView return CellType.self } - public init(item: CellType.CellData, actions: [TableRowAction]? = nil, editingActions: [UITableViewRowAction]? = nil) { + @available(iOS, deprecated: 11, message: "Use leadingContextualActions, trailingContextualActions instead") + public init(item: CellType.CellData, + actions: [TableRowAction]? = nil, + editingActions: [UITableViewRowAction]? = nil) { self.item = item self.editingActions = editingActions + + actions?.forEach { on($0) } + } + + @available(iOS 11, *) + public init(item: CellType.CellData, + actions: [TableRowAction]? = nil) { + + self.item = item + actions?.forEach { on($0) } } @@ -81,7 +111,14 @@ open class TableRow: Row where CellType: UITableView if actions[TableRowActionType.canEdit.key] != nil { return invoke(action: .canEdit, cell: nil, path: indexPath) as? Bool ?? false } - return editingActions?.isEmpty == false || actions[TableRowActionType.clickDelete.key] != nil + + if #available(iOS 11, *) { + return !leadingContextualActions.isEmpty + || !trailingContextualActions.isEmpty + || actions[TableRowActionType.clickDelete.key] != nil + } else { + return editingActions?.isEmpty == false || actions[TableRowActionType.clickDelete.key] != nil + } } // MARK: - actions - @@ -117,7 +154,7 @@ open class TableRow: Row where CellType: UITableView open func removeAction(forActionId actionId: String) { for (key, value) in actions { - if let actionIndex = value.index(where: { $0.id == actionId }) { + if let actionIndex = value.firstIndex(where: { $0.id == actionId }) { actions[key]?.remove(at: actionIndex) } } diff --git a/TableKit.podspec b/TableKit.podspec index 0a92cd7..2db6237 100644 --- a/TableKit.podspec +++ b/TableKit.podspec @@ -2,7 +2,7 @@ Pod::Spec.new do |s| s.name = 'TableKit' s.module_name = 'TableKit' - s.version = '2.8.1' + s.version = '2.11.0' s.homepage = 'https://github.com/maxsokolov/TableKit' s.summary = 'Type-safe declarative table views with Swift.' diff --git a/TableKit.xcodeproj/project.pbxproj b/TableKit.xcodeproj/project.pbxproj index 43a4aa8..990d148 100644 --- a/TableKit.xcodeproj/project.pbxproj +++ b/TableKit.xcodeproj/project.pbxproj @@ -213,6 +213,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = DA9EA74C1D0B679A0021F650; @@ -339,7 +340,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -392,7 +393,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -417,7 +418,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -437,7 +438,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKit; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -449,7 +450,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -461,7 +462,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Release; }; diff --git a/Tests/TableKitTests.swift b/Tests/TableKitTests.swift index ded9bd6..d9d5b11 100644 --- a/Tests/TableKitTests.swift +++ b/Tests/TableKitTests.swift @@ -74,7 +74,10 @@ class TableKitTests: XCTestCase { super.setUp() testController = TestController() - testController.view.isHidden = false + testController.tableView.frame = UIScreen.main.bounds + testController.tableView.isHidden = false + testController.tableView.setNeedsLayout() + testController.tableView.layoutIfNeeded() } override func tearDown() {