From e595e24c9d313a6b6e576837bd099193a058283a Mon Sep 17 00:00:00 2001 From: schrockblock Date: Tue, 14 Jun 2022 16:39:39 -0400 Subject: [PATCH 1/2] view models, combine integration --- .../FlexDataSource.xcodeproj/project.pbxproj | 61 ------------------- .../FlexCollectionDataSource.swift | 10 +++ .../FlexCollectionViewModel.swift | 36 +++++++++++ ...eDataSource.swift => FlexDataSource.swift} | 12 +++- .../flex-data-source/FlexTableViewModel.swift | 36 +++++++++++ 5 files changed, 93 insertions(+), 62 deletions(-) create mode 100644 Sources/flex-data-source/FlexCollectionViewModel.swift rename Sources/flex-data-source/{FlexSimpleDataSource.swift => FlexDataSource.swift} (82%) create mode 100644 Sources/flex-data-source/FlexTableViewModel.swift diff --git a/Example/FlexDataSource.xcodeproj/project.pbxproj b/Example/FlexDataSource.xcodeproj/project.pbxproj index dc797c6..967f6e1 100644 --- a/Example/FlexDataSource.xcodeproj/project.pbxproj +++ b/Example/FlexDataSource.xcodeproj/project.pbxproj @@ -21,17 +21,6 @@ 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; }; 60F5B00A42193B3AF34EFF1F /* Pods_FlexDataSource_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70B1472C8F94AAAB3D29C47C /* Pods_FlexDataSource_Tests.framework */; }; - 6431743A265C542400BB682B /* FlexSimpleDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6431742F265C542400BB682B /* FlexSimpleDataSource.swift */; }; - 6431743B265C542400BB682B /* Array+Flex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64317430265C542400BB682B /* Array+Flex.swift */; }; - 6431743C265C542400BB682B /* FlexDataSourceSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64317431265C542400BB682B /* FlexDataSourceSection.swift */; }; - 6431743D265C542400BB682B /* Swipeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64317432265C542400BB682B /* Swipeable.swift */; }; - 6431743E265C542400BB682B /* FlexTitledDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64317433265C542400BB682B /* FlexTitledDataSource.swift */; }; - 6431743F265C542400BB682B /* Tappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64317434265C542400BB682B /* Tappable.swift */; }; - 64317440265C542400BB682B /* FlexCollectionDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64317435265C542400BB682B /* FlexCollectionDataSource.swift */; }; - 64317441265C542400BB682B /* FlexDataSourceItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64317436265C542400BB682B /* FlexDataSourceItem.swift */; }; - 64317442265C542400BB682B /* FlexDataSourceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64317437265C542400BB682B /* FlexDataSourceProtocol.swift */; }; - 64317443265C542400BB682B /* FlexCollectionSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64317438265C542400BB682B /* FlexCollectionSection.swift */; }; - 64317444265C542400BB682B /* FlexCollectionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64317439265C542400BB682B /* FlexCollectionItem.swift */; }; 89D097AA605F356244FA4433 /* Pods_FlexDataSource_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B58498B2EB53A67483D9A3E4 /* Pods_FlexDataSource_Example.framework */; }; /* End PBXBuildFile section */ @@ -69,17 +58,6 @@ 607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6431742A265C53D800BB682B /* flex_data_sourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = flex_data_sourceTests.swift; sourceTree = ""; }; 6431742E265C53D800BB682B /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Package.swift; path = ../Package.swift; sourceTree = ""; }; - 6431742F265C542400BB682B /* FlexSimpleDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexSimpleDataSource.swift; sourceTree = ""; }; - 64317430265C542400BB682B /* Array+Flex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Flex.swift"; sourceTree = ""; }; - 64317431265C542400BB682B /* FlexDataSourceSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexDataSourceSection.swift; sourceTree = ""; }; - 64317432265C542400BB682B /* Swipeable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Swipeable.swift; sourceTree = ""; }; - 64317433265C542400BB682B /* FlexTitledDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexTitledDataSource.swift; sourceTree = ""; }; - 64317434265C542400BB682B /* Tappable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tappable.swift; sourceTree = ""; }; - 64317435265C542400BB682B /* FlexCollectionDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexCollectionDataSource.swift; sourceTree = ""; }; - 64317436265C542400BB682B /* FlexDataSourceItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexDataSourceItem.swift; sourceTree = ""; }; - 64317437265C542400BB682B /* FlexDataSourceProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexDataSourceProtocol.swift; sourceTree = ""; }; - 64317438265C542400BB682B /* FlexCollectionSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexCollectionSection.swift; sourceTree = ""; }; - 64317439265C542400BB682B /* FlexCollectionItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexCollectionItem.swift; sourceTree = ""; }; 70B1472C8F94AAAB3D29C47C /* Pods_FlexDataSource_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FlexDataSource_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 879D79256B72CCA876FDF46B /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 88E8F3051D2D88F16AFB7F97 /* FlexDataSource.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = FlexDataSource.podspec; path = ../FlexDataSource.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; @@ -123,7 +101,6 @@ children = ( 23D949362718EFCF0008D371 /* .circleci */, 6431742E265C53D800BB682B /* Package.swift */, - 6431742B265C53D800BB682B /* Sources */, 64317428265C53D800BB682B /* Tests */, 494C77C1242E6DD200B8C018 /* Example.playground */, 607FACF51AFB993E008FA782 /* Podspec Metadata */, @@ -217,33 +194,6 @@ path = "flex-data-sourceTests"; sourceTree = ""; }; - 6431742B265C53D800BB682B /* Sources */ = { - isa = PBXGroup; - children = ( - 6431742C265C53D800BB682B /* flex-data-source */, - ); - name = Sources; - path = ../Sources; - sourceTree = ""; - }; - 6431742C265C53D800BB682B /* flex-data-source */ = { - isa = PBXGroup; - children = ( - 64317430265C542400BB682B /* Array+Flex.swift */, - 64317435265C542400BB682B /* FlexCollectionDataSource.swift */, - 64317439265C542400BB682B /* FlexCollectionItem.swift */, - 64317438265C542400BB682B /* FlexCollectionSection.swift */, - 64317437265C542400BB682B /* FlexDataSourceProtocol.swift */, - 64317436265C542400BB682B /* FlexDataSourceItem.swift */, - 64317431265C542400BB682B /* FlexDataSourceSection.swift */, - 6431742F265C542400BB682B /* FlexSimpleDataSource.swift */, - 64317433265C542400BB682B /* FlexTitledDataSource.swift */, - 64317432265C542400BB682B /* Swipeable.swift */, - 64317434265C542400BB682B /* Tappable.swift */, - ); - path = "flex-data-source"; - sourceTree = ""; - }; CBB51F0C6B4320961CD22F51 /* Pods */ = { isa = PBXGroup; children = ( @@ -444,19 +394,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6431743B265C542400BB682B /* Array+Flex.swift in Sources */, - 6431743A265C542400BB682B /* FlexSimpleDataSource.swift in Sources */, - 6431743F265C542400BB682B /* Tappable.swift in Sources */, - 64317440265C542400BB682B /* FlexCollectionDataSource.swift in Sources */, - 6431743C265C542400BB682B /* FlexDataSourceSection.swift in Sources */, 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */, - 64317443265C542400BB682B /* FlexCollectionSection.swift in Sources */, - 64317441265C542400BB682B /* FlexDataSourceItem.swift in Sources */, - 6431743E265C542400BB682B /* FlexTitledDataSource.swift in Sources */, - 6431743D265C542400BB682B /* Swipeable.swift in Sources */, - 64317442265C542400BB682B /* FlexDataSourceProtocol.swift in Sources */, 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, - 64317444265C542400BB682B /* FlexCollectionItem.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/flex-data-source/FlexCollectionDataSource.swift b/Sources/flex-data-source/FlexCollectionDataSource.swift index b4f2f44..58d64fb 100644 --- a/Sources/flex-data-source/FlexCollectionDataSource.swift +++ b/Sources/flex-data-source/FlexCollectionDataSource.swift @@ -68,6 +68,16 @@ open class FlexCollectionDataSource: FPUICollectionViewDatasource { } return UICollectionViewCell() } + + open func setSections(_ sections: [FlexCollectionSection]?) { + self.sections = sections + collectionView?.reloadData() + } + + open func setItems(_ items: [FlexCollectionItem]?) { + let section = FlexCollectionSection(title: nil, items: items) + setSections([section]) + } } // MARK: - Tapping diff --git a/Sources/flex-data-source/FlexCollectionViewModel.swift b/Sources/flex-data-source/FlexCollectionViewModel.swift new file mode 100644 index 0000000..947d08c --- /dev/null +++ b/Sources/flex-data-source/FlexCollectionViewModel.swift @@ -0,0 +1,36 @@ +// +// FlexCollectionViewModel.swift +// FlexDataSource +// +// Created by Elliot Schrock on 6/14/22. +// + +import fuikit +import Combine + +open class FlexCollectionViewModel { + open var dataSource: FlexCollectionDataSource { didSet { didSetDataSource() }} + open var delegate: FPUICollectionViewDelegate { didSet { didSetTableDelegate() }} + + public var collectionView: UICollectionView? { didSet { configureTableView() }} + + public init(_ ds: FlexCollectionDataSource = FlexCollectionDataSource(), _ delegate: FPUICollectionViewDelegate = FPUICollectionViewDelegate()) { + self.dataSource = ds + self.delegate = delegate + } + + open func didSetDataSource() { configureTableView() } + open func didSetTableDelegate() { configureTableView() } + open func configureTableView() { + dataSource.collectionView = collectionView + collectionView?.delegate = delegate + } +} + +public extension FlexCollectionViewModel { + @available(iOS 13.0, *) + convenience init(_ publisher: AnyPublisher<[FlexCollectionItem], Never>, _ cancelBag: inout Set) { + self.init() + publisher.sink(receiveValue: dataSource.setItems(_:)).store(in: &cancelBag) + } +} diff --git a/Sources/flex-data-source/FlexSimpleDataSource.swift b/Sources/flex-data-source/FlexDataSource.swift similarity index 82% rename from Sources/flex-data-source/FlexSimpleDataSource.swift rename to Sources/flex-data-source/FlexDataSource.swift index 0e2a8aa..7bf1dcf 100644 --- a/Sources/flex-data-source/FlexSimpleDataSource.swift +++ b/Sources/flex-data-source/FlexDataSource.swift @@ -7,9 +7,9 @@ import UIKit import fuikit +import Combine open class FlexDataSource: FPUITableViewDataSource, FlexDataSourceProtocol { - public var tableView: UITableView? { didSet { registerCells() @@ -44,4 +44,14 @@ open class FlexDataSource: FPUITableViewDataSource, FlexDataSourceProtocol { let section = FlexDataSourceSection(title: nil, items: items) self.init(tableView, [section]) } + + open func setSections(_ sections: [FlexDataSourceSection]?) { + self.sections = sections + tableView?.reloadData() + } + + open func setItems(_ items: [FlexDataSourceItem]?) { + let section = FlexDataSourceSection(title: nil, items: items) + setSections([section]) + } } diff --git a/Sources/flex-data-source/FlexTableViewModel.swift b/Sources/flex-data-source/FlexTableViewModel.swift new file mode 100644 index 0000000..e84cf1c --- /dev/null +++ b/Sources/flex-data-source/FlexTableViewModel.swift @@ -0,0 +1,36 @@ +// +// FlexTableViewModel.swift +// FlexDataSource +// +// Created by Elliot Schrock on 6/12/22. +// + +import fuikit +import Combine + +open class FlexTableViewModel { + open var dataSource: FlexDataSource { didSet { didSetDataSource() }} + open var tableDelegate: FPUITableViewDelegate { didSet { didSetTableDelegate() }} + + public var tableView: UITableView? { didSet { configureTableView() }} + + public init(_ ds: FlexDataSource = FlexDataSource(), _ delegate: FPUITableViewDelegate = FPUITableViewDelegate()) { + self.dataSource = ds + self.tableDelegate = delegate + } + + open func didSetDataSource() { configureTableView() } + open func didSetTableDelegate() { configureTableView() } + open func configureTableView() { + dataSource.tableView = tableView + tableView?.delegate = tableDelegate + } +} + +public extension FlexTableViewModel { + @available(iOS 13.0, *) + convenience init(_ publisher: AnyPublisher<[FlexDataSourceItem], Never>, _ cancelBag: inout Set) { + self.init() + publisher.sink(receiveValue: dataSource.setItems(_:)).store(in: &cancelBag) + } +} From 36db19e4dfaac413824dbfe93c07366ceffa0078 Mon Sep 17 00:00:00 2001 From: schrockblock Date: Tue, 14 Jun 2022 18:58:17 -0400 Subject: [PATCH 2/2] simplify model items --- Example/Tests/FlexCollectionItemTests.swift | 2 +- Example/Tests/FlexDataSourceItemTests.swift | 7 ++- Example/Tests/FlexItemsTests.swift | 10 ++-- .../FlexCollectionDataSource.swift | 2 +- .../flex-data-source/FlexCollectionItem.swift | 2 +- .../FlexCollectionItems.swift | 45 +++++++--------- .../flex-data-source/FlexDataSourceItem.swift | 21 ++++---- .../FlexDataSourceProtocol.swift | 8 +-- Sources/flex-data-source/FlexItems.swift | 51 +++++++++---------- Sources/flex-data-source/Swipeable.swift | 4 +- Sources/flex-data-source/Tappable.swift | 4 +- 11 files changed, 72 insertions(+), 84 deletions(-) diff --git a/Example/Tests/FlexCollectionItemTests.swift b/Example/Tests/FlexCollectionItemTests.swift index cd156e8..4b3fae3 100644 --- a/Example/Tests/FlexCollectionItemTests.swift +++ b/Example/Tests/FlexCollectionItemTests.swift @@ -39,7 +39,7 @@ class FlexCollectionItemTests: XCTestCase { pressed = true } item.configureCell(cell) - item.onTap() + item.onTap?() XCTAssertEqual(cell.backgroundColor, .red) XCTAssertEqual(item.cellIdentifier(), cellID) XCTAssertTrue(pressed == true) diff --git a/Example/Tests/FlexDataSourceItemTests.swift b/Example/Tests/FlexDataSourceItemTests.swift index 86bb365..f320efc 100644 --- a/Example/Tests/FlexDataSourceItemTests.swift +++ b/Example/Tests/FlexDataSourceItemTests.swift @@ -11,7 +11,6 @@ import LithoOperators @testable import FlexDataSource class FlexDataSourceItemTests: XCTestCase { - func testFunctionalFlexDataSourceItem() { let identifier = "TableViewCell" let item = FunctionalFlexDataSourceItem(identifier: identifier, set(\UITableViewCell.backgroundColor, .red)) @@ -38,7 +37,7 @@ class FlexDataSourceItemTests: XCTestCase { pressed = true } item.configureCell(cell) - item.onTap() + item.onTap?() XCTAssertEqual(cell.backgroundColor, .red) XCTAssertEqual(item.cellIdentifier(), cellID) XCTAssertTrue(pressed) @@ -51,8 +50,8 @@ class FlexDataSourceItemTests: XCTestCase { let cell = UITableViewCell() let item = SwipableItem(identifier: cellID, set(\UITableViewCell.backgroundColor, .blue), { wasTapped = true }, {wasSwiped = true}) item.configureCell(cell) - item.onTap() - item.onSwipe() + item.onTap?() + item.onSwipe?() XCTAssertEqual(cell.backgroundColor, .blue) XCTAssertEqual(item.cellIdentifier(), cellID) XCTAssertTrue(wasSwiped == true) diff --git a/Example/Tests/FlexItemsTests.swift b/Example/Tests/FlexItemsTests.swift index 62eea38..f301e74 100644 --- a/Example/Tests/FlexItemsTests.swift +++ b/Example/Tests/FlexItemsTests.swift @@ -33,10 +33,10 @@ class FlexItemTests: XCTestCase { } let configurer: (Human, UITableViewCell) -> Void = setMainLabel var wasTapped: Bool = false - let item = FlexTappableModelItem(model: Human(id: 123, name: "Calvin Collins"), configurer: configurer, tap: { _ in + let item = FlexModelItem(model: Human(id: 123, name: "Calvin Collins"), configurer: configurer, tap: { _ in wasTapped = true }) - item.onTap() + item.onTap?() XCTAssert(wasTapped) } @@ -47,13 +47,13 @@ class FlexItemTests: XCTestCase { let configurer: (Human, UITableViewCell) -> Void = setMainLabel var wasSwiped: Bool = false var wasTapped: Bool = false - let item = FlexSwipeTapModelItem(model: Human(id: 123, name: "Calvin Collins"), configurer: configurer, tap: { _ in + let item = FlexModelItem(model: Human(id: 123, name: "Calvin Collins"), configurer: configurer, tap: { _ in wasTapped = true }, swipe: { _ in wasSwiped = true }) - item.onSwipe() - item.onTap() + item.onSwipe?() + item.onTap?() XCTAssert(wasTapped && wasSwiped) } } diff --git a/Sources/flex-data-source/FlexCollectionDataSource.swift b/Sources/flex-data-source/FlexCollectionDataSource.swift index 58d64fb..7be4861 100644 --- a/Sources/flex-data-source/FlexCollectionDataSource.swift +++ b/Sources/flex-data-source/FlexCollectionDataSource.swift @@ -86,7 +86,7 @@ public extension FlexCollectionDataSource { func tappableOnSelect(_ collectionView: UICollectionView, _ indexPath: IndexPath) -> Void { collectionView.deselectItem(at: indexPath, animated: true) if let tappable = sections?[indexPath.section].items?[indexPath.row] as? Tappable { - tappable.onTap() + tappable.onTap?() } } diff --git a/Sources/flex-data-source/FlexCollectionItem.swift b/Sources/flex-data-source/FlexCollectionItem.swift index 3df3aa6..f24fbce 100644 --- a/Sources/flex-data-source/FlexCollectionItem.swift +++ b/Sources/flex-data-source/FlexCollectionItem.swift @@ -47,7 +47,7 @@ open class FunctionalFlexCollectionItem: ConcreteFlexCollectionItem where } open class TappableFlexCollectionItem: FunctionalFlexCollectionItem, Tappable where T: UICollectionViewCell { - public var onTap: () -> Void + public var onTap: (() -> Void)? public init(identifier: String, _ configureCell: @escaping (UICollectionViewCell) -> Void, _ onTap: @escaping () -> Void) { self.onTap = onTap diff --git a/Sources/flex-data-source/FlexCollectionItems.swift b/Sources/flex-data-source/FlexCollectionItems.swift index 6af7580..c9cbf10 100644 --- a/Sources/flex-data-source/FlexCollectionItems.swift +++ b/Sources/flex-data-source/FlexCollectionItems.swift @@ -9,9 +9,13 @@ import Foundation import LithoOperators import Prelude -open class FlexModelCollectionItem: ConcreteFlexCollectionItem where C: UICollectionViewCell { +open class FlexModelCollectionItem: ConcreteFlexCollectionItem, Tappable where C: UICollectionViewCell { open var model: T open var configurer: (C) -> Void + public var onTap: (() -> Void)? + public var onButtonPressed: (() -> Void)? + public var gestureRecognizer: UIGestureRecognizer? + public var onGesture: ((T, UIGestureRecognizer?) -> Void)? public init(_ model: T, _ configurer: @escaping (T, C) -> Void) { self.model = model @@ -19,31 +23,21 @@ open class FlexModelCollectionItem: ConcreteFlexCollectionItem where C: super.init(identifier: String(describing: C.self)) } - override open func configureCell(_ cell: UICollectionViewCell) { - if let cell = cell as? C { - configurer(cell) - } - } -} - -open class FlexTappableModelCollectionItem: FlexModelCollectionItem, Tappable where C: UICollectionViewCell { - public var onTap: () -> Void = {} - public init(model: T, configurer: @escaping (T, C) -> Void, tap: @escaping (T) -> Void) { self.onTap = voidCurry(model, tap) - super.init(model, configurer) + self.model = model + self.configurer = model *-> configurer + super.init(identifier: String(describing: C.self)) } -} - -open class FlexButtonTappableModelCollectionItem: FlexTappableModelCollectionItem where C: UICollectionViewCell { - public var onButtonPressed: () -> Void public init(model: T, configurer: @escaping (T, C) -> Void, tap: @escaping (T) -> Void, buttonPressed: @escaping () -> Void) { self.onButtonPressed = buttonPressed - super.init(model: model, configurer: configurer, tap: tap) + self.model = model + self.configurer = model *-> configurer + super.init(identifier: String(describing: C.self)) } public init(model: T, @@ -51,20 +45,19 @@ open class FlexButtonTappableModelCollectionItem: FlexTappableModelCollect tap: @escaping (T) -> Void, buttonPressed: @escaping (T) -> Void) { self.onButtonPressed = voidCurry(model, buttonPressed) - super.init(model: model, configurer: configurer, tap: tap) + self.model = model + self.configurer = model *-> configurer + super.init(identifier: String(describing: C.self)) } -} - -open class FlexGestureModelCollectionItem: FlexModelCollectionItem where C: UICollectionViewCell { - public var gestureRecognizer: UIGestureRecognizer? - public var onGesture: ((T, UIGestureRecognizer?) -> Void)? override open func configureCell(_ cell: UICollectionViewCell) { if let recognizer = gestureRecognizer { cell.contentView.removeGestureRecognizer(recognizer) cell.contentView.addGestureRecognizer(recognizer) } - super.configureCell(cell) + if let cell = cell as? C { + configurer(cell) + } } @objc open func gesturePerformed() { @@ -76,7 +69,7 @@ public func modelItem(_ configurer: @escaping (T, U) return configurer -*> FlexModelCollectionItem.init } -public func tappableModelItem(_ configurer: @escaping (T, U) -> Void, onTap: @escaping (T) -> Void) -> (T) -> FlexTappableModelCollectionItem { - return (configurer, onTap) -**> FlexTappableModelCollectionItem.init +public func tappableModelItem(_ configurer: @escaping (T, U) -> Void, onTap: @escaping (T) -> Void) -> (T) -> FlexModelCollectionItem { + return (configurer, onTap) -**> FlexModelCollectionItem.init } diff --git a/Sources/flex-data-source/FlexDataSourceItem.swift b/Sources/flex-data-source/FlexDataSourceItem.swift index 6e9a84a..3158cbb 100644 --- a/Sources/flex-data-source/FlexDataSourceItem.swift +++ b/Sources/flex-data-source/FlexDataSourceItem.swift @@ -6,6 +6,7 @@ // import UIKit +import LithoOperators public protocol FlexDataSourceItem { func cellIdentifier() -> String @@ -13,7 +14,7 @@ public protocol FlexDataSourceItem { func configureCell(_ cell: UITableViewCell) } -open class ConcreteFlexDataSourceItem: FlexDataSourceItem where T: UITableViewCell { +open class ConcreteFlexDataSourceItem: FlexDataSourceItem where C: UITableViewCell { private let identifier: String public init(identifier: String) { @@ -25,7 +26,7 @@ open class ConcreteFlexDataSourceItem: FlexDataSourceItem where T: UITableVie } open func cellClass() -> UITableViewCell.Type { - return T.self + return C.self } open func configureCell(_ cell: UITableViewCell) { @@ -33,7 +34,7 @@ open class ConcreteFlexDataSourceItem: FlexDataSourceItem where T: UITableVie } } -open class FunctionalFlexDataSourceItem: ConcreteFlexDataSourceItem where T: UITableViewCell { +open class FunctionalFlexDataSourceItem: ConcreteFlexDataSourceItem where C: UITableViewCell { private let configureCell: (UITableViewCell) -> Void public init(identifier: String = "cell", _ configureCell: @escaping (UITableViewCell) -> Void) { @@ -46,22 +47,22 @@ open class FunctionalFlexDataSourceItem: ConcreteFlexDataSourceItem where } } -open class TappableFunctionalFlexItem: FunctionalFlexDataSourceItem, Tappable where T: UITableViewCell { - public var onTap: () -> Void +open class TappableFunctionalFlexItem: FunctionalFlexDataSourceItem, Tappable where C: UITableViewCell { + public var onTap: (() -> Void)? - public init(identifier: String, _ configureCell: @escaping (UITableViewCell) -> Void, _ onTap: @escaping () -> Void) { + public init(identifier: String, _ configureCell: @escaping (UITableViewCell) -> Void, _ onTap: (() -> Void)?) { self.onTap = onTap super.init(identifier: identifier, configureCell) } } -open class SwipableItem: TappableFunctionalFlexItem, Swipable where T: UITableViewCell { - public var onSwipe: () -> Void +open class SwipableItem: TappableFunctionalFlexItem, Swipable where C: UITableViewCell { + public var onSwipe: (() -> Void)? public init(identifier: String, _ configureCell: @escaping (UITableViewCell) -> Void, - _ onTap: @escaping () -> Void, - _ onSwipe: @escaping () -> Void) { + _ onTap: (() -> Void)?, + _ onSwipe: (() -> Void)?) { self.onSwipe = onSwipe super.init(identifier: identifier, configureCell, onTap) } diff --git a/Sources/flex-data-source/FlexDataSourceProtocol.swift b/Sources/flex-data-source/FlexDataSourceProtocol.swift index 4dc66d1..c6adf9a 100644 --- a/Sources/flex-data-source/FlexDataSourceProtocol.swift +++ b/Sources/flex-data-source/FlexDataSourceProtocol.swift @@ -59,8 +59,8 @@ public let deselectRow: (UITableView, IndexPath) -> Void = { $0.deselectRow(at: extension FlexDataSourceProtocol { public func tappableOnSelect(_ tableView: UITableView, _ indexPath: IndexPath) -> Void { deselectRow(tableView, indexPath) - if let tappable = sections?[indexPath.section].items?[indexPath.row] as? Tappable { - tappable.onTap() + if let tappable = sections?[indexPath.section].items?[indexPath.row] as? Tappable, let tap = tappable.onTap { + tap() } } @@ -86,8 +86,8 @@ extension FlexDataSourceProtocol { public func commitEditingStyleForRow(_ tableView: UITableView, editingStyle: UITableViewCell.EditingStyle, at indexPath: IndexPath) { if editingStyle == .delete { - if let item = sections?[indexPath.section].items?[indexPath.row] as? Swipable { - item.onSwipe() + if let item = sections?[indexPath.section].items?[indexPath.row] as? Swipable, let swipe = item.onSwipe { + swipe() sections?[indexPath.section].items?.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .fade) } diff --git a/Sources/flex-data-source/FlexItems.swift b/Sources/flex-data-source/FlexItems.swift index 16efdc1..6fccaaa 100644 --- a/Sources/flex-data-source/FlexItems.swift +++ b/Sources/flex-data-source/FlexItems.swift @@ -9,9 +9,13 @@ import Foundation import LithoOperators import Prelude -open class FlexModelItem: ConcreteFlexDataSourceItem where C: UITableViewCell { +open class FlexModelItem: ConcreteFlexDataSourceItem, Tappable, Swipable where C: UITableViewCell { open var model: T open var configurer: (C) -> Void + public var onTap: (() -> Void)? + public var onSwipe: (() -> Void)? + public var gestureRecognizer: UIGestureRecognizer? + public var onGesture: ((T, UIGestureRecognizer?) -> Void)? public init(_ model: T, _ configurer: @escaping (T, C) -> Void) { self.model = model @@ -19,31 +23,22 @@ open class FlexModelItem: ConcreteFlexDataSourceItem where C: UITableVi super.init(identifier: String(describing: C.self)) } - override open func configureCell(_ cell: UITableViewCell) { - if let cell = cell as? C { - configurer(cell) - } - } -} - -open class FlexTappableModelItem: FlexModelItem, Tappable where C: UITableViewCell { - public var onTap: () -> Void = {} - public init(model: T, configurer: @escaping (T, C) -> Void, tap: @escaping (T) -> Void) { self.onTap = voidCurry(model, tap) - super.init(model, configurer) + self.model = model + self.configurer = model *-> configurer + super.init(identifier: String(describing: C.self)) } -} - -open class FlexSwipeTapModelItem: FlexTappableModelItem, Swipable where C: UITableViewCell { - public var onSwipe: () -> Void public init(model: T, configurer: @escaping (T, C) -> Void, tap: @escaping (T) -> Void, swipe: @escaping () -> Void) { self.onSwipe = swipe - super.init(model: model, configurer: configurer, tap: tap) + self.onTap = voidCurry(model, tap) + self.model = model + self.configurer = model *-> configurer + super.init(identifier: String(describing: C.self)) } public init(model: T, @@ -51,20 +46,20 @@ open class FlexSwipeTapModelItem: FlexTappableModelItem, Swipable wh tap: @escaping (T) -> Void, swipe: @escaping (T) -> Void) { self.onSwipe = voidCurry(model, swipe) - super.init(model: model, configurer: configurer, tap: tap) + self.onTap = voidCurry(model, tap) + self.model = model + self.configurer = model *-> configurer + super.init(identifier: String(describing: C.self)) } -} - -open class FlexGestureModelItem: FlexModelItem where C: UITableViewCell { - public var gestureRecognizer: UIGestureRecognizer? - public var onGesture: ((T, UIGestureRecognizer?) -> Void)? override open func configureCell(_ cell: UITableViewCell) { if let recognizer = gestureRecognizer { cell.contentView.removeGestureRecognizer(recognizer) cell.contentView.addGestureRecognizer(recognizer) } - super.configureCell(cell) + if let cell = cell as? C { + configurer(cell) + } } @objc open func gesturePerformed() { @@ -76,10 +71,10 @@ public func modelItem(_ configurer: @escaping (T, U) -> V return configurer -*> FlexModelItem.init } -public func tappableModelItem(_ configurer: @escaping (T, U) -> Void, onTap: @escaping (T) -> Void) -> (T) -> FlexTappableModelItem { - return (configurer, onTap) -**> FlexTappableModelItem.init +public func tappableModelItem(_ configurer: @escaping (T, U) -> Void, onTap: @escaping (T) -> Void) -> (T) -> FlexModelItem { + return (configurer, onTap) -**> FlexModelItem.init } -public func swipeTappableModelItem(_ configurer: @escaping (T, U) -> Void, onTap: @escaping (T) -> Void, onSwipe: @escaping (T) -> Void) -> (T) -> FlexSwipeTapModelItem { - return (configurer, onTap, onSwipe) -***> FlexSwipeTapModelItem.init +public func swipeTappableModelItem(_ configurer: @escaping (T, U) -> Void, onTap: @escaping (T) -> Void, onSwipe: @escaping (T) -> Void) -> (T) -> FlexModelItem { + return (configurer, onTap, onSwipe) -***> FlexModelItem.init } diff --git a/Sources/flex-data-source/Swipeable.swift b/Sources/flex-data-source/Swipeable.swift index c0154de..defed94 100644 --- a/Sources/flex-data-source/Swipeable.swift +++ b/Sources/flex-data-source/Swipeable.swift @@ -8,9 +8,9 @@ import Foundation public protocol Swipable { - var onSwipe: () -> Void { get } + var onSwipe: (() -> Void)? { get } } public func swipe(on swipable: Swipable) { - swipable.onSwipe() + swipable.onSwipe?() } diff --git a/Sources/flex-data-source/Tappable.swift b/Sources/flex-data-source/Tappable.swift index ed1d8b0..9320595 100644 --- a/Sources/flex-data-source/Tappable.swift +++ b/Sources/flex-data-source/Tappable.swift @@ -8,9 +8,9 @@ import Foundation public protocol Tappable { - var onTap: () -> Void { get } + var onTap: (() -> Void)? { get } } public func tap(on tappable: Tappable) { - tappable.onTap() + tappable.onTap?() }