This repository was archived by the owner on Apr 15, 2020. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 46
Issue 29 table view data source editing #67
Merged
jessesquires
merged 41 commits into
jessesquires:develop
from
psartzetakis:issue_29_tableViewDataSource_editing
Dec 13, 2016
Merged
Changes from all commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
55e9a0c
update to swift 2.3, #53
jessesquires 56af816
update travis for swift 2.3, #53
jessesquires f6029a2
initial migration to swift 3.0, #54
jessesquires 2f442d4
update xcode 8 beta 3, #54
jessesquires 77540a7
Merge branch 'develop' into swift2.3
jessesquires 63ac07f
proj settings
jessesquires 4912ecc
Merge branch 'swift2.3' into swift3.0
dcaunt 4ee1a40
Update mixed cell type example for Swift 3.0
dcaunt 8d680f1
Merge pull request #60 from dcaunt/example-mixed-swift3.0
jessesquires 5be49cf
minor demo updates
jessesquires 04cb5de
update Xcode 8 beta 4, #54
jessesquires 69bb4e2
Merge branch 'develop' into swift2.3
jessesquires fbba40d
Merge branch 'swift2.3' into swift3.0
jessesquires 96c97c5
update for Xcode8 beta6, #54
jessesquires 5e12e27
update for xcode8 GM, #54
jessesquires a51bfe6
name closure params
jessesquires 386e5dc
edit functionality support for UITableViewDataSource
923f174
Merge branch 'swift3.0' into issue_29_tableViewDataSource_editing
22264e8
Merge remote-tracking branch 'jessesquires/develop' into issue_29_tab…
78de1c1
Merge branch 'develop' into issue_29_tableViewDataSource_editing
3b63d1c
Merge remote-tracking branch 'jessesquires/develop' into issue_29_tab…
311488a
Merge remote-tracking branch 'origin/issue_29_tableViewDataSource_edi…
3e6a9ac
updates to match existing coding style
5f5aae8
Merge remote-tracking branch 'jessesquires/develop' into issue_29_tab…
025e7c7
Merge branch 'develop' into issue_29_tableViewDataSource_editing
a971fa1
minor format adjustments, more tests cases added
9f8afe8
Merge remote-tracking branch 'origin/issue_29_tableViewDataSource_edi…
656d4cc
initial migration to swift 3.0, #54
jessesquires 0055fd0
rebase commit 1
3a45779
rebase commit 2
779aeee
updates to match existing coding style
3b2d28a
minor format adjustments, more tests cases added
9f07521
Merge remote-tracking branch 'origin/issue_29_tableViewDataSource_edi…
3ba8580
redundant void removed
d98fc67
Merge branch 'develop' into issue_29_tableViewDataSource_editing
jessesquires 356f15e
Merge branch 'develop' into issue_29_tableViewDataSource_editing
jessesquires 250783f
minor updates
b94065b
Merge remote-tracking branch 'jessesquires/develop' into issue_29_tab…
c62032a
review updates
7305f83
Merge branch 'develop' into issue_29_tableViewDataSource_editing
jessesquires 97f94dc
minor update
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -82,7 +82,7 @@ extension DataSourceProtocol { | |
|
|
||
| - returns: The item specified by indexPath, or `nil`. | ||
| */ | ||
| func item(atIndexPath indexPath: IndexPath) -> Item? { | ||
| public func item(atIndexPath indexPath: IndexPath) -> Item? { | ||
| return item(atRow: indexPath.row, inSection: indexPath.section) | ||
| } | ||
| } | ||
|
|
@@ -159,7 +159,20 @@ public struct DataSource<S: SectionInfoProtocol>: DataSourceProtocol { | |
| guard section < sections.count else { return nil } | ||
| return sections[section].footerTitle | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| Removes an item at the specified index path. | ||
|
|
||
| - parameter indexPath: The index path specifying the location of the item. | ||
| - returns: The item at `indexPath`, or `nil` if it does not exist. | ||
| */ | ||
| @discardableResult | ||
| public mutating func remove(at indexPath: IndexPath) -> S.Item? { | ||
| guard item(atIndexPath: indexPath) != nil else { return nil } | ||
| let section = indexPath.section | ||
| let row = indexPath.row | ||
| return sections[section].items.remove(at: row) | ||
| } | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
|
||
| // MARK: Subscripts | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,7 +37,8 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour | |
| public let supplementaryFactory: SupplementaryFactory | ||
|
|
||
| fileprivate var bridgedDataSource: BridgedDataSource? | ||
|
|
||
|
|
||
| fileprivate var _tableEditingController: TableDataSourceEditingController? | ||
|
|
||
| // MARK: Initialization | ||
|
|
||
|
|
@@ -61,7 +62,6 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour | |
| } | ||
| } | ||
|
|
||
|
|
||
| public extension DataSourceProvider where CellFactory.View: UITableViewCell { | ||
|
|
||
| // MARK: UITableViewDataSource | ||
|
|
@@ -73,7 +73,16 @@ public extension DataSourceProvider where CellFactory.View: UITableViewCell { | |
| } | ||
| return bridgedDataSource! | ||
| } | ||
|
|
||
|
|
||
| public var tableEditingController: TableDataSourceEditingController? { | ||
| set { | ||
| _tableEditingController = newValue | ||
| } | ||
| get { | ||
| return _tableEditingController | ||
| } | ||
| } | ||
|
|
||
| private func tableViewBridgedDataSource() -> BridgedDataSource { | ||
| let dataSource = BridgedDataSource( | ||
| numberOfSections: { [unowned self] () -> Int in | ||
|
|
@@ -95,6 +104,15 @@ public extension DataSourceProvider where CellFactory.View: UITableViewCell { | |
| dataSource.tableTitleForFooterInSection = { [unowned self] (section) -> String? in | ||
| return self.dataSource.footerTitle(inSection: section) | ||
| } | ||
|
|
||
| dataSource.tableCanEditRow = { [unowned self] (tableView, indexPath) -> Bool in | ||
| guard let editDataSource = self.tableEditingController else { return false } | ||
| return editDataSource.canEditRowAt(indexPath: indexPath, in: tableView) | ||
| } | ||
|
|
||
| dataSource.tableCommitEditingStyleForRow = { [unowned self] (tableView, editingStyle,indexPath) in | ||
| self.tableEditingController?.commitEditStyleForRow(in: tableView, editingStyle: editingStyle, at: indexPath) | ||
| } | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
|
||
| return dataSource | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| // | ||
| // Created by Jesse Squires | ||
| // http://www.jessesquires.com | ||
| // | ||
| // | ||
| // Documentation | ||
| // http://jessesquires.com/JSQDataSourcesKit | ||
| // | ||
| // | ||
| // GitHub | ||
| // https://github.com/jessesquires/JSQDataSourcesKit | ||
| // | ||
| // | ||
| // License | ||
| // Copyright © 2015 Jesse Squires | ||
| // Released under an MIT license: http://opensource.org/licenses/MIT | ||
| // | ||
|
|
||
| import Foundation | ||
| import UIKit | ||
|
|
||
| public struct TableDataSourceEditingController { | ||
|
|
||
| public typealias CanEditRowConfigurator = (IndexPath, UITableView) -> Bool | ||
| public typealias CommitEditingStyleConfigurator = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void | ||
|
|
||
| public let canEditConfigurator: CanEditRowConfigurator | ||
| public let commitEditingStyle: CommitEditingStyleConfigurator | ||
|
|
||
| public init(canEditConfigurator: @escaping CanEditRowConfigurator, | ||
| commitEditingStyle: @escaping CommitEditingStyleConfigurator) { | ||
|
|
||
| self.canEditConfigurator = canEditConfigurator | ||
| self.commitEditingStyle = commitEditingStyle | ||
| } | ||
|
|
||
| public func canEditRowAt(indexPath: IndexPath, in tableView: UITableView) -> Bool { | ||
| return canEditConfigurator(indexPath, tableView) | ||
| } | ||
|
|
||
| public func commitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) { | ||
| return commitEditingStyle(tableView, editingStyle, indexPath) | ||
| } | ||
|
|
||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -369,4 +369,93 @@ final class DataSourceProviderTests: TestCase { | |
| } | ||
| } | ||
|
|
||
| func test_thatDataSourceProvider_forTableView_returnsExpectedData_afterRemovingRowFromTableView() { | ||
| // GIVEN: a single section with data items | ||
| let expectedModel = FakeViewModel() | ||
| let expectedIndexPath = IndexPath(row: 2, section: 0) | ||
|
|
||
| let section0 = Section(items: FakeViewModel(), FakeViewModel(), expectedModel, FakeViewModel(), FakeViewModel(), | ||
| headerTitle: "Header", | ||
| footerTitle: "Footer") | ||
| let dataSource = DataSource([section0]) | ||
|
|
||
| let oldItemForExpectedIndexPath = dataSource.item(atRow: expectedIndexPath.row, inSection: expectedIndexPath.section) | ||
| let oldCount = dataSource.numberOfItems(inSection: expectedIndexPath.section) | ||
|
|
||
| let factoryExpectation = expectation(description: #function) | ||
| tableView.dequeueCellExpectation = expectation(description: dequeueCellExpectationName + #function) | ||
|
|
||
| typealias TableCellFactory = ViewFactory<FakeViewModel, FakeTableCell> | ||
| var dataSourceProvider: DataSourceProvider<DataSource<Section<FakeViewModel>>, TableCellFactory, TableCellFactory>! | ||
|
|
||
| // GIVEN: a cell factory | ||
| let factory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, tableView, indexPath) -> FakeTableCell in | ||
|
|
||
| XCTAssertEqual(cell.reuseIdentifier!, self.cellReuseId, "Dequeued cell should have expected identifier") | ||
| XCTAssertEqual(tableView, self.tableView, "TableView should equal the tableView for the data source") | ||
|
|
||
| factoryExpectation.fulfill() | ||
| return cell | ||
| } | ||
|
|
||
| //GIVEN: a data source editing controller | ||
| let tableDataSourceEditingController = TableDataSourceEditingController( | ||
| canEditConfigurator: { (indexPath, tableView) -> Bool in | ||
| return indexPath == expectedIndexPath | ||
| }, | ||
| commitEditingStyle:{ (tableView, editingStyle, indexPath) in | ||
| if editingStyle == .delete { | ||
| if let _ = dataSourceProvider.dataSource.remove(at: indexPath) { | ||
| tableView.deleteRows(at: [indexPath], with: .automatic) | ||
| } | ||
| } | ||
| }) | ||
|
|
||
| // GIVEN: a data source provider | ||
| dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory) | ||
| dataSourceProvider.tableEditingController = tableDataSourceEditingController | ||
|
|
||
| let tableViewDataSource = dataSourceProvider.tableViewDataSource | ||
| tableView.dataSource = tableViewDataSource | ||
|
|
||
| // WHEN: we call the table view data source methods | ||
| let canEditRow = tableViewDataSource.tableView?(tableView, canEditRowAt: expectedIndexPath) | ||
| tableViewDataSource.tableView?(tableView, commit: .delete, forRowAt: expectedIndexPath) | ||
| let newItemForExpectedIndexPath = dataSourceProvider.dataSource.item(atRow: expectedIndexPath.row, inSection: expectedIndexPath.section) | ||
| let newCount = dataSourceProvider.dataSource.numberOfItems(inSection: expectedIndexPath.section) | ||
|
|
||
| let numSections = tableViewDataSource.numberOfSections?(in: tableView) | ||
| let cell = tableViewDataSource.tableView(tableView, cellForRowAt: expectedIndexPath) | ||
| let header = tableViewDataSource.tableView?(tableView, titleForHeaderInSection: 0) | ||
| let footer = tableViewDataSource.tableView?(tableView, titleForFooterInSection: 0) | ||
|
|
||
| // THEN: we receive the expected return values | ||
| XCTAssertNotNil(canEditRow, "canEditRow should not be nil") | ||
| XCTAssert(canEditRow!, "expectedIndexpath should be able to be removed from tableview") | ||
|
|
||
| XCTAssertNotEqual(oldCount, newCount, "Number of items for \(expectedIndexPath.section) should not be equal after removing the expected row") | ||
| XCTAssertEqual(newCount, oldCount - 1, "Number of items for \(expectedIndexPath.section) should be less by one") | ||
| XCTAssertNotEqual(newItemForExpectedIndexPath, oldItemForExpectedIndexPath, "old item at row \(expectedIndexPath.row), section \(expectedIndexPath.section) shouldn't exist any more") | ||
|
|
||
| XCTAssertNotNil(numSections, "Number of sections should not be nil") | ||
| XCTAssertEqual(numSections!, dataSourceProvider.dataSource.sections.count, "Data source should return expected number of sections") | ||
|
|
||
| XCTAssertNotNil(cell.reuseIdentifier, "Cell reuse identifier should not be nil") | ||
| XCTAssertEqual(cell.reuseIdentifier!, cellReuseId, "Data source should return cells with the expected identifier") | ||
|
|
||
| XCTAssertNotNil(header, "Header should not be nil") | ||
| XCTAssertNotNil(section0.headerTitle, "Section 0 header title should not be nil") | ||
| XCTAssertEqual(header!, section0.headerTitle!, "Data source should return expected header title") | ||
|
|
||
| XCTAssertNotNil(footer, "Footer should not be nil") | ||
| XCTAssertNotNil(section0.footerTitle, "Section 0 footer title should not be nil") | ||
| XCTAssertEqual(footer!, section0.footerTitle!, "Data source should return expected footer title") | ||
|
|
||
| // THEN: the tableView calls `dequeueReusableCellWithIdentifier` | ||
| // THEN: the cell factory calls its `ConfigurationHandler` | ||
| waitForExpectations(timeout: defaultTimeout, handler: { (error) -> Void in | ||
| XCTAssertNil(error, "Expectations should not error") | ||
| }) | ||
| } | ||
|
|
||
| } | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 🙌 |
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -201,7 +201,7 @@ final class DataSourceTests: XCTestCase { | |
| let ip = IndexPath(item: 2, section: 2) | ||
| let item = dataSource[ip] | ||
|
|
||
| // THEN: we receive the exepected data | ||
| // THEN: we receive the expected data | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😊 |
||
| XCTAssertEqual(item, model) | ||
| } | ||
|
|
||
|
|
@@ -219,4 +219,21 @@ final class DataSourceTests: XCTestCase { | |
| // THEN: the item is replaced | ||
| XCTAssertEqual(dataSource[ip], item) | ||
| } | ||
|
|
||
| func test_thatDataSource_removesExpectedData_atIndexPath() { | ||
| // GIVEN: a data source | ||
| let sectionA = Section(items: FakeViewModel(), FakeViewModel(), headerTitle: "Header") | ||
| let sectionB = Section(items: FakeViewModel(), FakeViewModel(), footerTitle: "Footer") | ||
| var dataSource = DataSource(sections: sectionA, sectionB) | ||
|
|
||
| // WHEN: we set an item at a specific index path | ||
| let ip = IndexPath(item: 1, section: 0) | ||
| let itemToRemove = dataSource.item(atIndexPath: ip) | ||
|
|
||
| // THEN: Check if an item exists at the specified indexPath .Then check if the removedItem is the expected item | ||
| XCTAssertNotNil(itemToRemove) | ||
|
|
||
| let removedItem = dataSource.remove(at: ip) | ||
| XCTAssertEqual(removedItem, itemToRemove) | ||
| } | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should test out-of-bounds indexPaths, too 😄 |
||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉