From 87d959f05f3f44b6e5491b94e3525a8647c1993d Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Sun, 15 May 2016 19:01:47 +0300 Subject: [PATCH 01/34] fix travis-ci badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1116ae..c543553 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ #Tablet.swift

-Build Status +Build Status Swift 2.2 compatible Platform iOS CocoaPods compatible From 0250b083021cb629769cdf6ad5200e84d9754cad Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Mon, 23 May 2016 22:30:17 +0300 Subject: [PATCH 02/34] add row height --- .../UserInterfaceState.xcuserstate | Bin 12275 -> 13496 bytes Tablet/TablePrototypeRowBuilder.swift | 27 ++++++++++++++++++ Tablet/TableRowBuilder.swift | 6 ++++ Tablet/Tablet.swift | 5 ++++ Tablet/Tablet.xcodeproj/project.pbxproj | 4 +++ 5 files changed, 42 insertions(+) create mode 100644 Tablet/TablePrototypeRowBuilder.swift diff --git a/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate b/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate index c9f97f271711b0245f54b2ae1789a32474cd1224..6ab9c7e2f769abd248e639a893a741926d5c42b0 100644 GIT binary patch delta 8188 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 delta 7200 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 : TableBaseRowBuilder { + + +} \ No newline at end of file diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index 7c57528..72325a7 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -44,6 +44,8 @@ public protocol RowBuilder { var reusableIdentifier: String { get } var numberOfRows: Int { get } + + var rowHeight: Float { get } var estimatedRowHeight: Float { get } func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? @@ -68,6 +70,10 @@ public class TableBaseRowBuilder String static func estimatedHeight() -> Float + static func defaultHeight() -> Float? func configure(_: T) } @@ -114,4 +115,8 @@ public extension ConfigurableCell where Self: UITableViewCell { static func reusableIdentifier() -> String { return String(self) } + + static func defaultHeight() -> Float? { + return nil + } } \ No newline at end of file diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index 49ea0b1..b0a1e05 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 501C70391CF387090099458A /* TablePrototypeRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501C70381CF387090099458A /* TablePrototypeRowBuilder.swift */; }; DAC2D6741C9D743D009E9C19 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC2D6691C9D743D009E9C19 /* Tablet.framework */; }; DAC2D6871C9D7517009E9C19 /* Tablet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2D6851C9D7517009E9C19 /* Tablet.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */; }; @@ -27,6 +28,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 501C70381CF387090099458A /* TablePrototypeRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TablePrototypeRowBuilder.swift; sourceTree = ""; }; DAC2D6691C9D743D009E9C19 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Tablet.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6731C9D743D009E9C19 /* TabletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TabletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6841C9D7517009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -93,6 +95,7 @@ DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */, DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */, DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */, + 501C70381CF387090099458A /* TablePrototypeRowBuilder.swift */, ); name = Classes; sourceTree = ""; @@ -218,6 +221,7 @@ DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */, DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */, DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */, + 501C70391CF387090099458A /* TablePrototypeRowBuilder.swift in Sources */, DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From ba8aa05d8b10dbd389bc512a1c03a30365022c2d Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Tue, 24 May 2016 01:13:18 +0300 Subject: [PATCH 03/34] add prototype based cell height row builder --- Tablet/ConfigurableCell.swift | 46 ++++++++++++++ ...otypeRowBuilder.swift => RowBuilder.swift} | 13 +++- Tablet/TableDirector.swift | 4 +- Tablet/TableRowBuilder.swift | 63 +++++++++---------- Tablet/Tablet.swift | 41 +++++------- Tablet/Tablet.xcodeproj/project.pbxproj | 14 +++-- 6 files changed, 115 insertions(+), 66 deletions(-) create mode 100644 Tablet/ConfigurableCell.swift rename Tablet/{TablePrototypeRowBuilder.swift => RowBuilder.swift} (74%) diff --git a/Tablet/ConfigurableCell.swift b/Tablet/ConfigurableCell.swift new file mode 100644 index 0000000..ba3ca10 --- /dev/null +++ b/Tablet/ConfigurableCell.swift @@ -0,0 +1,46 @@ +// +// Copyright (c) 2015 Max Sokolov https://twitter.com/max_sokolov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import UIKit + +/** + If you want to delegate your cell configuration logic to cell itself (with your view model or even model) than + just provide an implementation of this protocol for your cell. Enjoy safe-typisation. + */ +public protocol ConfigurableCell { + + associatedtype T + + static func reusableIdentifier() -> String + static func estimatedHeight() -> Float + static func defaultHeight() -> Float? + func configure(_: T) +} + +public extension ConfigurableCell where Self: UITableViewCell { + + static func reusableIdentifier() -> String { + return String(self) + } + + static func defaultHeight() -> Float? { + return nil + } +} \ No newline at end of file diff --git a/Tablet/TablePrototypeRowBuilder.swift b/Tablet/RowBuilder.swift similarity index 74% rename from Tablet/TablePrototypeRowBuilder.swift rename to Tablet/RowBuilder.swift index 1f3d9f4..e57bebc 100644 --- a/Tablet/TablePrototypeRowBuilder.swift +++ b/Tablet/RowBuilder.swift @@ -19,9 +19,16 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import UIKit -import Foundation - -public class TablePrototypeRowBuilder : TableBaseRowBuilder { +public protocol RowBuilder { + var reusableIdentifier: String { get } + var numberOfRows: Int { get } + + var estimatedRowHeight: Float { get } + + func rowHeight(index: Int) -> CGFloat + + func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? + func registerCell(inTableView tableView: UITableView) } \ No newline at end of file diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index b79f730..1e21985 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -146,7 +146,9 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate } public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - return invoke(action: .height, cell: nil, indexPath: indexPath) as? CGFloat ?? UITableViewAutomaticDimension + + let builder = builderAtIndexPath(indexPath) + return builder.0.rowHeight(builder.1) } public func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index 72325a7..1af47fa 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -23,35 +23,6 @@ import Foundation public typealias ReturnValue = AnyObject? -enum ActionHandler { - - case Handler((data: ActionData) -> Void) - case ValueHandler((data: ActionData) -> AnyObject?) - - func invoke(data: ActionData) -> ReturnValue { - - switch (self) { - case .Handler(let handler): - handler(data: data) - return nil - case .ValueHandler(let handler): - return handler(data: data) - } - } -} - -public protocol RowBuilder { - - var reusableIdentifier: String { get } - var numberOfRows: Int { get } - - var rowHeight: Float { get } - var estimatedRowHeight: Float { get } - - func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? - func registerCell(inTableView tableView: UITableView) -} - /** Responsible for building cells of given type and passing items to them. */ @@ -70,10 +41,6 @@ public class TableBaseRowBuilder CGFloat { + return 0 + } + // MARK: - Chaining actions - public func action(key: String, handler: (data: ActionData) -> Void) -> Self { @@ -170,6 +141,32 @@ public class TableRowBuilder : TableBaseRowBuilder { + + private var cachedHeights = [Int: CGFloat]() + private var prototypeCell: CellType? + + public override func rowHeight(index: Int) -> CGFloat { + + guard let cell = prototypeCell else { return 0 } + + let item = items[index] + + if let height = cachedHeights[item.hashValue] { + return height + } + + cell.configure(item) + cell.setNeedsLayout() + cell.layoutIfNeeded() + + let height = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1 + cachedHeights[item.hashValue] = height + + return height + } +} + public func +=(left: TableBaseRowBuilder, right: DataType) { left.append(items: [right]) } diff --git a/Tablet/Tablet.swift b/Tablet/Tablet.swift index 3a1f663..b960913 100644 --- a/Tablet/Tablet.swift +++ b/Tablet/Tablet.swift @@ -69,6 +69,23 @@ public class ActionData { } } +enum ActionHandler { + + case Handler((data: ActionData) -> Void) + case ValueHandler((data: ActionData) -> AnyObject?) + + func invoke(data: ActionData) -> ReturnValue { + + switch (self) { + case .Handler(let handler): + handler(data: data) + return nil + case .ValueHandler(let handler): + return handler(data: data) + } + } +} + /** A custom action that you can trigger from your cell. You can eacily catch actions using a chaining manner with your row builder. @@ -96,27 +113,3 @@ public class Action { } } -/** - If you want to delegate your cell configuration logic to cell itself (with your view model or even model) than - just provide an implementation of this protocol for your cell. Enjoy safe-typisation. -*/ -public protocol ConfigurableCell { - - associatedtype T - - static func reusableIdentifier() -> String - static func estimatedHeight() -> Float - static func defaultHeight() -> Float? - func configure(_: T) -} - -public extension ConfigurableCell where Self: UITableViewCell { - - static func reusableIdentifier() -> String { - return String(self) - } - - static func defaultHeight() -> Float? { - return nil - } -} \ No newline at end of file diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index b0a1e05..ed7ad7e 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -7,7 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - 501C70391CF387090099458A /* TablePrototypeRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501C70381CF387090099458A /* TablePrototypeRowBuilder.swift */; }; + DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */; }; + DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */; }; DAC2D6741C9D743D009E9C19 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC2D6691C9D743D009E9C19 /* Tablet.framework */; }; DAC2D6871C9D7517009E9C19 /* Tablet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2D6851C9D7517009E9C19 /* Tablet.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */; }; @@ -28,7 +29,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 501C70381CF387090099458A /* TablePrototypeRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TablePrototypeRowBuilder.swift; sourceTree = ""; }; + DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; + DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowBuilder.swift; sourceTree = ""; }; DAC2D6691C9D743D009E9C19 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Tablet.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6731C9D743D009E9C19 /* TabletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TabletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6841C9D7517009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -91,11 +93,12 @@ DAC2D68B1C9D7990009E9C19 /* Classes */ = { isa = PBXGroup; children = ( - DAC2D68F1C9D799E009E9C19 /* Tablet.swift */, + DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, + DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */, DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */, DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */, DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */, - 501C70381CF387090099458A /* TablePrototypeRowBuilder.swift */, + DAC2D68F1C9D799E009E9C19 /* Tablet.swift */, ); name = Classes; sourceTree = ""; @@ -220,8 +223,9 @@ files = ( DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */, DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */, + DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */, + DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */, DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */, - 501C70391CF387090099458A /* TablePrototypeRowBuilder.swift in Sources */, DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From 779bf8dd435a67038bd87e5532fdd6da6bb3d959 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Tue, 24 May 2016 01:30:26 +0300 Subject: [PATCH 04/34] estimatedHeight to CGFloat --- Tablet/RowBuilder.swift | 2 +- Tablet/TableDirector.swift | 2 +- Tablet/TableRowBuilder.swift | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Tablet/RowBuilder.swift b/Tablet/RowBuilder.swift index e57bebc..4a07be7 100644 --- a/Tablet/RowBuilder.swift +++ b/Tablet/RowBuilder.swift @@ -25,7 +25,7 @@ public protocol RowBuilder { var reusableIdentifier: String { get } var numberOfRows: Int { get } - var estimatedRowHeight: Float { get } + var estimatedRowHeight: CGFloat { get } func rowHeight(index: Int) -> CGFloat diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 1e21985..1882db2 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -142,7 +142,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate // MARK: UITableViewDelegate - actions public func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - return CGFloat(builderAtIndexPath(indexPath).0.estimatedRowHeight) + return builderAtIndexPath(indexPath).0.estimatedRowHeight } public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index 1af47fa..bc23db0 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -37,7 +37,7 @@ public class TableBaseRowBuilder : TableBaseRowBuilder { - public override var estimatedRowHeight: Float { - return CellType.estimatedHeight() + public override var estimatedRowHeight: CGFloat { + return CGFloat(CellType.estimatedHeight()) } public init(item: DataType) { From b87d2b8aec5e58cbb584efc56aed38653618ea8a Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Tue, 24 May 2016 20:22:35 +0300 Subject: [PATCH 05/34] remove Foundation import --- Tablet/TableDirector.swift | 1 - Tablet/TableRowBuilder.swift | 3 ++- Tablet/TableSectionBuilder.swift | 1 - Tablet/Tablet.swift | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 1882db2..15109bf 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -19,7 +19,6 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import UIKit -import Foundation /** Responsible for table view's datasource and delegate. diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index bc23db0..3b0e121 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -19,7 +19,6 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import UIKit -import Foundation public typealias ReturnValue = AnyObject? @@ -156,6 +155,8 @@ public class TablePrototypeRowBuilder Date: Tue, 24 May 2016 22:51:04 +0300 Subject: [PATCH 06/34] first try prototype cells --- Tablet/RowBuilder.swift | 10 +++-- Tablet/TableDirector.swift | 12 ++--- Tablet/TableRowBuilder.swift | 44 ++++++++++++++++--- Tablet/TableSectionBuilder.swift | 4 +- .../Controllers/MainController.swift | 2 +- 5 files changed, 53 insertions(+), 19 deletions(-) diff --git a/Tablet/RowBuilder.swift b/Tablet/RowBuilder.swift index 4a07be7..ced4fb6 100644 --- a/Tablet/RowBuilder.swift +++ b/Tablet/RowBuilder.swift @@ -22,13 +22,15 @@ import UIKit public protocol RowBuilder { - var reusableIdentifier: String { get } - var numberOfRows: Int { get } + var tableDirector: TableDirector? { get } + var reusableIdentifier: String { get } + + var numberOfRows: Int { get } var estimatedRowHeight: CGFloat { get } - func rowHeight(index: Int) -> CGFloat + func willUpdateDirector(director: TableDirector?) + func rowHeight(index: Int) -> CGFloat func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? - func registerCell(inTableView tableView: UITableView) } \ No newline at end of file diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 15109bf..0ce4c13 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -25,16 +25,16 @@ import UIKit */ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate { - public unowned let tableView: UITableView + public private(set) weak var tableView: UITableView? public weak var scrollDelegate: UIScrollViewDelegate? private var sections = [TableSectionBuilder]() public init(tableView: UITableView) { + super.init() self.tableView = tableView - super.init() - self.tableView.delegate = self - self.tableView.dataSource = self + self.tableView?.delegate = self + self.tableView?.dataSource = self NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(didReceiveAction), name: TabletNotifications.CellAction, object: nil) } @@ -77,7 +77,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate func didReceiveAction(notification: NSNotification) { - if let action = notification.object as? Action, indexPath = tableView.indexPathForCell(action.cell) { + if let action = notification.object as? Action, indexPath = tableView?.indexPathForCell(action.cell) { let builder = builderAtIndexPath(indexPath) builder.0.invoke(action: .custom(action.key), cell: action.cell, indexPath: indexPath, itemIndex: builder.1, userInfo: notification.userInfo) @@ -145,7 +145,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate } public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - + let builder = builderAtIndexPath(indexPath) return builder.0.rowHeight(builder.1) } diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index 3b0e121..e1cb19e 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -27,6 +27,8 @@ public typealias ReturnValue = AnyObject? */ public class TableBaseRowBuilder : RowBuilder { + public private(set) weak var tableDirector: TableDirector? + private var actions = [String: ActionHandler]() private var items = [DataType]() @@ -56,7 +58,7 @@ public class TableBaseRowBuilder CGFloat { - return 0 + return UITableViewAutomaticDimension } // MARK: - Chaining actions - @@ -86,8 +88,8 @@ public class TableBaseRowBuilder CGFloat { @@ -154,8 +170,8 @@ public class TablePrototypeRowBuilder AnyObject? { + + if case .configure = action { + (cell as? CellType)?.configure(items[itemIndex]) + } + return super.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: itemIndex, userInfo: userInfo) + } + + public override func willUpdateDirector(director: TableDirector?) { + + tableDirector = director + if let tableView = director?.tableView, cell = tableView.dequeueReusableCellWithIdentifier(reusableIdentifier) as? CellType { + prototypeCell = cell + } + } } public func +=(left: TableBaseRowBuilder, right: DataType) { diff --git a/Tablet/TableSectionBuilder.swift b/Tablet/TableSectionBuilder.swift index ac20791..d9e300a 100644 --- a/Tablet/TableSectionBuilder.swift +++ b/Tablet/TableSectionBuilder.swift @@ -29,7 +29,7 @@ public class TableSectionBuilder { weak var tableDirector: TableDirector? { didSet { guard let director = tableDirector else { return } - builders.forEach { $0.registerCell(inTableView: director.tableView) } + builders.forEach { $0.willUpdateDirector(director) } } } @@ -79,7 +79,7 @@ public class TableSectionBuilder { public func append(rows rows: [RowBuilder]) { - if let tableView = tableDirector?.tableView { rows.forEach { $0.registerCell(inTableView: tableView) } } + if let director = tableDirector { rows.forEach { $0.willUpdateDirector(director) } } builders.appendContentsOf(rows) } diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 1375ff0..8f3faae 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -21,7 +21,7 @@ class MainController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - let rows = TableRowBuilder(items: ["1", "2", "3"]) + let rows = TablePrototypeRowBuilder(items: ["1"]) .action(.click) { [unowned self] e in self.performSegueWithIdentifier("headerfooter", sender: nil) } From 92ee2b731c2c7e4c32885ff6bf6e68904a61540e Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Wed, 25 May 2016 01:31:22 +0300 Subject: [PATCH 07/34] fix autolayout issues --- Tablet/RowBuilder.swift | 3 +- Tablet/TableDirector.swift | 3 +- Tablet/TableRowBuilder.swift | 38 ++++++++++----- .../Controllers/MainController.swift | 2 +- .../Views/StoryboardImageTableViewCell.swift | 37 ++++++++++++++ TabletDemo/Resources/Info.plist | 2 + .../Storyboards/LaunchScreen.storyboard | 4 +- .../Resources/Storyboards/Main.storyboard | 48 ++++++++++++++++++- .../TabletDemo.xcodeproj/project.pbxproj | 16 ++++++- 9 files changed, 131 insertions(+), 22 deletions(-) create mode 100644 TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift diff --git a/Tablet/RowBuilder.swift b/Tablet/RowBuilder.swift index ced4fb6..0f2415d 100644 --- a/Tablet/RowBuilder.swift +++ b/Tablet/RowBuilder.swift @@ -27,10 +27,11 @@ public protocol RowBuilder { var reusableIdentifier: String { get } var numberOfRows: Int { get } - var estimatedRowHeight: CGFloat { get } func willUpdateDirector(director: TableDirector?) func rowHeight(index: Int) -> CGFloat + func estimatedRowHeight() -> CGFloat + func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? } \ No newline at end of file diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 0ce4c13..b0574b5 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -141,11 +141,10 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate // MARK: UITableViewDelegate - actions public func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - return builderAtIndexPath(indexPath).0.estimatedRowHeight + return builderAtIndexPath(indexPath).0.estimatedRowHeight() } public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - let builder = builderAtIndexPath(indexPath) return builder.0.rowHeight(builder.1) } diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index e1cb19e..1cf6335 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -37,11 +37,7 @@ public class TableBaseRowBuilder CGFloat { + return 44 + } + // MARK: - Chaining actions - public func action(key: String, handler: (data: ActionData) -> Void) -> Self { @@ -127,10 +127,6 @@ public class TableBaseRowBuilder : TableBaseRowBuilder { - public override var estimatedRowHeight: CGFloat { - return CGFloat(CellType.estimatedHeight()) - } - public init(item: DataType) { super.init(item: item, id: CellType.reusableIdentifier()) } @@ -146,13 +142,17 @@ public class TableRowBuilder CGFloat { + return CGFloat(CellType.estimatedHeight()) + } } public class TablePrototypeRowBuilder : TableBaseRowBuilder { private var cachedHeights = [Int: CGFloat]() private var prototypeCell: CellType? - + public init(item: DataType) { super.init(item: item, id: CellType.reusableIdentifier()) } @@ -160,6 +160,10 @@ public class TablePrototypeRowBuilder CGFloat { + return UITableViewAutomaticDimension + } public override func rowHeight(index: Int) -> CGFloat { @@ -168,17 +172,25 @@ public class TablePrototypeRowBuilder(items: ["1"]) + let rows = TablePrototypeRowBuilder(items: ["1", "1", "1", "1"]) .action(.click) { [unowned self] e in self.performSegueWithIdentifier("headerfooter", sender: nil) } diff --git a/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift b/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift new file mode 100644 index 0000000..5a848f6 --- /dev/null +++ b/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift @@ -0,0 +1,37 @@ +// +// StoryboardImageTableViewCell.swift +// TabletDemo +// +// Created by Max Sokolov on 24/05/16. +// Copyright © 2016 Tablet. All rights reserved. +// + +import UIKit +import Tablet + +class StoryboardImageTableViewCell: UITableViewCell, ConfigurableCell { + + typealias T = String + + @IBOutlet var titleLabel: UILabel! + @IBOutlet var subtitleLabel: UILabel! + @IBOutlet var customImageView: UIImageView! + + func configure(string: T) { + + titleLabel.text = "Test" + subtitleLabel.text = "Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.1" + } + + static func estimatedHeight() -> Float { + return 140 + } + + override func layoutSubviews() { + super.layoutSubviews() + + //contentView.layoutIfNeeded() + + subtitleLabel.preferredMaxLayoutWidth = subtitleLabel.bounds.size.width + } +} \ No newline at end of file diff --git a/TabletDemo/Resources/Info.plist b/TabletDemo/Resources/Info.plist index 6c48029..6905cc6 100644 --- a/TabletDemo/Resources/Info.plist +++ b/TabletDemo/Resources/Info.plist @@ -33,6 +33,8 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight diff --git a/TabletDemo/Resources/Storyboards/LaunchScreen.storyboard b/TabletDemo/Resources/Storyboards/LaunchScreen.storyboard index c9b7564..0a546bb 100644 --- a/TabletDemo/Resources/Storyboards/LaunchScreen.storyboard +++ b/TabletDemo/Resources/Storyboards/LaunchScreen.storyboard @@ -1,8 +1,8 @@ - + - + diff --git a/TabletDemo/Resources/Storyboards/Main.storyboard b/TabletDemo/Resources/Storyboards/Main.storyboard index 1a1d1c2..4edf1ae 100644 --- a/TabletDemo/Resources/Storyboards/Main.storyboard +++ b/TabletDemo/Resources/Storyboards/Main.storyboard @@ -39,8 +39,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj b/TabletDemo/TabletDemo.xcodeproj/project.pbxproj index 9779299..f3e4618 100644 --- a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj +++ b/TabletDemo/TabletDemo.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + DA08A0531CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */; }; DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */; }; DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */; }; DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */; }; @@ -17,6 +18,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardImageTableViewCell.swift; sourceTree = ""; }; DAB7EB271BEF787300D2AD5E /* TabletDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabletDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; @@ -39,11 +41,19 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + DA539C871CF50B1800368ACB /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; DAB7EB1E1BEF787300D2AD5E = { isa = PBXGroup; children = ( DAC2D5C61C9D2FE5009E9C19 /* Classes */, DAC2D5CB1C9D3058009E9C19 /* Resources */, + DA539C871CF50B1800368ACB /* Frameworks */, DAB7EB281BEF787300D2AD5E /* Products */, ); sourceTree = ""; @@ -122,6 +132,7 @@ isa = PBXGroup; children = ( DACB71771CC2D6ED00432BD3 /* StoryboardTableViewCell.swift */, + DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */, ); path = Views; sourceTree = ""; @@ -202,6 +213,7 @@ DACB71761CC2D63D00432BD3 /* MainController.swift in Sources */, DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */, DACB717A1CC2D89D00432BD3 /* HeaderFooterController.swift in Sources */, + DA08A0531CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -298,7 +310,7 @@ INFOPLIST_FILE = Resources/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.tablet.tablet; + PRODUCT_BUNDLE_IDENTIFIER = com.tablet.demo; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; }; @@ -313,7 +325,7 @@ INFOPLIST_FILE = Resources/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.tablet.tablet; + PRODUCT_BUNDLE_IDENTIFIER = com.tablet.demo; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; }; From bc503bcb4f7035028cf73b2cbcffe003f8a45028 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Wed, 25 May 2016 01:37:41 +0300 Subject: [PATCH 08/34] fix build --- .../TabletDemo.xcodeproj/project.pbxproj | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj b/TabletDemo/TabletDemo.xcodeproj/project.pbxproj index f3e4618..0a8c7bf 100644 --- a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj +++ b/TabletDemo/TabletDemo.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ DA08A0531CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */; }; + DA539C901CF50E9900368ACB /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA539C8F1CF50E9900368ACB /* Tablet.framework */; }; + DA539C911CF50E9900368ACB /* Tablet.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA539C8F1CF50E9900368ACB /* Tablet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */; }; DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */; }; DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */; }; @@ -17,8 +19,23 @@ DACB717A1CC2D89D00432BD3 /* HeaderFooterController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACB71791CC2D89D00432BD3 /* HeaderFooterController.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXCopyFilesBuildPhase section */ + DA539C921CF50E9900368ACB /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + DA539C911CF50E9900368ACB /* Tablet.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardImageTableViewCell.swift; sourceTree = ""; }; + DA539C8F1CF50E9900368ACB /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = Tablet.framework; path = "/Users/maxsokolov/Library/Developer/Xcode/DerivedData/Tablet-hgommdyxtgxijceamltarpblrbwc/Build/Products/Debug-iphoneos/Tablet.framework"; sourceTree = ""; }; DAB7EB271BEF787300D2AD5E /* TabletDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabletDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; @@ -35,6 +52,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DA539C901CF50E9900368ACB /* Tablet.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -51,6 +69,7 @@ DAB7EB1E1BEF787300D2AD5E = { isa = PBXGroup; children = ( + DA539C8F1CF50E9900368ACB /* Tablet.framework */, DAC2D5C61C9D2FE5009E9C19 /* Classes */, DAC2D5CB1C9D3058009E9C19 /* Resources */, DA539C871CF50B1800368ACB /* Frameworks */, @@ -147,6 +166,7 @@ DAB7EB231BEF787300D2AD5E /* Sources */, DAB7EB241BEF787300D2AD5E /* Frameworks */, DAB7EB251BEF787300D2AD5E /* Resources */, + DA539C921CF50E9900368ACB /* Embed Frameworks */, ); buildRules = ( ); From 94925e301b4162e9c548e54a148ac01f494e1172 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Wed, 25 May 2016 21:47:14 +0300 Subject: [PATCH 09/34] try preheat --- .../UserInterfaceState.xcuserstate | Bin 13496 -> 18832 bytes Tablet/TableRowBuilder.swift | 52 +++++++++++++----- .../Views/StoryboardImageTableViewCell.swift | 2 +- .../TabletDemo.xcodeproj/project.pbxproj | 12 ++-- 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate b/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate index 6ab9c7e2f769abd248e639a893a741926d5c42b0..bb497d2bd25cc669c22a1cf2a053676b4919f68c 100644 GIT binary patch literal 18832 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%0AD`f$6bz0Kineo=de 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 delta 7993 zcmZ`-2Ygf2_rK#MO`82OUXr%SOOv)qTc9lkN?9#XHZ62Op+G1!VEvT>9Sm#9eGHK) z5Cjy_4ps$`DJUva#R13?MN~u?0-|gX(Em+B3-#llen@i9z2|$s_ndRjIqxm;SvKG}r_7hW+3GI1mnp zBcL0OgoSV%EQRCY1UL~^z!zW@B=BW82hN4_;C#3gz6zItx$rgk7Oa7*;oEQn+zfZY z_u&U{KRf^r!Y|-acp82Szk@%+^Y9w<{tmChKadECQ3#SCDGEh0Bu5IQL@LB012Um- zWJQt4j#{H+)CRRh?NAD8kGh~V)C=`SeNZ;aLAhuIa-)&xIaG|wQ3a|*RY*Xy(E{W{ z%h4)Sk2au<=pD2Jy@z(9J!mi5hxVfb=#&?IgHEGw(Rb(!`W~G{=g}|d0eX!7#t35^ zf+bjv6p28LsdjES)` z4kn6mF)f%*OlPJGlg6Yo8B8yxH`9m7WQH;$7&kMTDPo>uip9)0rj#l3oxq*(VUp|9 zG1En6VkYiwE15!=)g44PfDWJ|=ma{0E+7r0gRY<(Q4uQO}->w5x374V)7M=waVeWyJut+6<3TeOE2>j`iQv9 z_m4QzTR_FRg`@fvj`EbKf%F8Bf>0m>1;FFyF$@d`BY+!>1chJ}7!8U@IEf$@VkJDW zkw{`Ejs`FWjHOI6=->Z92^a_Zk|@%iGBMG=QRGEZO}V&-mK07MUs;h`=JB}Ih9)k) zts!$AZnZk+x$%>`dq!1`9qS43I|*I@Rp3R+q#8^EUO;?9G=2Ft1dwQw@(q{{X3(jb zU>10ZPFI6DU@n*k@_h$2nc;0nJ2fORr@#WRkS=-!ECP$c65s<%L5430;B~N)#F7@I6;Yl5Z-Td|W(_@2-O%1ep3;iqF~y#;yxyfno+%`b z9xHwrwONU$qGkEy;xQG+K{99q)_}D>rQ8PB`4Z%IcM!twq&m{luQ9k=Nnv@pr@Rq; zQ(!8=KQ$-_b^>gpyKVasv@2Nd#Ny05!b1?;r3J0&7rw(8ptPYsb$*{ zn#lal{|qG60xz|+GI+8t!B=i|jPDp@^4()qA>c4bc{*0ggNu%Wuia{UV9^k*ECd|$ zFA9w9{hD0g7+xp9DG*%?PLkAG@D1re!?aM6(B%v`>z95{I@W?8NGIaX?O#}2+Nkq0 zxB%FCa31^uekGkr7m`*FE>a_2Ch63OBk4{0S~4omUzOo(WrMhmK&_k^(X)7_tEe zK^Ki#7z^WIJQ+;#$&i1=EQ#yx539yVdnO2x0*t=Y*w3Fy$HQ^uo_My6G$bQ(zuTRX9BhkPKPtdL{e4k;x?YDSdm|^pt>3(A3M}iV>MP{VOZ{nJK-j ztZ-^QTn^fTlt#$c;TwLcD@j!?$e>4ZyVaU*<4eoOmw0*VC7#h0o}$dcNyTFeY323pHO6McKOs#>4e$oM32(vM z@D98S@4@@<0a-$PWGQ)-EF;Uw3i29xy@6(yNANNH8}vm0LHdblFs>wTkT>b~Tcn15 z*3$htn!X>RMw%M3Di8`ti*z)zJPCyyPenbI=s^m-opcZ|7~-BRr}-Y4p|^%i3Cbg$ zk@JDylyqEs2Z{sHYf%)6Mlr~VTqu^TCTqxAvW~1L4Qo+6YJpl(ehIYtzfImJA5dl= z)BkRtM$h?P*V}wmdaKW=&uMfdN<|$3TZ=l74YjBf*+_ETY84HRL4_rip7Qi^f1~ik z;3yr@rl<~eMcv3dWK$i=Kt0I2WG8JZf`zlYXWaOv8X8FYs4vR&tMo(t$!4;p4rS3F zTgevU_BPhx0gdQ+Xb5#D>W>Dae7a&A+3p_{P=zgIhhJsbfHF@xt;96pjV~=opFp$A z=)mtrghEv0->g3xO_#st|KZoAng#TFRg{e{De;uix*uTXMbD$s;C>~bfiBubTKe~E z)S+5=xwP1qyVbg<$uX&2n|Qumo8+e4h$f*aP3D_Qc9YyjGB2WO^ny@RZK_3H@?q2c zMbpttI^m_8wyZ_7$VX3SUPg2245%S-wE^ahR~{`yGzmTN(PFaa=_X6jtId)FT7h0~ zyq0Js+4tmHqBo(p9=(NXP%YU{J|Tz5lqUbLM(duvaA-YhAP2}ne;lZ395me-fBLqk zO-y_CwxUgFOEcxIXdC&Id`5Dcce(boB?-;+b|G$eGsO?lN91$z1x+%KBEqp-o#8tc zol(%NyK6M;LG%^vBhV-4Q}h`+gg!@KpfAZ0a+G{cj*;W!1Ub15IM5Mv6n%}3q2uTT ztr({S$O=#|K)V1l1lWV#2eEYzi+(^q`JMD5`KA_~Bd4jjRuStBMhN;9U8ng0T|gJn zC3G46hOVHi=oy`T{n=;hSn`ZiACUgyTNFD? z_Y~h8kX~@BJJVj*>C1~TJ~L?zOkQ%U`}rGT-{a`8XYd?>$=`fiddc>RBBG~l00*s{N+-v8n&Uf8yJI%p3S7z9m4H0AmFhSC8-DyZD{};|174fGsKJ=Hyy0 z0~qE%7BeD7>?e>Qz{CInd$1A!Fp$sdT3K9D^u(Nug3F$4S^S?m|WVaVGOwj`D8l>2R=^13>sbhM8lo7e(iwdXmg%x~KQfg9) z`bwZBWcosHEl?2jq(x-1pqExBW}v?&p-W62Gl&_?$XNmQ7GPf*gZ%}V zMWf+q>0yTZbF%<@JzF5yrlik|3QqU&SBPiCV}s&;{u1;4@qnkL z!{F0&(t4RnW>Q`bZR0!y0tqmINDxQglB9wzwANll_c6dS`qq)dCi>Qq$C21U-#PZD z?-VCuLf<6L#4q8O@mxF~FT|_pyTn?W6xQH%xB+j#@6aoGjH8Ri0Wow>_A6nPnuM&uAhi=3iZQM{<7C_$7YN*1*h^%nIN^%rG{28wb-d7{Ch zA)*4&aM2{u9MN*oXQDG=sW@C5CvGQhFHRNr6b}^-6ORy&6ps=YiN}ba6F)C55qrgg zc!qeEc(!o{f(p#a@P-Univ_)us=*TBDYvt?ZZ_78zH_124 zx61d(zm#8;|D`Y}k`-x+L5k6e5=E(Ef}%`Op{Q1P6@p@hVwPgIqE7L-;m7|rnlkb*j~>wW{^1EvnB|CsjYHuBvXU?yByq{!%?si_{@%samF1s8#9~ z>OSgm>X+27s28c1sNYi8dDW}c>(mYE4eCAWL+Zooqv~Vo6Y6v73+hYi-_+ODf2wb) zZ)=c7ud!%iG|8Iwnhu&yny#AenjV^7nruyhrbtt+c|kK~VM%`MFx%{|QnR?Ny+1*>9ptk=LASu^WkTd=8Y7dD;k z#`a?Su>IIfb|hQOPGYCBRqQmDu+!Oj>>_pvyOdqV*0bx`x7m&C7IquEgWbvQV)wB} z*c0q2_B4Bz{gFM#o@cMJ_t}56P>Z!9tz4_rsLbzvDW9+ zzN%fWeNDSkyGpxRyH&eg`<`}}_5yXZ%i_&${4b+X(P1n7q ztJBr%*623rcI)=*4(X2Rj_Xe9e$f4>JE!|icSUzicSmHS+OXEJ-tewri(#8#hheAT zpy6x74~FxGUkw)xR}H@#{xIAyJmx|<4X5Sw9LHHWo{QuhTr?N&<+^bLxEwBz%jbr2 z!?vaiB5Bm}eYn z9A@;6Fpe~q8YdfP8s`}285bCr7?&EC8CMuL7`GcAnWQFzDasUMa+%^xEljOUiKf=3 zuBPs$9;V)=ex@u_wkgjv*i>qoXIf!;*L2==+pIE&o2_P>*lBg_-c<>pHB zWb;&WmATsNH4Ek$=4Iv;=GV<{nBVl8Ys~fLwdMx%M)M}~Zu3XxJ?4Gpzr$ojyN6hYsAHf%Mn*B36@Tl9+qB~K9+u#Ov_-)5KDn&xW#QLw0NJl zOtuJ?g_h-(*DNb7t1NF>)?41TY_x2$Y_@E*9JbuHB5SO*wY8%)!9<&~|p0@sMy>7i{ zePDfPeQf=Qm++yyf>-e@uk-Q|d<>t+cjkNYz4^X;e?E)P=L`4|{78N@@8L`N$^0~a z9>0`d#;@RC=ilJh@ay>v{5$++ek;G5Kg1vBf8sCmSNLoEb^cHO0sn~q#|CYTO>9%y zOg6hM!Pef^!Pd#v#g=aCW9x4lV9U1U*#_H2+Q!)?+q^Svvu$&23v7#QOKdf^b++xc zPi%*5U)qk?j@eGyPTS7dez0A)-LT!V-Lc)bJ+%ED2_tc&C{h(^j%*#-C(<2R5jj6{ zP2>lW5ADbI$7#o}j;oIAjvJ2Kj)#uFqhJ&hC5}=>u~DX|=%^M^2~n-1+D3JXN{i|i)g!7` z)WE3xsKTh?m?JUAV$Q@|j`<_zt`j@ePOZ~xaGIRqPOCH0*~*#ZOm?<&raC)1J3G^y z9_L)=cIS`IOU^%>_ni-2j7#QHyR0soE7sM*)ykFVN_F*jWx29lxvoL3d{=>Mgsae1 z CGFloat { return UITableViewAutomaticDimension } + + func heightCall(item: DataType, width: CGFloat) -> CGFloat { + + guard let cell = prototypeCell else { return 0 } + + cell.bounds = CGRectMake(0, 0, width, cell.bounds.height) + + cell.configure(item) + + cell.setNeedsLayout() + cell.layoutIfNeeded() + + return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1 + } + + // прехит по мере скроллинга в бэк + // прехит не должен прехитить то что уже есть (показанное) + // по мере скроллинга уметь отменять перхит () public override func rowHeight(index: Int) -> CGFloat { @@ -172,22 +190,11 @@ public class TablePrototypeRowBuilder AnyObject? { if case .configure = action { diff --git a/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift b/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift index 5a848f6..498d200 100644 --- a/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift +++ b/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift @@ -30,7 +30,7 @@ class StoryboardImageTableViewCell: UITableViewCell, ConfigurableCell { override func layoutSubviews() { super.layoutSubviews() - //contentView.layoutIfNeeded() + contentView.layoutIfNeeded() subtitleLabel.preferredMaxLayoutWidth = subtitleLabel.bounds.size.width } diff --git a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj b/TabletDemo/TabletDemo.xcodeproj/project.pbxproj index 0a8c7bf..5b1d76e 100644 --- a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj +++ b/TabletDemo/TabletDemo.xcodeproj/project.pbxproj @@ -7,9 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 5058386B1CF6189D00224C58 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5058386A1CF6189D00224C58 /* Tablet.framework */; }; + 5058386C1CF6189D00224C58 /* Tablet.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5058386A1CF6189D00224C58 /* Tablet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; DA08A0531CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */; }; - DA539C901CF50E9900368ACB /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA539C8F1CF50E9900368ACB /* Tablet.framework */; }; - DA539C911CF50E9900368ACB /* Tablet.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA539C8F1CF50E9900368ACB /* Tablet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */; }; DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */; }; DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */; }; @@ -26,7 +26,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - DA539C911CF50E9900368ACB /* Tablet.framework in Embed Frameworks */, + 5058386C1CF6189D00224C58 /* Tablet.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -34,8 +34,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 5058386A1CF6189D00224C58 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = Tablet.framework; path = "/Users/max/Library/Developer/Xcode/DerivedData/Tablet-bomgsgklcxthxkeamvdbfmrhqnno/Build/Products/Debug-iphonesimulator/Tablet.framework"; sourceTree = ""; }; DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardImageTableViewCell.swift; sourceTree = ""; }; - DA539C8F1CF50E9900368ACB /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = Tablet.framework; path = "/Users/maxsokolov/Library/Developer/Xcode/DerivedData/Tablet-hgommdyxtgxijceamltarpblrbwc/Build/Products/Debug-iphoneos/Tablet.framework"; sourceTree = ""; }; DAB7EB271BEF787300D2AD5E /* TabletDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabletDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; @@ -52,7 +52,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DA539C901CF50E9900368ACB /* Tablet.framework in Frameworks */, + 5058386B1CF6189D00224C58 /* Tablet.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -69,7 +69,7 @@ DAB7EB1E1BEF787300D2AD5E = { isa = PBXGroup; children = ( - DA539C8F1CF50E9900368ACB /* Tablet.framework */, + 5058386A1CF6189D00224C58 /* Tablet.framework */, DAC2D5C61C9D2FE5009E9C19 /* Classes */, DAC2D5CB1C9D3058009E9C19 /* Resources */, DA539C871CF50B1800368ACB /* Frameworks */, From 051dba0e970e017ab74d419a738b760ef3b79338 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Wed, 25 May 2016 21:54:04 +0300 Subject: [PATCH 10/34] builders to separate files --- .../UserInterfaceState.xcuserstate | Bin 18832 -> 18062 bytes Tablet/TableBaseRowBuilder.swift | 135 ++++++++++++ Tablet/TablePrototypeRowBuilder.swift | 112 ++++++++++ Tablet/TableRowBuilder.swift | 208 +----------------- Tablet/Tablet.xcodeproj/project.pbxproj | 16 +- 5 files changed, 263 insertions(+), 208 deletions(-) create mode 100644 Tablet/TableBaseRowBuilder.swift create mode 100644 Tablet/TablePrototypeRowBuilder.swift diff --git a/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate b/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate index bb497d2bd25cc669c22a1cf2a053676b4919f68c..b016cadf59844c2010e0917ab4e8bf123f58a10b 100644 GIT binary patch delta 6954 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 delta 7624 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 : RowBuilder { + + public private(set) weak var tableDirector: TableDirector? + + private var actions = [String: ActionHandler]() + private var items = [DataType]() + + public let reusableIdentifier: String + + public var numberOfRows: Int { + return items.count + } + + public init(item: DataType, id: String? = nil) { + + reusableIdentifier = id ?? String(CellType) + items.append(item) + } + + public init(items: [DataType]? = nil, id: String? = nil) { + + reusableIdentifier = id ?? String(CellType) + + if let items = items { + self.items.appendContentsOf(items) + } + } + + public func rowHeight(index: Int) -> CGFloat { + return UITableViewAutomaticDimension + } + + public func estimatedRowHeight() -> CGFloat { + return 44 + } + + // MARK: - Chaining actions - + + public func action(key: String, handler: (data: ActionData) -> Void) -> Self { + + actions[key] = .Handler(handler) + return self + } + + public func action(type: ActionType, handler: (data: ActionData) -> Void) -> Self { + + actions[type.key] = .Handler(handler) + return self + } + + public func valueAction(type: ActionType, handler: (data: ActionData) -> ReturnValue) -> Self { + + actions[type.key] = .ValueHandler(handler) + return self + } + + public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { + + if let action = actions[action.key] { + return action.invoke(ActionData(cell: cell as? CellType, indexPath: indexPath, item: items[itemIndex], itemIndex: itemIndex, userInfo: userInfo)) + } + return nil + } + + private func registerCell(inTableView tableView: UITableView) { + + if tableView.dequeueReusableCellWithIdentifier(reusableIdentifier) != nil { + return + } + + let resource = String(CellType) + let bundle = NSBundle(forClass: CellType.self) + + if let _ = bundle.pathForResource(resource, ofType: "nib") { // existing cell + tableView.registerNib(UINib(nibName: resource, bundle: bundle), forCellReuseIdentifier: reusableIdentifier) + } else { + tableView.registerClass(CellType.self, forCellReuseIdentifier: reusableIdentifier) + } + } + + public func willUpdateDirector(director: TableDirector?) { + tableDirector = director + + + } + + // MARK: - Items manipulation - + + public func item(index index: Int) -> DataType { + return items[index] + } + + public func append(items items: [DataType]) { + self.items.appendContentsOf(items) + } + + public func clear() { + items.removeAll() + } +} + +public func +=(left: TableBaseRowBuilder, right: DataType) { + left.append(items: [right]) +} + +public func +=(left: TableBaseRowBuilder, right: [DataType]) { + left.append(items: right) +} \ No newline at end of file diff --git a/Tablet/TablePrototypeRowBuilder.swift b/Tablet/TablePrototypeRowBuilder.swift new file mode 100644 index 0000000..b28cf68 --- /dev/null +++ b/Tablet/TablePrototypeRowBuilder.swift @@ -0,0 +1,112 @@ +// +// Copyright (c) 2015 Max Sokolov https://twitter.com/max_sokolov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import UIKit + +public class TablePrototypeRowBuilder : TableBaseRowBuilder { + + private var cachedHeights = [Int: CGFloat]() + private var prototypeCell: CellType? + + public init(item: DataType) { + super.init(item: item, id: CellType.reusableIdentifier()) + } + + public init(items: [DataType]? = nil) { + super.init(items: items, id: CellType.reusableIdentifier()) + } + + public override func estimatedRowHeight() -> CGFloat { + return UITableViewAutomaticDimension + } + + func heightCall(item: DataType, width: CGFloat) -> CGFloat { + + guard let cell = prototypeCell else { return 0 } + + cell.bounds = CGRectMake(0, 0, width, cell.bounds.height) + + cell.configure(item) + + cell.setNeedsLayout() + cell.layoutIfNeeded() + + return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1 + } + + // прехит по мере скроллинга в бэк + // прехит не должен прехитить то что уже есть (показанное) + // по мере скроллинга уметь отменять перхит () + + public override func rowHeight(index: Int) -> CGFloat { + + guard let cell = prototypeCell else { return 0 } + + let itemz = item(index: index) + + if let height = cachedHeights[itemz.hashValue] { + return height + } + + let height = heightCall(itemz, width: tableDirector?.tableView?.bounds.size.width ?? 0) + + cachedHeights[itemz.hashValue] = height + + print(tableDirector?.tableView?.bounds.size.width, cell.bounds.height, height) + + return height + } + + public func preheat(item: DataType) { + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { + + let height = self.heightCall(item, width: 0) + + // check if actual height exists + // calc height + + //let heights = self.items.map { self.heightZ($0) } + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { + + // check if table width is actual + // store height in cache + } + } + } + + public override func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { + + if case .configure = action { + + (cell as? CellType)?.configure(item(index: itemIndex)) + } + return super.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: itemIndex, userInfo: userInfo) + } + + public override func willUpdateDirector(director: TableDirector?) { + + //tableDirector = director + if let tableView = director?.tableView, cell = tableView.dequeueReusableCellWithIdentifier(reusableIdentifier) as? CellType { + prototypeCell = cell + } + } +} \ No newline at end of file diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index b101ddc..210a3e8 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -20,108 +20,6 @@ import UIKit -public typealias ReturnValue = AnyObject? - -/** - Responsible for building cells of given type and passing items to them. - */ -public class TableBaseRowBuilder : RowBuilder { - - public private(set) weak var tableDirector: TableDirector? - - private var actions = [String: ActionHandler]() - private var items = [DataType]() - - public let reusableIdentifier: String - - public var numberOfRows: Int { - return items.count - } - - public init(item: DataType, id: String? = nil) { - - reusableIdentifier = id ?? String(CellType) - items.append(item) - } - - public init(items: [DataType]? = nil, id: String? = nil) { - - reusableIdentifier = id ?? String(CellType) - - if let items = items { - self.items.appendContentsOf(items) - } - } - - public func rowHeight(index: Int) -> CGFloat { - return UITableViewAutomaticDimension - } - - public func estimatedRowHeight() -> CGFloat { - return 44 - } - - // MARK: - Chaining actions - - - public func action(key: String, handler: (data: ActionData) -> Void) -> Self { - - actions[key] = .Handler(handler) - return self - } - - public func action(type: ActionType, handler: (data: ActionData) -> Void) -> Self { - - actions[type.key] = .Handler(handler) - return self - } - - public func valueAction(type: ActionType, handler: (data: ActionData) -> ReturnValue) -> Self { - - actions[type.key] = .ValueHandler(handler) - return self - } - - public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { - - if let action = actions[action.key] { - return action.invoke(ActionData(cell: cell as? CellType, indexPath: indexPath, item: items[itemIndex], itemIndex: itemIndex, userInfo: userInfo)) - } - return nil - } - - private func registerCell(inTableView tableView: UITableView) { - - if tableView.dequeueReusableCellWithIdentifier(reusableIdentifier) != nil { - return - } - - let resource = String(CellType) - let bundle = NSBundle(forClass: CellType.self) - - if let _ = bundle.pathForResource(resource, ofType: "nib") { // existing cell - tableView.registerNib(UINib(nibName: resource, bundle: bundle), forCellReuseIdentifier: reusableIdentifier) - } else { - tableView.registerClass(CellType.self, forCellReuseIdentifier: reusableIdentifier) - } - } - - public func willUpdateDirector(director: TableDirector?) { - tableDirector = director - - - } - - // MARK: - Items manipulation - - - public func append(items items: [DataType]) { - self.items.appendContentsOf(items) - } - - public func clear() { - items.removeAll() - } -} - /** Responsible for building configurable cells of given type and passing items to them. */ @@ -130,118 +28,20 @@ public class TableRowBuilder AnyObject? { if case .configure = action { - (cell as? CellType)?.configure(items[itemIndex]) + (cell as? CellType)?.configure(item(index: itemIndex)) } return super.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: itemIndex, userInfo: userInfo) } - + public override func estimatedRowHeight() -> CGFloat { return CGFloat(CellType.estimatedHeight()) } -} - -public class TablePrototypeRowBuilder : TableBaseRowBuilder { - - private var cachedHeights = [Int: CGFloat]() - private var prototypeCell: CellType? - - public init(item: DataType) { - super.init(item: item, id: CellType.reusableIdentifier()) - } - - public init(items: [DataType]? = nil) { - super.init(items: items, id: CellType.reusableIdentifier()) - } - - public override func estimatedRowHeight() -> CGFloat { - return UITableViewAutomaticDimension - } - - func heightCall(item: DataType, width: CGFloat) -> CGFloat { - - guard let cell = prototypeCell else { return 0 } - - cell.bounds = CGRectMake(0, 0, width, cell.bounds.height) - - cell.configure(item) - - cell.setNeedsLayout() - cell.layoutIfNeeded() - - return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1 - } - - // прехит по мере скроллинга в бэк - // прехит не должен прехитить то что уже есть (показанное) - // по мере скроллинга уметь отменять перхит () - - public override func rowHeight(index: Int) -> CGFloat { - - guard let cell = prototypeCell else { return 0 } - - let item = items[index] - - if let height = cachedHeights[item.hashValue] { - return height - } - - let height = heightCall(item, width: tableDirector?.tableView?.bounds.size.width ?? 0) - - cachedHeights[item.hashValue] = height - - print(tableDirector?.tableView?.bounds.size.width, cell.bounds.height, height) - - return height - } - - public func preheat(item: DataType) { - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { - - let height = self.heightCall(item, width: 0) - - // check if actual height exists - // calc height - - //let heights = self.items.map { self.heightZ($0) } - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { - - // check if table width is actual - // store height in cache - } - } - } - - public override func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { - - if case .configure = action { - (cell as? CellType)?.configure(items[itemIndex]) - } - return super.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: itemIndex, userInfo: userInfo) - } - - public override func willUpdateDirector(director: TableDirector?) { - - tableDirector = director - if let tableView = director?.tableView, cell = tableView.dequeueReusableCellWithIdentifier(reusableIdentifier) as? CellType { - prototypeCell = cell - } - } -} - -public func +=(left: TableBaseRowBuilder, right: DataType) { - left.append(items: [right]) -} - -public func +=(left: TableBaseRowBuilder, right: [DataType]) { - left.append(items: right) } \ No newline at end of file diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index ed7ad7e..77a0417 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -7,12 +7,14 @@ objects = { /* Begin PBXBuildFile section */ + 5058386E1CF62B0700224C58 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */; }; + 505838701CF62B1300224C58 /* TablePrototypeRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */; }; DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */; }; DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */; }; DAC2D6741C9D743D009E9C19 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC2D6691C9D743D009E9C19 /* Tablet.framework */; }; DAC2D6871C9D7517009E9C19 /* Tablet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2D6851C9D7517009E9C19 /* Tablet.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */; }; - DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */; }; + DAC2D6911C9D799E009E9C19 /* TableBaseRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */; }; DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */; }; DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68F1C9D799E009E9C19 /* Tablet.swift */; }; DAC2D6991C9D7A3F009E9C19 /* TabletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D6961C9D7A3B009E9C19 /* TabletTests.swift */; }; @@ -29,6 +31,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = ""; }; + 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TablePrototypeRowBuilder.swift; sourceTree = ""; }; DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowBuilder.swift; sourceTree = ""; }; DAC2D6691C9D743D009E9C19 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Tablet.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -36,7 +40,7 @@ DAC2D6841C9D7517009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DAC2D6851C9D7517009E9C19 /* Tablet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tablet.h; sourceTree = ""; }; DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDirector.swift; sourceTree = ""; }; - DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = ""; }; + DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableBaseRowBuilder.swift; sourceTree = ""; }; DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableSectionBuilder.swift; sourceTree = ""; }; DAC2D68F1C9D799E009E9C19 /* Tablet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tablet.swift; sourceTree = ""; }; DAC2D6951C9D7A3B009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -96,7 +100,9 @@ DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */, DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */, - DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */, + DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */, + 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */, + 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */, DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */, DAC2D68F1C9D799E009E9C19 /* Tablet.swift */, ); @@ -225,7 +231,9 @@ DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */, DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */, DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */, - DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */, + DAC2D6911C9D799E009E9C19 /* TableBaseRowBuilder.swift in Sources */, + 5058386E1CF62B0700224C58 /* TableRowBuilder.swift in Sources */, + 505838701CF62B1300224C58 /* TablePrototypeRowBuilder.swift in Sources */, DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From 3f54cacab0d336f4125e528bf9c7f40d5a278c10 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Thu, 26 May 2016 01:42:55 +0300 Subject: [PATCH 11/34] estimated height improvements --- Tablet/RowBuilder.swift | 2 +- Tablet/TableBaseRowBuilder.swift | 2 +- Tablet/TableDirector.swift | 3 ++- Tablet/TablePrototypeRowBuilder.swift | 21 +--------------- Tablet/TableRowBuilder.swift | 2 +- Tablet/TableSectionBuilder.swift | 2 +- Tablet/Tablet.swift | 3 +-- Tablet/Tablet.xcodeproj/project.pbxproj | 4 ++-- .../Controllers/MainController.swift | 2 +- .../TabletDemo.xcodeproj/project.pbxproj | 24 ++++--------------- 10 files changed, 15 insertions(+), 50 deletions(-) diff --git a/Tablet/RowBuilder.swift b/Tablet/RowBuilder.swift index 0f2415d..02a7abc 100644 --- a/Tablet/RowBuilder.swift +++ b/Tablet/RowBuilder.swift @@ -31,7 +31,7 @@ public protocol RowBuilder { func willUpdateDirector(director: TableDirector?) func rowHeight(index: Int) -> CGFloat - func estimatedRowHeight() -> CGFloat + func estimatedRowHeight(index: Int) -> CGFloat func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? } \ No newline at end of file diff --git a/Tablet/TableBaseRowBuilder.swift b/Tablet/TableBaseRowBuilder.swift index d31f092..f365fc2 100644 --- a/Tablet/TableBaseRowBuilder.swift +++ b/Tablet/TableBaseRowBuilder.swift @@ -57,7 +57,7 @@ public class TableBaseRowBuilder CGFloat { + public func estimatedRowHeight(index: Int) -> CGFloat { return 44 } diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index b0574b5..6bc4d97 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -141,7 +141,8 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate // MARK: UITableViewDelegate - actions public func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - return builderAtIndexPath(indexPath).0.estimatedRowHeight() + let builder = builderAtIndexPath(indexPath) + return builder.0.estimatedRowHeight(builder.1) } public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { diff --git a/Tablet/TablePrototypeRowBuilder.swift b/Tablet/TablePrototypeRowBuilder.swift index b28cf68..f37d158 100644 --- a/Tablet/TablePrototypeRowBuilder.swift +++ b/Tablet/TablePrototypeRowBuilder.swift @@ -33,7 +33,7 @@ public class TablePrototypeRowBuilder CGFloat { + public override func estimatedRowHeight(index: Int) -> CGFloat { return UITableViewAutomaticDimension } @@ -74,25 +74,6 @@ public class TablePrototypeRowBuilder AnyObject? { if case .configure = action { diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index 210a3e8..222e0cc 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -41,7 +41,7 @@ public class TableRowBuilder CGFloat { + public override func estimatedRowHeight(index: Int) -> CGFloat { return CGFloat(CellType.estimatedHeight()) } } \ No newline at end of file diff --git a/Tablet/TableSectionBuilder.swift b/Tablet/TableSectionBuilder.swift index d9e300a..1797852 100644 --- a/Tablet/TableSectionBuilder.swift +++ b/Tablet/TableSectionBuilder.swift @@ -25,7 +25,7 @@ import UIKit Can host several row builders. */ public class TableSectionBuilder { - + weak var tableDirector: TableDirector? { didSet { guard let director = tableDirector else { return } diff --git a/Tablet/Tablet.swift b/Tablet/Tablet.swift index 8e5f0c2..bf5e653 100644 --- a/Tablet/Tablet.swift +++ b/Tablet/Tablet.swift @@ -110,5 +110,4 @@ public class Action { public func invoke() { NSNotificationCenter.defaultCenter().postNotificationName(TabletNotifications.CellAction, object: self, userInfo: userInfo) } -} - +} \ No newline at end of file diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index 77a0417..1317545 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -97,13 +97,13 @@ DAC2D68B1C9D7990009E9C19 /* Classes */ = { isa = PBXGroup; children = ( - DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, - DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */, DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */, + DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */, DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */, 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */, 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */, DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */, + DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, DAC2D68F1C9D799E009E9C19 /* Tablet.swift */, ); name = Classes; diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 20c5328..1b47a81 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -21,7 +21,7 @@ class MainController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - let rows = TablePrototypeRowBuilder(items: ["1", "1", "1", "1"]) + let rows = TableRowBuilder(items: ["1", "1", "1", "1"]) .action(.click) { [unowned self] e in self.performSegueWithIdentifier("headerfooter", sender: nil) } diff --git a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj b/TabletDemo/TabletDemo.xcodeproj/project.pbxproj index 5b1d76e..e5a839f 100644 --- a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj +++ b/TabletDemo/TabletDemo.xcodeproj/project.pbxproj @@ -7,9 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - 5058386B1CF6189D00224C58 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5058386A1CF6189D00224C58 /* Tablet.framework */; }; - 5058386C1CF6189D00224C58 /* Tablet.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5058386A1CF6189D00224C58 /* Tablet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; DA08A0531CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */; }; + DA539C941CF6610400368ACB /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA539C931CF6610400368ACB /* Tablet.framework */; }; DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */; }; DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */; }; DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */; }; @@ -19,23 +18,9 @@ DACB717A1CC2D89D00432BD3 /* HeaderFooterController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACB71791CC2D89D00432BD3 /* HeaderFooterController.swift */; }; /* End PBXBuildFile section */ -/* Begin PBXCopyFilesBuildPhase section */ - DA539C921CF50E9900368ACB /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 5058386C1CF6189D00224C58 /* Tablet.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ - 5058386A1CF6189D00224C58 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = Tablet.framework; path = "/Users/max/Library/Developer/Xcode/DerivedData/Tablet-bomgsgklcxthxkeamvdbfmrhqnno/Build/Products/Debug-iphonesimulator/Tablet.framework"; sourceTree = ""; }; DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardImageTableViewCell.swift; sourceTree = ""; }; + DA539C931CF6610400368ACB /* Tablet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Tablet.framework; path = "../../../../../Library/Developer/Xcode/DerivedData/Tablet-hgommdyxtgxijceamltarpblrbwc/Build/Products/Debug-iphoneos/Tablet.framework"; sourceTree = ""; }; DAB7EB271BEF787300D2AD5E /* TabletDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabletDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; @@ -52,7 +37,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5058386B1CF6189D00224C58 /* Tablet.framework in Frameworks */, + DA539C941CF6610400368ACB /* Tablet.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -62,6 +47,7 @@ DA539C871CF50B1800368ACB /* Frameworks */ = { isa = PBXGroup; children = ( + DA539C931CF6610400368ACB /* Tablet.framework */, ); name = Frameworks; sourceTree = ""; @@ -69,7 +55,6 @@ DAB7EB1E1BEF787300D2AD5E = { isa = PBXGroup; children = ( - 5058386A1CF6189D00224C58 /* Tablet.framework */, DAC2D5C61C9D2FE5009E9C19 /* Classes */, DAC2D5CB1C9D3058009E9C19 /* Resources */, DA539C871CF50B1800368ACB /* Frameworks */, @@ -166,7 +151,6 @@ DAB7EB231BEF787300D2AD5E /* Sources */, DAB7EB241BEF787300D2AD5E /* Frameworks */, DAB7EB251BEF787300D2AD5E /* Resources */, - DA539C921CF50E9900368ACB /* Embed Frameworks */, ); buildRules = ( ); From 82fce34c2e72ba13a58a5925a07e7c0d1df7946f Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Thu, 26 May 2016 02:27:58 +0300 Subject: [PATCH 12/34] doing animations --- Tablet/TableBaseRowBuilder.swift | 5 +++++ Tablet/TablePrototypeRowBuilder.swift | 2 +- .../Classes/Presentation/Controllers/MainController.swift | 7 ++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Tablet/TableBaseRowBuilder.swift b/Tablet/TableBaseRowBuilder.swift index f365fc2..e8b1db0 100644 --- a/Tablet/TableBaseRowBuilder.swift +++ b/Tablet/TableBaseRowBuilder.swift @@ -113,6 +113,11 @@ public class TableBaseRowBuilder, withRowAnimation: <#T##UITableViewRowAnimation#>) + } + public func item(index index: Int) -> DataType { return items[index] } diff --git a/Tablet/TablePrototypeRowBuilder.swift b/Tablet/TablePrototypeRowBuilder.swift index f37d158..a1661bc 100644 --- a/Tablet/TablePrototypeRowBuilder.swift +++ b/Tablet/TablePrototypeRowBuilder.swift @@ -84,8 +84,8 @@ public class TablePrototypeRowBuilder(items: ["1", "1", "1", "1"]) + let rows = TablePrototypeRowBuilder(items: ["1", "1", "1", "1"]) .action(.click) { [unowned self] e in self.performSegueWithIdentifier("headerfooter", sender: nil) } + + let rows2 = TablePrototypeRowBuilder(items: ["1", "1", "1", "1"]) + + rows.remove(index: 0, animated: .None) tableDirector += rows + tableDirector += rows2 } } \ No newline at end of file From 7f1edda39e70e6b905520eaa6b92504edf4df7fb Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Sat, 28 May 2016 14:34:37 +0300 Subject: [PATCH 13/34] fix scroll delegate --- Tablet/TableDirector.swift | 5 +++-- Tablet/TableRowBuilder.swift | 12 ++++++++++++ .../Controllers/MainController.swift | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 6bc4d97..f0c8374 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -26,12 +26,13 @@ import UIKit public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate { public private(set) weak var tableView: UITableView? - public weak var scrollDelegate: UIScrollViewDelegate? + private weak var scrollDelegate: UIScrollViewDelegate? private var sections = [TableSectionBuilder]() - public init(tableView: UITableView) { + public init(tableView: UITableView, scrollDelegate: UIScrollViewDelegate? = nil) { super.init() + self.scrollDelegate = scrollDelegate self.tableView = tableView self.tableView?.delegate = self self.tableView?.dataSource = self diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index 222e0cc..8cedf6c 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -43,5 +43,17 @@ public class TableRowBuilder CGFloat { return CGFloat(CellType.estimatedHeight()) + } +} + +public class LolRowBuilder { + + public init() { + + } + + public func append(items: [ItemType], cellType: CellType.Type) { + + } } \ No newline at end of file diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 8e3330f..45ad1fc 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -9,6 +9,19 @@ import UIKit import Tablet +class LolCell: UITableViewCell, ConfigurableCell { + + typealias T = String + + func configure(str: T) { + + } + + static func estimatedHeight() -> Float { + return 44 + } +} + class MainController: UIViewController { @IBOutlet weak var tableView: UITableView! { @@ -28,9 +41,14 @@ class MainController: UIViewController { let rows2 = TablePrototypeRowBuilder(items: ["1", "1", "1", "1"]) + // animation task rows.remove(index: 0, animated: .None) tableDirector += rows tableDirector += rows2 + + let lolBuilder = LolRowBuilder() + + lolBuilder.append(["1", "2", "3"], cellType: LolCell.self) } } \ No newline at end of file From 4bda5142772673f73b5c71c975534b51d8df1afa Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Sun, 29 May 2016 13:58:05 +0300 Subject: [PATCH 14/34] add operators --- Tablet/Operators.swift | 54 +++++++++++++++++++ Tablet/TableBaseRowBuilder.swift | 29 ++++++---- Tablet/TableDirector.swift | 40 ++++++-------- Tablet/TableRowBuilder.swift | 12 ----- Tablet/TableSectionBuilder.swift | 8 --- Tablet/Tablet.xcodeproj/project.pbxproj | 4 ++ .../Controllers/MainController.swift | 46 ++++++++-------- 7 files changed, 116 insertions(+), 77 deletions(-) create mode 100644 Tablet/Operators.swift diff --git a/Tablet/Operators.swift b/Tablet/Operators.swift new file mode 100644 index 0000000..fa2f029 --- /dev/null +++ b/Tablet/Operators.swift @@ -0,0 +1,54 @@ +// +// Copyright (c) 2015 Max Sokolov https://twitter.com/max_sokolov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// - +public func +=(left: TableDirector, right: RowBuilder) { + left.append(section: TableSectionBuilder(rows: [right])) +} + +public func +=(left: TableDirector, right: [RowBuilder]) { + left.append(section: TableSectionBuilder(rows: right)) +} + +public func +=(left: TableDirector, right: TableSectionBuilder) { + left.append(section: right) +} + +public func +=(left: TableDirector, right: [TableSectionBuilder]) { + left.append(sections: right) +} + +// - +public func +=(left: TableBaseRowBuilder, right: DataType) { + left.append(items: [right]) +} + +public func +=(left: TableBaseRowBuilder, right: [DataType]) { + left.append(items: right) +} + +// - +public func +=(left: TableSectionBuilder, right: RowBuilder) { + left.append(row: right) +} + +public func +=(left: TableSectionBuilder, right: [RowBuilder]) { + left.append(rows: right) +} \ No newline at end of file diff --git a/Tablet/TableBaseRowBuilder.swift b/Tablet/TableBaseRowBuilder.swift index e8b1db0..e84fff5 100644 --- a/Tablet/TableBaseRowBuilder.swift +++ b/Tablet/TableBaseRowBuilder.swift @@ -113,9 +113,26 @@ public class TableBaseRowBuilder Self { - //tableDirector?.tableView?.deleteRowsAtIndexPaths(<#T##indexPaths: [NSIndexPath]##[NSIndexPath]#>, withRowAnimation: <#T##UITableViewRowAnimation#>) + return self + } + + public func insert(items: [DataType], atIndex index: Int, animated: UITableViewRowAnimation) -> Self { + + self.items.insertContentsOf(items, at: index) + + return self + } + + public func move(indexes: [Int], toIndexes: [Int]) -> Self { + + return self + } + + public func update(index index: Int, item: DataType, animated: UITableViewRowAnimation) -> Self { + + return self } public func item(index index: Int) -> DataType { @@ -129,12 +146,4 @@ public class TableBaseRowBuilder(left: TableBaseRowBuilder, right: DataType) { - left.append(items: [right]) -} - -public func +=(left: TableBaseRowBuilder, right: [DataType]) { - left.append(items: right) } \ No newline at end of file diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index f0c8374..4858084 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -43,17 +43,23 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } + + public func reload() { + tableView?.reloadData() + } + + public func performBatchUpdates(handler: () -> Void) { + + + } + + public func row(row: T) -> T { + + return row + } // MARK: Private methods - - /** - Find a row builder that responsible for building a row from cell with given item type. - - - Parameters: - - indexPath: path of cell to dequeue - - - Returns: A touple - (builder, builderItemIndex) - */ + private func builderAtIndexPath(indexPath: NSIndexPath) -> (RowBuilder, Int) { return sections[indexPath.section].builderAtIndex(indexPath.row)! } @@ -194,20 +200,4 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate public func clear() { sections.removeAll() } -} - -public func +=(left: TableDirector, right: RowBuilder) { - left.append(section: TableSectionBuilder(rows: [right])) -} - -public func +=(left: TableDirector, right: [RowBuilder]) { - left.append(section: TableSectionBuilder(rows: right)) -} - -public func +=(left: TableDirector, right: TableSectionBuilder) { - left.append(section: right) -} - -public func +=(left: TableDirector, right: [TableSectionBuilder]) { - left.append(sections: right) } \ No newline at end of file diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index 8cedf6c..222e0cc 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -43,17 +43,5 @@ public class TableRowBuilder CGFloat { return CGFloat(CellType.estimatedHeight()) - } -} - -public class LolRowBuilder { - - public init() { - - } - - public func append(items: [ItemType], cellType: CellType.Type) { - - } } \ No newline at end of file diff --git a/Tablet/TableSectionBuilder.swift b/Tablet/TableSectionBuilder.swift index 1797852..819da7d 100644 --- a/Tablet/TableSectionBuilder.swift +++ b/Tablet/TableSectionBuilder.swift @@ -97,12 +97,4 @@ public class TableSectionBuilder { return nil } -} - -public func +=(left: TableSectionBuilder, right: RowBuilder) { - left.append(row: right) -} - -public func +=(left: TableSectionBuilder, right: [RowBuilder]) { - left.append(rows: right) } \ No newline at end of file diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index 1317545..9211a4f 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 505838701CF62B1300224C58 /* TablePrototypeRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */; }; DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */; }; DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */; }; + DA539C9F1CFB025C00368ACB /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539C9E1CFB025C00368ACB /* Operators.swift */; }; DAC2D6741C9D743D009E9C19 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC2D6691C9D743D009E9C19 /* Tablet.framework */; }; DAC2D6871C9D7517009E9C19 /* Tablet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2D6851C9D7517009E9C19 /* Tablet.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */; }; @@ -35,6 +36,7 @@ 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TablePrototypeRowBuilder.swift; sourceTree = ""; }; DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowBuilder.swift; sourceTree = ""; }; + DA539C9E1CFB025C00368ACB /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; DAC2D6691C9D743D009E9C19 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Tablet.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6731C9D743D009E9C19 /* TabletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TabletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6841C9D7517009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -105,6 +107,7 @@ DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */, DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, DAC2D68F1C9D799E009E9C19 /* Tablet.swift */, + DA539C9E1CFB025C00368ACB /* Operators.swift */, ); name = Classes; sourceTree = ""; @@ -235,6 +238,7 @@ 5058386E1CF62B0700224C58 /* TableRowBuilder.swift in Sources */, 505838701CF62B1300224C58 /* TablePrototypeRowBuilder.swift in Sources */, DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */, + DA539C9F1CFB025C00368ACB /* Operators.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 45ad1fc..b77cdcf 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -9,19 +9,6 @@ import UIKit import Tablet -class LolCell: UITableViewCell, ConfigurableCell { - - typealias T = String - - func configure(str: T) { - - } - - static func estimatedHeight() -> Float { - return 44 - } -} - class MainController: UIViewController { @IBOutlet weak var tableView: UITableView! { @@ -34,21 +21,36 @@ class MainController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - let rows = TablePrototypeRowBuilder(items: ["1", "1", "1", "1"]) + let rowBuilder = TableRowBuilder(items: ["1", "1", "1", "1"]) .action(.click) { [unowned self] e in self.performSegueWithIdentifier("headerfooter", sender: nil) } - let rows2 = TablePrototypeRowBuilder(items: ["1", "1", "1", "1"]) + let rows2 = TableRowBuilder(items: ["1", "1", "1", "1"]) - // animation task - rows.remove(index: 0, animated: .None) - tableDirector += rows + + let section = TableSectionBuilder(headerTitle: "", footerTitle: "", rows: [rowBuilder]) + + //tableView.moveSection(0, toSection: 0) + //tableView.reloadSections([], withRowAnimation: .None) + //tableView.deleteSections([], withRowAnimation: .None) + //tableView.insertSections([], withRowAnimation: .None) + + + + tableDirector.performBatchUpdates { + + rowBuilder + .delete(indexes: [0], animated: .None) + .insert(["2"], atIndex: 0, animated: .None) + .update(index: 0, item: "", animated: .None) + .move([1, 2], toIndexes: [3, 4]) + } + + tableDirector.append(section: section) + + tableDirector += rowBuilder tableDirector += rows2 - - let lolBuilder = LolRowBuilder() - - lolBuilder.append(["1", "2", "3"], cellType: LolCell.self) } } \ No newline at end of file From bdf009b980cfe6599e5e1d5205662df25ed0db3a Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Mon, 30 May 2016 01:02:36 +0300 Subject: [PATCH 15/34] update task --- Tablet/TableDirector.swift | 5 ---- .../Controllers/MainController.swift | 23 +++++++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 4858084..87239bc 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -52,11 +52,6 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate } - - public func row(row: T) -> T { - - return row - } // MARK: Private methods diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index b77cdcf..77b07bc 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -9,6 +9,11 @@ import UIKit import Tablet +class TableUpdateTask { + + +} + class MainController: UIViewController { @IBOutlet weak var tableView: UITableView! { @@ -28,24 +33,28 @@ class MainController: UIViewController { let rows2 = TableRowBuilder(items: ["1", "1", "1", "1"]) + rowBuilder + .delete(indexes: [0], animated: .None) + .insert(["2"], atIndex: 0, animated: .None) + .update(index: 0, item: "", animated: .None) + .move([1, 2], toIndexes: [3, 4]) let section = TableSectionBuilder(headerTitle: "", footerTitle: "", rows: [rowBuilder]) + //tableView.moveRowAtIndexPath(<#T##indexPath: NSIndexPath##NSIndexPath#>, toIndexPath: <#T##NSIndexPath#>) + //tableView.deleteRowsAtIndexPaths(<#T##indexPaths: [NSIndexPath]##[NSIndexPath]#>, withRowAnimation: <#T##UITableViewRowAnimation#>) + //tableView.insertRowsAtIndexPaths(<#T##indexPaths: [NSIndexPath]##[NSIndexPath]#>, withRowAnimation: <#T##UITableViewRowAnimation#>) + //tableView.reloadRowsAtIndexPaths(<#T##indexPaths: [NSIndexPath]##[NSIndexPath]#>, withRowAnimation: <#T##UITableViewRowAnimation#>) + //tableView.moveSection(0, toSection: 0) //tableView.reloadSections([], withRowAnimation: .None) //tableView.deleteSections([], withRowAnimation: .None) //tableView.insertSections([], withRowAnimation: .None) - - tableDirector.performBatchUpdates { - rowBuilder - .delete(indexes: [0], animated: .None) - .insert(["2"], atIndex: 0, animated: .None) - .update(index: 0, item: "", animated: .None) - .move([1, 2], toIndexes: [3, 4]) + } tableDirector.append(section: section) From 08fb8af74eb5ea99c548196b3eea46f786760864 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Thu, 2 Jun 2016 00:48:10 +0300 Subject: [PATCH 16/34] add TableRowAction --- Tablet/TableBaseRowBuilder.swift | 19 +++++++++++++++++++ .../Controllers/MainController.swift | 8 ++++++++ 2 files changed, 27 insertions(+) diff --git a/Tablet/TableBaseRowBuilder.swift b/Tablet/TableBaseRowBuilder.swift index e84fff5..13c6cd9 100644 --- a/Tablet/TableBaseRowBuilder.swift +++ b/Tablet/TableBaseRowBuilder.swift @@ -22,6 +22,21 @@ import UIKit public typealias ReturnValue = AnyObject? +public enum TableActionType { + + case Click + case Custom(String) +} + +public class TableRowAction { + + let type: TableActionType + + public init(type: TableActionType, handler: (data: ActionData) -> Void) { + self.type = type + } +} + /** Responsible for building cells of given type and passing items to them. */ @@ -63,6 +78,10 @@ public class TableBaseRowBuilder) { + + } + public func action(key: String, handler: (data: ActionData) -> Void) -> Self { actions[key] = .Handler(handler) diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 77b07bc..f527e9b 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -33,6 +33,14 @@ class MainController: UIViewController { let rows2 = TableRowBuilder(items: ["1", "1", "1", "1"]) + + + rowBuilder + .addAction(TableRowAction(type: .Click) { (data) in + + + }) + rowBuilder .delete(indexes: [0], animated: .None) .insert(["2"], atIndex: 0, animated: .None) From b5c7493140eb1f48e196884d88a2082741e3674f Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Thu, 2 Jun 2016 19:46:50 +0300 Subject: [PATCH 17/34] dynamic cells --- .../UserInterfaceState.xcuserstate | Bin 18062 -> 20594 bytes .../Controllers/MainController.swift | 52 ++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate b/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate index b016cadf59844c2010e0917ab4e8bf123f58a10b..e78d368dbe66dfbbe53fc8b751489cae939ada4d 100644 GIT binary patch literal 20594 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 literal 18062 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

l&ihI7o!KAxecFLNX;n=EbDl5QF+c0THlj(Ddy> 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: CellItemable { + + let item: DataType + + init(item: DataType) { + self.item = item + } + + func configure(cell: UITableViewCell) { + (cell as? CellType)?.configure(item) + } +} + + +class BUILDER { + + var cellItems = [CellItemable]() + + init(cellItems: [CellItemable]) { + self.cellItems = cellItems + + } + + func configure(cell: UITableViewCell, itemIndex: Int) { + + let cellItem = cellItems[itemIndex] + + cellItem.configure(cell) + } +} + + class MainController: UIViewController { @IBOutlet weak var tableView: UITableView! { @@ -33,7 +70,22 @@ class MainController: UIViewController { let rows2 = TableRowBuilder(items: ["1", "1", "1", "1"]) + + + + let cellItem = CellItem(item: "1") + + let cellItem2 = CellItem(item: "1") + + let cellItem3 = CellItem(item: "1") + + + + + let b = BUILDER(cellItems: [cellItem, cellItem2, cellItem3]) + + rowBuilder .addAction(TableRowAction(type: .Click) { (data) in From e121c3fbc625da654e3b2724611bea1fc16a2902 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Sun, 5 Jun 2016 23:58:51 +0300 Subject: [PATCH 18/34] dynamic approach --- Tablet/RowBuilder.swift | 6 +- Tablet/TableBaseRowBuilder.swift | 15 +++-- Tablet/TableDirector.swift | 4 +- Tablet/TableDynamicRowBuilder.swift | 56 +++++++++++++++++++ Tablet/TablePrototypeRowBuilder.swift | 6 +- Tablet/Tablet.xcodeproj/project.pbxproj | 4 ++ .../Controllers/MainController.swift | 43 ++------------ 7 files changed, 81 insertions(+), 53 deletions(-) create mode 100644 Tablet/TableDynamicRowBuilder.swift diff --git a/Tablet/RowBuilder.swift b/Tablet/RowBuilder.swift index 02a7abc..3a524ad 100644 --- a/Tablet/RowBuilder.swift +++ b/Tablet/RowBuilder.swift @@ -23,13 +23,13 @@ import UIKit public protocol RowBuilder { var tableDirector: TableDirector? { get } - - var reusableIdentifier: String { get } - + var numberOfRows: Int { get } func willUpdateDirector(director: TableDirector?) + func reusableIdentifier(index: Int) -> String + func rowHeight(index: Int) -> CGFloat func estimatedRowHeight(index: Int) -> CGFloat diff --git a/Tablet/TableBaseRowBuilder.swift b/Tablet/TableBaseRowBuilder.swift index 13c6cd9..094592d 100644 --- a/Tablet/TableBaseRowBuilder.swift +++ b/Tablet/TableBaseRowBuilder.swift @@ -47,7 +47,10 @@ public class TableBaseRowBuilder]() private var items = [DataType]() - public let reusableIdentifier: String + + public func reusableIdentifier(_: Int) -> String { + return String(CellType) + } public var numberOfRows: Int { return items.count @@ -55,13 +58,13 @@ public class TableBaseRowBuilder: RowItemable { + + public let item: DataType + + public init(item: DataType) { + self.item = item + } + + public func configure(cell: UITableViewCell) { + (cell as? CellType)?.configure(item) + } +} + +public class TableDynamicRowBuilder { + + var items = [RowItemable]() + + public init(items: [RowItemable]) { + self.items = items + + } + + func configure(cell: UITableViewCell, itemIndex: Int) { + + let cellItem = items[itemIndex] + + cellItem.configure(cell) + } +} \ No newline at end of file diff --git a/Tablet/TablePrototypeRowBuilder.swift b/Tablet/TablePrototypeRowBuilder.swift index a1661bc..2d04836 100644 --- a/Tablet/TablePrototypeRowBuilder.swift +++ b/Tablet/TablePrototypeRowBuilder.swift @@ -68,9 +68,7 @@ public class TablePrototypeRowBuilder: CellItemable { - - let item: DataType - - init(item: DataType) { - self.item = item - } - - func configure(cell: UITableViewCell) { - (cell as? CellType)?.configure(item) - } -} - - -class BUILDER { - - var cellItems = [CellItemable]() - - init(cellItems: [CellItemable]) { - self.cellItems = cellItems - - } - - func configure(cell: UITableViewCell, itemIndex: Int) { - - let cellItem = cellItems[itemIndex] - - cellItem.configure(cell) - } -} class MainController: UIViewController { @@ -73,16 +38,16 @@ class MainController: UIViewController { - let cellItem = CellItem(item: "1") + let cellItem = RowItem(item: "1") - let cellItem2 = CellItem(item: "1") + let cellItem2 = RowItem(item: "1") - let cellItem3 = CellItem(item: "1") + let cellItem3 = RowItem(item: "1") - let b = BUILDER(cellItems: [cellItem, cellItem2, cellItem3]) + let b = TableDynamicRowBuilder(items: [cellItem, cellItem2, cellItem3]) From 7faee8f24e0f3fd743e4628b87a77914d8ded93c Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Mon, 6 Jun 2016 23:35:20 +0300 Subject: [PATCH 19/34] add HeightStrategies --- Tablet/HeightStrategy.swift | 66 +++++++++++++++++++ Tablet/TableDirector.swift | 22 ++++--- Tablet/Tablet.xcodeproj/project.pbxproj | 4 ++ .../Controllers/MainController.swift | 11 +++- 4 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 Tablet/HeightStrategy.swift diff --git a/Tablet/HeightStrategy.swift b/Tablet/HeightStrategy.swift new file mode 100644 index 0000000..4938e66 --- /dev/null +++ b/Tablet/HeightStrategy.swift @@ -0,0 +1,66 @@ +// +// Copyright (c) 2015 Max Sokolov https://twitter.com/max_sokolov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import UIKit + +public protocol HeightStrategy { + + func height(item: Item, cell: Cell.Type) -> CGFloat + + func estimatedHeight() -> CGFloat +} + +public class AutolayoutHeightStrategy: HeightStrategy { + + public func height(item: Item, cell: Cell.Type) -> CGFloat { + return UITableViewAutomaticDimension + } + + public func estimatedHeight() -> CGFloat { + return 0 + } +} + +public class PrototypeHeightStrategy: HeightStrategy { + + private weak var tableView: UITableView? + + public init(tableView: UITableView) { + self.tableView = tableView + } + + public func height(item: Item, cell: Cell.Type) -> CGFloat { + + guard let cell = tableView?.dequeueReusableCellWithIdentifier(Cell.reusableIdentifier()) as? Cell else { return 0 } + + cell.bounds = CGRectMake(0, 0, tableView?.bounds.size.width ?? 0, cell.bounds.height) + + cell.configure(item) + + cell.setNeedsLayout() + cell.layoutIfNeeded() + + return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1 + } + + public func estimatedHeight() -> CGFloat { + return UITableViewAutomaticDimension + } +} \ No newline at end of file diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 7860e71..4ed254f 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -86,6 +86,18 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate } } + // MARK: - Height + + public func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { + let builder = builderAtIndexPath(indexPath) + return builder.0.estimatedRowHeight(builder.1) + } + + public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { + let builder = builderAtIndexPath(indexPath) + return builder.0.rowHeight(builder.1) + } + // MARK: UITableViewDataSource - configuration public func numberOfSectionsInTableView(tableView: UITableView) -> Int { @@ -144,16 +156,6 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate // MARK: UITableViewDelegate - actions - public func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - let builder = builderAtIndexPath(indexPath) - return builder.0.estimatedRowHeight(builder.1) - } - - public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - let builder = builderAtIndexPath(indexPath) - return builder.0.rowHeight(builder.1) - } - public func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let cell = tableView.cellForRowAtIndexPath(indexPath) diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index 84e3ea4..ea1054c 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */; }; DA539C9F1CFB025C00368ACB /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539C9E1CFB025C00368ACB /* Operators.swift */; }; DA539CC61D01D44500368ACB /* TableDynamicRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */; }; + DA9EA7351D06155E0021F650 /* HeightStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7341D06155E0021F650 /* HeightStrategy.swift */; }; DAC2D6741C9D743D009E9C19 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC2D6691C9D743D009E9C19 /* Tablet.framework */; }; DAC2D6871C9D7517009E9C19 /* Tablet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2D6851C9D7517009E9C19 /* Tablet.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */; }; @@ -39,6 +40,7 @@ DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowBuilder.swift; sourceTree = ""; }; DA539C9E1CFB025C00368ACB /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDynamicRowBuilder.swift; sourceTree = ""; }; + DA9EA7341D06155E0021F650 /* HeightStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeightStrategy.swift; sourceTree = ""; }; DAC2D6691C9D743D009E9C19 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Tablet.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6731C9D743D009E9C19 /* TabletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TabletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6841C9D7517009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -111,6 +113,7 @@ DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, DAC2D68F1C9D799E009E9C19 /* Tablet.swift */, DA539C9E1CFB025C00368ACB /* Operators.swift */, + DA9EA7341D06155E0021F650 /* HeightStrategy.swift */, ); name = Classes; sourceTree = ""; @@ -235,6 +238,7 @@ files = ( DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */, DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */, + DA9EA7351D06155E0021F650 /* HeightStrategy.swift in Sources */, DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */, DA539CC61D01D44500368ACB /* TableDynamicRowBuilder.swift in Sources */, DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */, diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 9bf5755..17d4c78 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -9,10 +9,12 @@ import UIKit import Tablet -class TableUpdateTask { - -} + + + + + @@ -28,6 +30,9 @@ class MainController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + let h = PrototypeHeightStrategy(tableView: tableView) + h.height("123", cell: StoryboardImageTableViewCell.self) + let rowBuilder = TableRowBuilder(items: ["1", "1", "1", "1"]) .action(.click) { [unowned self] e in self.performSegueWithIdentifier("headerfooter", sender: nil) From 66f318bb151477e8c2fd8a66e6f118e6eac98d37 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Mon, 6 Jun 2016 23:37:00 +0300 Subject: [PATCH 20/34] remove prototype row builder --- Tablet/TablePrototypeRowBuilder.swift | 91 ------------------- Tablet/Tablet.xcodeproj/project.pbxproj | 4 - .../Controllers/MainController.swift | 9 -- 3 files changed, 104 deletions(-) delete mode 100644 Tablet/TablePrototypeRowBuilder.swift diff --git a/Tablet/TablePrototypeRowBuilder.swift b/Tablet/TablePrototypeRowBuilder.swift deleted file mode 100644 index 2d04836..0000000 --- a/Tablet/TablePrototypeRowBuilder.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (c) 2015 Max Sokolov https://twitter.com/max_sokolov -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import UIKit - -public class TablePrototypeRowBuilder : TableBaseRowBuilder { - - private var cachedHeights = [Int: CGFloat]() - private var prototypeCell: CellType? - - public init(item: DataType) { - super.init(item: item, id: CellType.reusableIdentifier()) - } - - public init(items: [DataType]? = nil) { - super.init(items: items, id: CellType.reusableIdentifier()) - } - - public override func estimatedRowHeight(index: Int) -> CGFloat { - return UITableViewAutomaticDimension - } - - func heightCall(item: DataType, width: CGFloat) -> CGFloat { - - guard let cell = prototypeCell else { return 0 } - - cell.bounds = CGRectMake(0, 0, width, cell.bounds.height) - - cell.configure(item) - - cell.setNeedsLayout() - cell.layoutIfNeeded() - - return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1 - } - - // прехит по мере скроллинга в бэк - // прехит не должен прехитить то что уже есть (показанное) - // по мере скроллинга уметь отменять перхит () - - public override func rowHeight(index: Int) -> CGFloat { - - guard let cell = prototypeCell else { return 0 } - - let itemz = item(index: index) - - if let height = cachedHeights[itemz.hashValue] { - return height - } - - let height = heightCall(itemz, width: tableDirector?.tableView?.bounds.size.width ?? 0) - - cachedHeights[itemz.hashValue] = height - - return height - } - - public override func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { - - if case .configure = action { - - (cell as? CellType)?.configure(item(index: itemIndex)) - } - return super.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: itemIndex, userInfo: userInfo) - } - - public override func willUpdateDirector(director: TableDirector?) { - super.willUpdateDirector(director) - - if let tableView = director?.tableView, cell = tableView.dequeueReusableCellWithIdentifier(reusableIdentifier(0)) as? CellType { - prototypeCell = cell - } - } -} \ No newline at end of file diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index ea1054c..e160546 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 5058386E1CF62B0700224C58 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */; }; - 505838701CF62B1300224C58 /* TablePrototypeRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */; }; DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */; }; DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */; }; DA539C9F1CFB025C00368ACB /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539C9E1CFB025C00368ACB /* Operators.swift */; }; @@ -35,7 +34,6 @@ /* Begin PBXFileReference section */ 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = ""; }; - 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TablePrototypeRowBuilder.swift; sourceTree = ""; }; DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowBuilder.swift; sourceTree = ""; }; DA539C9E1CFB025C00368ACB /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; @@ -107,7 +105,6 @@ DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */, DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */, 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */, - 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */, DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */, DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */, DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, @@ -244,7 +241,6 @@ DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */, DAC2D6911C9D799E009E9C19 /* TableBaseRowBuilder.swift in Sources */, 5058386E1CF62B0700224C58 /* TableRowBuilder.swift in Sources */, - 505838701CF62B1300224C58 /* TablePrototypeRowBuilder.swift in Sources */, DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */, DA539C9F1CFB025C00368ACB /* Operators.swift in Sources */, ); diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 17d4c78..9cbe11a 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -9,15 +9,6 @@ import UIKit import Tablet - - - - - - - - - class MainController: UIViewController { @IBOutlet weak var tableView: UITableView! { From 229ef94c0ea1e0b1b33811c8f49e63e555dd3554 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Tue, 7 Jun 2016 01:56:41 +0300 Subject: [PATCH 21/34] height strategies improvements --- Tablet/ConfigurableCell.swift | 6 ++++- Tablet/HeightStrategy.swift | 26 +++++-------------- Tablet/RowBuilder.swift | 11 +++++--- Tablet/TableBaseRowBuilder.swift | 23 ++++------------ Tablet/TableDirector.swift | 6 ++--- Tablet/TableRowBuilder.swift | 19 ++++++++++++-- Tablet/Tablet.swift | 15 +++++++++++ Tablet/Tablet.xcodeproj/project.pbxproj | 2 +- .../Controllers/MainController.swift | 20 +++++--------- .../Views/StoryboardImageTableViewCell.swift | 6 +---- .../Views/StoryboardTableViewCell.swift | 4 --- 11 files changed, 67 insertions(+), 71 deletions(-) diff --git a/Tablet/ConfigurableCell.swift b/Tablet/ConfigurableCell.swift index ba3ca10..6622122 100644 --- a/Tablet/ConfigurableCell.swift +++ b/Tablet/ConfigurableCell.swift @@ -29,7 +29,7 @@ public protocol ConfigurableCell { associatedtype T static func reusableIdentifier() -> String - static func estimatedHeight() -> Float + static func estimatedHeight() -> CGFloat static func defaultHeight() -> Float? func configure(_: T) } @@ -43,4 +43,8 @@ public extension ConfigurableCell where Self: UITableViewCell { static func defaultHeight() -> Float? { return nil } + + static func estimatedHeight() -> CGFloat { + return UITableViewAutomaticDimension + } } \ No newline at end of file diff --git a/Tablet/HeightStrategy.swift b/Tablet/HeightStrategy.swift index 4938e66..75f9516 100644 --- a/Tablet/HeightStrategy.swift +++ b/Tablet/HeightStrategy.swift @@ -22,31 +22,19 @@ import UIKit public protocol HeightStrategy { - func height(item: Item, cell: Cell.Type) -> CGFloat + var tableView: UITableView? { get set } + + func height(item: Item, indexPath: NSIndexPath, cell: Cell.Type) -> CGFloat func estimatedHeight() -> CGFloat } -public class AutolayoutHeightStrategy: HeightStrategy { - - public func height(item: Item, cell: Cell.Type) -> CGFloat { - return UITableViewAutomaticDimension - } - - public func estimatedHeight() -> CGFloat { - return 0 - } -} - public class PrototypeHeightStrategy: HeightStrategy { + + public weak var tableView: UITableView? + private var cachedHeights = [Int: CGFloat]() - private weak var tableView: UITableView? - - public init(tableView: UITableView) { - self.tableView = tableView - } - - public func height(item: Item, cell: Cell.Type) -> CGFloat { + public func height(item: Item, indexPath: NSIndexPath, cell: Cell.Type) -> CGFloat { guard let cell = tableView?.dequeueReusableCellWithIdentifier(Cell.reusableIdentifier()) as? Cell else { return 0 } diff --git a/Tablet/RowBuilder.swift b/Tablet/RowBuilder.swift index 3a524ad..d10b3cf 100644 --- a/Tablet/RowBuilder.swift +++ b/Tablet/RowBuilder.swift @@ -20,7 +20,13 @@ import UIKit -public protocol RowBuilder { +public protocol RowHeightCalculatable { + + func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat + func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat +} + +public protocol RowBuilder: RowHeightCalculatable { var tableDirector: TableDirector? { get } @@ -30,8 +36,5 @@ public protocol RowBuilder { func reusableIdentifier(index: Int) -> String - func rowHeight(index: Int) -> CGFloat - func estimatedRowHeight(index: Int) -> CGFloat - func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? } \ No newline at end of file diff --git a/Tablet/TableBaseRowBuilder.swift b/Tablet/TableBaseRowBuilder.swift index 094592d..58ca529 100644 --- a/Tablet/TableBaseRowBuilder.swift +++ b/Tablet/TableBaseRowBuilder.swift @@ -22,26 +22,11 @@ import UIKit public typealias ReturnValue = AnyObject? -public enum TableActionType { - - case Click - case Custom(String) -} - -public class TableRowAction { - - let type: TableActionType - - public init(type: TableActionType, handler: (data: ActionData) -> Void) { - self.type = type - } -} - /** Responsible for building cells of given type and passing items to them. */ public class TableBaseRowBuilder : RowBuilder { - + public private(set) weak var tableDirector: TableDirector? private var actions = [String: ActionHandler]() @@ -71,11 +56,13 @@ public class TableBaseRowBuilder CGFloat { + // MARK: - RowHeightCalculatable - + + public func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { return UITableViewAutomaticDimension } - public func estimatedRowHeight(index: Int) -> CGFloat { + public func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { return 44 } diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 4ed254f..72d3a9f 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -90,12 +90,12 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate public func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { let builder = builderAtIndexPath(indexPath) - return builder.0.estimatedRowHeight(builder.1) + return builder.0.estimatedRowHeight(builder.1, indexPath: indexPath) } public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { let builder = builderAtIndexPath(indexPath) - return builder.0.rowHeight(builder.1) + return builder.0.rowHeight(builder.1, indexPath: indexPath) } // MARK: UITableViewDataSource - configuration @@ -112,8 +112,6 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate let builder = builderAtIndexPath(indexPath) - - let cell = tableView.dequeueReusableCellWithIdentifier(builder.0.reusableIdentifier(builder.1), forIndexPath: indexPath) if cell.frame.size.width != tableView.frame.size.width { diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index 222e0cc..d6dbacf 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -25,6 +25,8 @@ import UIKit */ public class TableRowBuilder : TableBaseRowBuilder { + private var heightStrategy: HeightStrategy? + public init(item: DataType) { super.init(item: item, id: CellType.reusableIdentifier()) } @@ -33,6 +35,13 @@ public class TableRowBuilder AnyObject? { if case .configure = action { @@ -41,7 +50,13 @@ public class TableRowBuilder CGFloat { - return CGFloat(CellType.estimatedHeight()) + // MARK: - RowHeightCalculatable - + + public override func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { + return heightStrategy?.height(item(index: index), indexPath: indexPath, cell: CellType.self) ?? 0 + } + + public override func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { + return CellType.estimatedHeight() } } \ No newline at end of file diff --git a/Tablet/Tablet.swift b/Tablet/Tablet.swift index bf5e653..ad2034b 100644 --- a/Tablet/Tablet.swift +++ b/Tablet/Tablet.swift @@ -24,6 +24,21 @@ struct TabletNotifications { static let CellAction = "TabletNotificationsCellAction" } +public enum TableActionType { + + case Click + case Custom(String) +} + +public class TableRowAction { + + let type: TableActionType + + public init(type: TableActionType, handler: (data: ActionData) -> Void) { + self.type = type + } +} + /** The actions that Tablet provides. */ diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index e160546..2c4b42b 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -103,6 +103,7 @@ children = ( DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */, DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */, + DA9EA7341D06155E0021F650 /* HeightStrategy.swift */, DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */, 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */, DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */, @@ -110,7 +111,6 @@ DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, DAC2D68F1C9D799E009E9C19 /* Tablet.swift */, DA539C9E1CFB025C00368ACB /* Operators.swift */, - DA9EA7341D06155E0021F650 /* HeightStrategy.swift */, ); name = Classes; sourceTree = ""; diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 9cbe11a..c39d301 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -20,20 +20,19 @@ class MainController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - - let h = PrototypeHeightStrategy(tableView: tableView) - h.height("123", cell: StoryboardImageTableViewCell.self) let rowBuilder = TableRowBuilder(items: ["1", "1", "1", "1"]) .action(.click) { [unowned self] e in self.performSegueWithIdentifier("headerfooter", sender: nil) } - let rows2 = TableRowBuilder(items: ["1", "1", "1", "1"]) + let section = TableSectionBuilder(headerTitle: "", footerTitle: "", rows: [rowBuilder]) + /*let rows2 = TableRowBuilder(items: ["1", "1", "1", "1"]) + let cellItem = RowItem(item: "1") let cellItem2 = RowItem(item: "1") @@ -44,8 +43,6 @@ class MainController: UIViewController { let b = TableDynamicRowBuilder(items: [cellItem, cellItem2, cellItem3]) - - rowBuilder @@ -58,10 +55,10 @@ class MainController: UIViewController { .delete(indexes: [0], animated: .None) .insert(["2"], atIndex: 0, animated: .None) .update(index: 0, item: "", animated: .None) - .move([1, 2], toIndexes: [3, 4]) + .move([1, 2], toIndexes: [3, 4])*/ - let section = TableSectionBuilder(headerTitle: "", footerTitle: "", rows: [rowBuilder]) + //tableView.moveRowAtIndexPath(<#T##indexPath: NSIndexPath##NSIndexPath#>, toIndexPath: <#T##NSIndexPath#>) //tableView.deleteRowsAtIndexPaths(<#T##indexPaths: [NSIndexPath]##[NSIndexPath]#>, withRowAnimation: <#T##UITableViewRowAnimation#>) @@ -73,14 +70,11 @@ class MainController: UIViewController { //tableView.deleteSections([], withRowAnimation: .None) //tableView.insertSections([], withRowAnimation: .None) - tableDirector.performBatchUpdates { - - - } + //tableDirector.performBatchUpdates { + //} tableDirector.append(section: section) tableDirector += rowBuilder - tableDirector += rows2 } } \ No newline at end of file diff --git a/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift b/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift index 498d200..b161b36 100644 --- a/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift +++ b/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift @@ -22,11 +22,7 @@ class StoryboardImageTableViewCell: UITableViewCell, ConfigurableCell { titleLabel.text = "Test" subtitleLabel.text = "Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.1" } - - static func estimatedHeight() -> Float { - return 140 - } - + override func layoutSubviews() { super.layoutSubviews() diff --git a/TabletDemo/Classes/Presentation/Views/StoryboardTableViewCell.swift b/TabletDemo/Classes/Presentation/Views/StoryboardTableViewCell.swift index 2e4884b..1f06499 100644 --- a/TabletDemo/Classes/Presentation/Views/StoryboardTableViewCell.swift +++ b/TabletDemo/Classes/Presentation/Views/StoryboardTableViewCell.swift @@ -16,8 +16,4 @@ class StoryboardTableViewCell: UITableViewCell, ConfigurableCell { func configure(value: T) { textLabel?.text = value } - - static func estimatedHeight() -> Float { - return 44 - } } \ No newline at end of file From 6e4ea9caf69f7b18890e6c5c31f16224315f8412 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Tue, 7 Jun 2016 02:04:15 +0300 Subject: [PATCH 22/34] remove base row builder --- Tablet/Operators.swift | 4 +- Tablet/TableBaseRowBuilder.swift | 158 ------------------ Tablet/TableRowBuilder.swift | 136 ++++++++++++--- Tablet/Tablet.xcodeproj/project.pbxproj | 12 +- .../Controllers/MainController.swift | 2 - 5 files changed, 123 insertions(+), 189 deletions(-) delete mode 100644 Tablet/TableBaseRowBuilder.swift diff --git a/Tablet/Operators.swift b/Tablet/Operators.swift index fa2f029..6b5243d 100644 --- a/Tablet/Operators.swift +++ b/Tablet/Operators.swift @@ -36,11 +36,11 @@ public func +=(left: TableDirector, right: [TableSectionBuilder]) { } // - -public func +=(left: TableBaseRowBuilder, right: DataType) { +public func +=(left: TableRowBuilder, right: DataType) { left.append(items: [right]) } -public func +=(left: TableBaseRowBuilder, right: [DataType]) { +public func +=(left: TableRowBuilder, right: [DataType]) { left.append(items: right) } diff --git a/Tablet/TableBaseRowBuilder.swift b/Tablet/TableBaseRowBuilder.swift deleted file mode 100644 index 58ca529..0000000 --- a/Tablet/TableBaseRowBuilder.swift +++ /dev/null @@ -1,158 +0,0 @@ -// -// Copyright (c) 2015 Max Sokolov https://twitter.com/max_sokolov -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import UIKit - -public typealias ReturnValue = AnyObject? - -/** - Responsible for building cells of given type and passing items to them. - */ -public class TableBaseRowBuilder : RowBuilder { - - public private(set) weak var tableDirector: TableDirector? - - private var actions = [String: ActionHandler]() - private var items = [DataType]() - - - public func reusableIdentifier(_: Int) -> String { - return String(CellType) - } - - public var numberOfRows: Int { - return items.count - } - - public init(item: DataType, id: String? = nil) { - - //reusableIdentifier = id ?? String(CellType) - items.append(item) - } - - public init(items: [DataType]? = nil, id: String? = nil) { - - //reusableIdentifier = id ?? String(CellType) - - if let items = items { - self.items.appendContentsOf(items) - } - } - - // MARK: - RowHeightCalculatable - - - public func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { - return UITableViewAutomaticDimension - } - - public func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { - return 44 - } - - // MARK: - Chaining actions - - - public func addAction(action: TableRowAction) { - - } - - public func action(key: String, handler: (data: ActionData) -> Void) -> Self { - - actions[key] = .Handler(handler) - return self - } - - public func action(type: ActionType, handler: (data: ActionData) -> Void) -> Self { - - actions[type.key] = .Handler(handler) - return self - } - - public func valueAction(type: ActionType, handler: (data: ActionData) -> ReturnValue) -> Self { - - actions[type.key] = .ValueHandler(handler) - return self - } - - public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { - - if let action = actions[action.key] { - return action.invoke(ActionData(cell: cell as? CellType, indexPath: indexPath, item: items[itemIndex], itemIndex: itemIndex, userInfo: userInfo)) - } - return nil - } - - private func registerCell(inTableView tableView: UITableView) { - - if tableView.dequeueReusableCellWithIdentifier(reusableIdentifier(0)) != nil { - return - } - - let resource = String(CellType) - let bundle = NSBundle(forClass: CellType.self) - - if let _ = bundle.pathForResource(resource, ofType: "nib") { // existing cell - tableView.registerNib(UINib(nibName: resource, bundle: bundle), forCellReuseIdentifier: reusableIdentifier(0)) - } else { - tableView.registerClass(CellType.self, forCellReuseIdentifier: reusableIdentifier(0)) - } - } - - public func willUpdateDirector(director: TableDirector?) { - tableDirector = director - - - } - - // MARK: - Items manipulation - - - public func delete(indexes indexes: [Int], animated: UITableViewRowAnimation) -> Self { - - return self - } - - public func insert(items: [DataType], atIndex index: Int, animated: UITableViewRowAnimation) -> Self { - - self.items.insertContentsOf(items, at: index) - - return self - } - - public func move(indexes: [Int], toIndexes: [Int]) -> Self { - - return self - } - - public func update(index index: Int, item: DataType, animated: UITableViewRowAnimation) -> Self { - - return self - } - - public func item(index index: Int) -> DataType { - return items[index] - } - - public func append(items items: [DataType]) { - self.items.appendContentsOf(items) - } - - public func clear() { - items.removeAll() - } -} \ No newline at end of file diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index d6dbacf..0dabcfa 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -20,43 +20,141 @@ import UIKit +public typealias ReturnValue = AnyObject? + /** - Responsible for building configurable cells of given type and passing items to them. + Responsible for building cells of given type and passing items to them. */ -public class TableRowBuilder : TableBaseRowBuilder { - +public class TableRowBuilder : RowBuilder { + + public private(set) weak var tableDirector: TableDirector? private var heightStrategy: HeightStrategy? + private var actions = [String: ActionHandler]() + private var items = [DataType]() + + + public func reusableIdentifier(_: Int) -> String { + return CellType.reusableIdentifier() + } + + public var numberOfRows: Int { + return items.count + } + public init(item: DataType) { - super.init(item: item, id: CellType.reusableIdentifier()) + items.append(item) } public init(items: [DataType]? = nil) { - super.init(items: items, id: CellType.reusableIdentifier()) + + if let items = items { + self.items.appendContentsOf(items) + } + } + + // MARK: - RowHeightCalculatable - + + public func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { + return heightStrategy?.height(item(index: index), indexPath: indexPath, cell: CellType.self) ?? 0 } - public override func willUpdateDirector(director: TableDirector?) { - super.willUpdateDirector(director) + public func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { + return CellType.estimatedHeight() + } + + // MARK: - Chaining actions - + + public func addAction(action: TableRowAction) { - heightStrategy = PrototypeHeightStrategy() - heightStrategy?.tableView = director?.tableView } - public override func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { + public func action(key: String, handler: (data: ActionData) -> Void) -> Self { + + actions[key] = .Handler(handler) + return self + } + + public func action(type: ActionType, handler: (data: ActionData) -> Void) -> Self { + + actions[type.key] = .Handler(handler) + return self + } + + public func valueAction(type: ActionType, handler: (data: ActionData) -> ReturnValue) -> Self { + + actions[type.key] = .ValueHandler(handler) + return self + } + + public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { if case .configure = action { (cell as? CellType)?.configure(item(index: itemIndex)) } - return super.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: itemIndex, userInfo: userInfo) - } - - // MARK: - RowHeightCalculatable - - - public override func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { - return heightStrategy?.height(item(index: index), indexPath: indexPath, cell: CellType.self) ?? 0 + + if let action = actions[action.key] { + return action.invoke(ActionData(cell: cell as? CellType, indexPath: indexPath, item: items[itemIndex], itemIndex: itemIndex, userInfo: userInfo)) + } + return nil } - public override func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { - return CellType.estimatedHeight() + private func registerCell(inTableView tableView: UITableView) { + + if tableView.dequeueReusableCellWithIdentifier(reusableIdentifier(0)) != nil { + return + } + + let resource = String(CellType) + let bundle = NSBundle(forClass: CellType.self) + + if let _ = bundle.pathForResource(resource, ofType: "nib") { // existing cell + tableView.registerNib(UINib(nibName: resource, bundle: bundle), forCellReuseIdentifier: reusableIdentifier(0)) + } else { + tableView.registerClass(CellType.self, forCellReuseIdentifier: reusableIdentifier(0)) + } + } + + public func willUpdateDirector(director: TableDirector?) { + tableDirector = director + + heightStrategy = PrototypeHeightStrategy() + heightStrategy?.tableView = director?.tableView + } + + // MARK: - Items manipulation - + + public func delete(indexes indexes: [Int], animated: UITableViewRowAnimation) -> Self { + + return self + } + + public func insert(items: [DataType], atIndex index: Int, animated: UITableViewRowAnimation) -> Self { + + self.items.insertContentsOf(items, at: index) + + return self + } + + public func move(indexes: [Int], toIndexes: [Int]) -> Self { + + return self + } + + public func update(index index: Int, item: DataType, animated: UITableViewRowAnimation) -> Self { + + return self + } + + public func item(index index: Int) -> DataType { + return items[index] + } + + public func append(items items: [DataType]) { + self.items.appendContentsOf(items) + } + + public func clear() { + items.removeAll() } } \ No newline at end of file diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index 2c4b42b..84f6fb3 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 5058386E1CF62B0700224C58 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */; }; DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */; }; DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */; }; DA539C9F1CFB025C00368ACB /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539C9E1CFB025C00368ACB /* Operators.swift */; }; @@ -16,7 +15,7 @@ DAC2D6741C9D743D009E9C19 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC2D6691C9D743D009E9C19 /* Tablet.framework */; }; DAC2D6871C9D7517009E9C19 /* Tablet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2D6851C9D7517009E9C19 /* Tablet.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */; }; - DAC2D6911C9D799E009E9C19 /* TableBaseRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */; }; + DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */; }; DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */; }; DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68F1C9D799E009E9C19 /* Tablet.swift */; }; DAC2D6991C9D7A3F009E9C19 /* TabletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D6961C9D7A3B009E9C19 /* TabletTests.swift */; }; @@ -33,7 +32,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = ""; }; DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowBuilder.swift; sourceTree = ""; }; DA539C9E1CFB025C00368ACB /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; @@ -44,7 +42,7 @@ DAC2D6841C9D7517009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DAC2D6851C9D7517009E9C19 /* Tablet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tablet.h; sourceTree = ""; }; DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDirector.swift; sourceTree = ""; }; - DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableBaseRowBuilder.swift; sourceTree = ""; }; + DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = ""; }; DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableSectionBuilder.swift; sourceTree = ""; }; DAC2D68F1C9D799E009E9C19 /* Tablet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tablet.swift; sourceTree = ""; }; DAC2D6951C9D7A3B009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -104,8 +102,7 @@ DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */, DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */, DA9EA7341D06155E0021F650 /* HeightStrategy.swift */, - DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */, - 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */, + DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */, DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */, DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */, DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, @@ -239,8 +236,7 @@ DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */, DA539CC61D01D44500368ACB /* TableDynamicRowBuilder.swift in Sources */, DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */, - DAC2D6911C9D799E009E9C19 /* TableBaseRowBuilder.swift in Sources */, - 5058386E1CF62B0700224C58 /* TableRowBuilder.swift in Sources */, + DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */, DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */, DA539C9F1CFB025C00368ACB /* Operators.swift in Sources */, ); diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index c39d301..d8480ba 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -74,7 +74,5 @@ class MainController: UIViewController { //} tableDirector.append(section: section) - - tableDirector += rowBuilder } } \ No newline at end of file From 0c5f24a4910352f09d5042c9019010e97f8dea78 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Tue, 7 Jun 2016 02:15:37 +0300 Subject: [PATCH 23/34] fix --- Tablet/ConfigurableCell.swift | 10 +++++----- Tablet/HeightStrategy.swift | 8 +------- Tablet/TableRowBuilder.swift | 5 +++-- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/Tablet/ConfigurableCell.swift b/Tablet/ConfigurableCell.swift index 6622122..2db62b5 100644 --- a/Tablet/ConfigurableCell.swift +++ b/Tablet/ConfigurableCell.swift @@ -30,7 +30,7 @@ public protocol ConfigurableCell { static func reusableIdentifier() -> String static func estimatedHeight() -> CGFloat - static func defaultHeight() -> Float? + static func defaultHeight() -> CGFloat? func configure(_: T) } @@ -40,11 +40,11 @@ public extension ConfigurableCell where Self: UITableViewCell { return String(self) } - static func defaultHeight() -> Float? { - return nil - } - static func estimatedHeight() -> CGFloat { return UITableViewAutomaticDimension } + + static func defaultHeight() -> CGFloat? { + return nil + } } \ No newline at end of file diff --git a/Tablet/HeightStrategy.swift b/Tablet/HeightStrategy.swift index 75f9516..c34bd40 100644 --- a/Tablet/HeightStrategy.swift +++ b/Tablet/HeightStrategy.swift @@ -21,12 +21,10 @@ import UIKit public protocol HeightStrategy { - + var tableView: UITableView? { get set } func height(item: Item, indexPath: NSIndexPath, cell: Cell.Type) -> CGFloat - - func estimatedHeight() -> CGFloat } public class PrototypeHeightStrategy: HeightStrategy { @@ -47,8 +45,4 @@ public class PrototypeHeightStrategy: HeightStrategy { return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1 } - - public func estimatedHeight() -> CGFloat { - return UITableViewAutomaticDimension - } } \ No newline at end of file diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index 0dabcfa..b5f2d53 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -33,7 +33,6 @@ public class TableRowBuilder]() private var items = [DataType]() - public func reusableIdentifier(_: Int) -> String { return CellType.reusableIdentifier() } @@ -41,6 +40,8 @@ public class TableRowBuilder CGFloat { - return heightStrategy?.height(item(index: index), indexPath: indexPath, cell: CellType.self) ?? 0 + return CellType.defaultHeight() ?? heightStrategy?.height(item(index: index), indexPath: indexPath, cell: CellType.self) ?? UITableViewAutomaticDimension } public func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { From 21f131bb19df1c4189d5ffb11c8614b0cfcf56e5 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Tue, 7 Jun 2016 21:41:57 +0300 Subject: [PATCH 24/34] add RowConfigurable protocol --- Tablet/RowBuilder.swift | 7 ++- Tablet/TableDirector.swift | 4 +- Tablet/TableDynamicRowBuilder.swift | 45 ++++++++++++++++++- Tablet/TableRowBuilder.swift | 7 +++ .../Controllers/MainController.swift | 13 +++--- 5 files changed, 64 insertions(+), 12 deletions(-) diff --git a/Tablet/RowBuilder.swift b/Tablet/RowBuilder.swift index d10b3cf..773d8d1 100644 --- a/Tablet/RowBuilder.swift +++ b/Tablet/RowBuilder.swift @@ -26,7 +26,12 @@ public protocol RowHeightCalculatable { func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat } -public protocol RowBuilder: RowHeightCalculatable { +public protocol RowConfigurable { + + func configure(cell: UITableViewCell, path: NSIndexPath, index: Int) +} + +public protocol RowBuilder: RowConfigurable, RowHeightCalculatable { var tableDirector: TableDirector? { get } diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 72d3a9f..5d0a028 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -119,8 +119,8 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate cell.layoutIfNeeded() } - builder.0.invoke(action: .configure, cell: cell, indexPath: indexPath, itemIndex: builder.1, userInfo: nil) - + builder.0.configure(cell, path: indexPath, index: builder.1) + return cell } diff --git a/Tablet/TableDynamicRowBuilder.swift b/Tablet/TableDynamicRowBuilder.swift index 25c6455..5e2a0a4 100644 --- a/Tablet/TableDynamicRowBuilder.swift +++ b/Tablet/TableDynamicRowBuilder.swift @@ -22,12 +22,18 @@ import UIKit public protocol RowItemable { + var reusableIdentifier: String { get } + func configure(cell: UITableViewCell) } public class RowItem: RowItemable { public let item: DataType + + public var reusableIdentifier: String { + return CellType.reusableIdentifier() + } public init(item: DataType) { self.item = item @@ -38,7 +44,7 @@ public class RowItem String { + return items[index].reusableIdentifier + } + + public func willUpdateDirector(director: TableDirector?) { + + } + + public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject : AnyObject]?) -> AnyObject? { + + return nil + } + + // MARK: - RowHeightCalculatable - + + public func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { + return UITableViewAutomaticDimension + } + + public func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { + return 0 //CellType.estimatedHeight() + } } \ No newline at end of file diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index b5f2d53..752e238 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -64,6 +64,13 @@ public class TableRowBuilder) { diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index d8480ba..89d29cb 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -26,17 +26,15 @@ class MainController: UIViewController { self.performSegueWithIdentifier("headerfooter", sender: nil) } + let section = TableSectionBuilder(headerTitle: "", footerTitle: "", rows: [rowBuilder]) - /*let rows2 = TableRowBuilder(items: ["1", "1", "1", "1"]) - - let cellItem = RowItem(item: "1") + let cellItem = RowItem(item: "1") let cellItem2 = RowItem(item: "1") - let cellItem3 = RowItem(item: "1") @@ -45,7 +43,7 @@ class MainController: UIViewController { let b = TableDynamicRowBuilder(items: [cellItem, cellItem2, cellItem3]) - rowBuilder + /*rowBuilder .addAction(TableRowAction(type: .Click) { (data) in @@ -55,8 +53,7 @@ class MainController: UIViewController { .delete(indexes: [0], animated: .None) .insert(["2"], atIndex: 0, animated: .None) .update(index: 0, item: "", animated: .None) - .move([1, 2], toIndexes: [3, 4])*/ - + .move([1, 2], toIndexes: [3, 4]) @@ -71,7 +68,7 @@ class MainController: UIViewController { //tableView.insertSections([], withRowAnimation: .None) //tableDirector.performBatchUpdates { - //} + //}*/ tableDirector.append(section: section) } From c27a386807686209c7fa55971c0bb1d532379beb Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Tue, 7 Jun 2016 23:40:46 +0300 Subject: [PATCH 25/34] rowitem improvements --- Tablet/TableDynamicRowBuilder.swift | 29 ++++++++++--------- .../Controllers/MainController.swift | 29 ++++++++++++++++--- .../Views/StoryboardImageTableViewCell.swift | 2 +- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/Tablet/TableDynamicRowBuilder.swift b/Tablet/TableDynamicRowBuilder.swift index 5e2a0a4..63b9daa 100644 --- a/Tablet/TableDynamicRowBuilder.swift +++ b/Tablet/TableDynamicRowBuilder.swift @@ -23,6 +23,7 @@ import UIKit public protocol RowItemable { var reusableIdentifier: String { get } + var estimatedHeight: CGFloat { get } func configure(cell: UITableViewCell) } @@ -35,6 +36,10 @@ public class RowItem Void) -> Self { + + return self + } + // MARK: - RowHeightCalculatable - public func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { @@ -94,6 +95,6 @@ public class TableDynamicRowBuilder: RowBuilder { } public func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { - return 0 //CellType.estimatedHeight() + return items[index].estimatedHeight } } \ No newline at end of file diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 89d29cb..0a4da70 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -22,7 +22,8 @@ class MainController: UIViewController { super.viewDidLoad() let rowBuilder = TableRowBuilder(items: ["1", "1", "1", "1"]) - .action(.click) { [unowned self] e in + .action(.click) { [unowned self] data in + self.performSegueWithIdentifier("headerfooter", sender: nil) } @@ -34,13 +35,33 @@ class MainController: UIViewController { let cellItem = RowItem(item: "1") - let cellItem2 = RowItem(item: "1") - let cellItem3 = RowItem(item: "1") + let cellItem2 = RowItem(item: "2") + let cellItem3 = RowItem(item: "3") let b = TableDynamicRowBuilder(items: [cellItem, cellItem2, cellItem3]) + .action { (item, path) in + + if let x = item as? RowItem { + + } + } + .action { (item, path) in + + + } + + + + tableDirector += b + + + + + + /*rowBuilder @@ -70,6 +91,6 @@ class MainController: UIViewController { //tableDirector.performBatchUpdates { //}*/ - tableDirector.append(section: section) + //tableDirector.append(section: section) } } \ No newline at end of file diff --git a/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift b/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift index b161b36..45bf5b6 100644 --- a/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift +++ b/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift @@ -19,7 +19,7 @@ class StoryboardImageTableViewCell: UITableViewCell, ConfigurableCell { func configure(string: T) { - titleLabel.text = "Test" + titleLabel.text = string subtitleLabel.text = "Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.Copyright © 2016 Tablet. All rights reserved.1" } From 44c1a861d89a3a9dcc0025b509b7cf0c11f57dd2 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Wed, 8 Jun 2016 02:08:43 +0300 Subject: [PATCH 26/34] fix row item generic --- Tablet/TableDynamicRowBuilder.swift | 2 +- .../Classes/Presentation/Controllers/MainController.swift | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Tablet/TableDynamicRowBuilder.swift b/Tablet/TableDynamicRowBuilder.swift index 63b9daa..4f1e238 100644 --- a/Tablet/TableDynamicRowBuilder.swift +++ b/Tablet/TableDynamicRowBuilder.swift @@ -28,7 +28,7 @@ public protocol RowItemable { func configure(cell: UITableViewCell) } -public class RowItem: RowItemable { +public class RowItem: RowItemable { public let item: DataType diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 0a4da70..6b23bfa 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -39,6 +39,7 @@ class MainController: UIViewController { let cellItem3 = RowItem(item: "3") + let b = TableDynamicRowBuilder(items: [cellItem, cellItem2, cellItem3]) From 234e0efc85e6b1ea39dbff585553f5bfbee4e0b3 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Thu, 9 Jun 2016 01:20:52 +0300 Subject: [PATCH 27/34] rethink point --- Tablet/ConfigurableCell.swift | 4 - Tablet/Operators.swift | 4 +- Tablet/TableDirector.swift | 43 +++----- Tablet/TableDynamicRowBuilder.swift | 100 ------------------ Tablet/{RowBuilder.swift => TableRow.swift} | 37 ++++--- Tablet/TableRowBuilder.swift | 4 +- ...ectionBuilder.swift => TableSection.swift} | 44 +++----- Tablet/Tablet.xcodeproj/project.pbxproj | 22 ++-- .../Controllers/HeaderFooterController.swift | 10 +- .../Controllers/MainController.swift | 34 ++---- 10 files changed, 80 insertions(+), 222 deletions(-) delete mode 100644 Tablet/TableDynamicRowBuilder.swift rename Tablet/{RowBuilder.swift => TableRow.swift} (63%) rename Tablet/{TableSectionBuilder.swift => TableSection.swift} (67%) diff --git a/Tablet/ConfigurableCell.swift b/Tablet/ConfigurableCell.swift index 2db62b5..d3363b4 100644 --- a/Tablet/ConfigurableCell.swift +++ b/Tablet/ConfigurableCell.swift @@ -20,10 +20,6 @@ import UIKit -/** - If you want to delegate your cell configuration logic to cell itself (with your view model or even model) than - just provide an implementation of this protocol for your cell. Enjoy safe-typisation. - */ public protocol ConfigurableCell { associatedtype T diff --git a/Tablet/Operators.swift b/Tablet/Operators.swift index 6b5243d..9dfb675 100644 --- a/Tablet/Operators.swift +++ b/Tablet/Operators.swift @@ -19,7 +19,7 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // - -public func +=(left: TableDirector, right: RowBuilder) { +/*public func +=(left: TableDirector, right: RowBuilder) { left.append(section: TableSectionBuilder(rows: [right])) } @@ -51,4 +51,4 @@ public func +=(left: TableSectionBuilder, right: RowBuilder) { public func +=(left: TableSectionBuilder, right: [RowBuilder]) { left.append(rows: right) -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 5d0a028..101d3dc 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -27,7 +27,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate public private(set) weak var tableView: UITableView? private weak var scrollDelegate: UIScrollViewDelegate? - private var sections = [TableSectionBuilder]() + public private(set) var sections = [TableSection]() public init(tableView: UITableView, scrollDelegate: UIScrollViewDelegate? = nil) { super.init() @@ -47,24 +47,12 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate public func reload() { tableView?.reloadData() } - - public func performBatchUpdates(handler: () -> Void) { - - - } - // MARK: Private methods - - private func builderAtIndexPath(indexPath: NSIndexPath) -> (RowBuilder, Int) { - return sections[indexPath.section].builderAtIndex(indexPath.row)! - } - // MARK: Public public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath) -> AnyObject? { - let builder = builderAtIndexPath(indexPath) - return builder.0.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: builder.1, userInfo: nil) + return nil } public override func respondsToSelector(selector: Selector) -> Bool { @@ -81,21 +69,20 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate if let action = notification.object as? Action, indexPath = tableView?.indexPathForCell(action.cell) { - let builder = builderAtIndexPath(indexPath) - builder.0.invoke(action: .custom(action.key), cell: action.cell, indexPath: indexPath, itemIndex: builder.1, userInfo: notification.userInfo) + //let builder = builderAtIndexPath(indexPath) + //builder.0.invoke(action: .custom(action.key), cell: action.cell, indexPath: indexPath, itemIndex: builder.1, userInfo: notification.userInfo) } } // MARK: - Height public func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - let builder = builderAtIndexPath(indexPath) - return builder.0.estimatedRowHeight(builder.1, indexPath: indexPath) + return sections[indexPath.section].items[indexPath.row].estimatedHeight } public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - let builder = builderAtIndexPath(indexPath) - return builder.0.rowHeight(builder.1, indexPath: indexPath) + + return UITableViewAutomaticDimension } // MARK: UITableViewDataSource - configuration @@ -109,17 +96,17 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate } public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - - let builder = builderAtIndexPath(indexPath) - - let cell = tableView.dequeueReusableCellWithIdentifier(builder.0.reusableIdentifier(builder.1), forIndexPath: indexPath) + + let row = sections[indexPath.section].items[indexPath.row] + + let cell = tableView.dequeueReusableCellWithIdentifier(row.reusableIdentifier, forIndexPath: indexPath) if cell.frame.size.width != tableView.frame.size.width { cell.frame = CGRectMake(0, 0, tableView.frame.size.width, cell.frame.size.height) cell.layoutIfNeeded() } - - builder.0.configure(cell, path: indexPath, index: builder.1) + + row.configure(cell) return cell } @@ -184,11 +171,11 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate // MARK: - Sections manipulation - - public func append(section section: TableSectionBuilder) { + public func append(section section: TableSection) { append(sections: [section]) } - public func append(sections sections: [TableSectionBuilder]) { + public func append(sections sections: [TableSection]) { sections.forEach { $0.tableDirector = self } self.sections.appendContentsOf(sections) diff --git a/Tablet/TableDynamicRowBuilder.swift b/Tablet/TableDynamicRowBuilder.swift deleted file mode 100644 index 4f1e238..0000000 --- a/Tablet/TableDynamicRowBuilder.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// Copyright (c) 2015 Max Sokolov https://twitter.com/max_sokolov -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import UIKit - -public protocol RowItemable { - - var reusableIdentifier: String { get } - var estimatedHeight: CGFloat { get } - - func configure(cell: UITableViewCell) -} - -public class RowItem: RowItemable { - - public let item: DataType - - public var reusableIdentifier: String { - return CellType.reusableIdentifier() - } - - public var estimatedHeight: CGFloat { - return CellType.estimatedHeight() - } - - public init(item: DataType) { - self.item = item - } - - public func configure(cell: UITableViewCell) { - (cell as? CellType)?.configure(item) - } -} - -public class TableDynamicRowBuilder: RowBuilder { - - public private(set) weak var tableDirector: TableDirector? - private var items = [RowItemable]() - - public init(items: [RowItemable]) { - self.items = items - } - - // MARK: - RowConfigurable - - - public func configure(cell: UITableViewCell, path: NSIndexPath, index: Int) { - items[index].configure(cell) - } - - // MARK: - RowBuilder - - - public var numberOfRows: Int { - return items.count - } - - public func reusableIdentifier(index: Int) -> String { - return items[index].reusableIdentifier - } - - public func willUpdateDirector(director: TableDirector?) { - - } - - public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject : AnyObject]?) -> AnyObject? { - - return nil - } - - public func action(handler: (item: RowItemable, path: NSIndexPath) -> Void) -> Self { - - return self - } - - // MARK: - RowHeightCalculatable - - - public func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { - return UITableViewAutomaticDimension - } - - public func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat { - return items[index].estimatedHeight - } -} \ No newline at end of file diff --git a/Tablet/RowBuilder.swift b/Tablet/TableRow.swift similarity index 63% rename from Tablet/RowBuilder.swift rename to Tablet/TableRow.swift index 773d8d1..7f48b76 100644 --- a/Tablet/RowBuilder.swift +++ b/Tablet/TableRow.swift @@ -20,26 +20,31 @@ import UIKit -public protocol RowHeightCalculatable { - - func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat - func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat +public protocol Row { + + var reusableIdentifier: String { get } + var estimatedHeight: CGFloat { get } + + func configure(cell: UITableViewCell) } -public protocol RowConfigurable { +public class TableRow: Row { + + public let item: ItemType - func configure(cell: UITableViewCell, path: NSIndexPath, index: Int) -} - -public protocol RowBuilder: RowConfigurable, RowHeightCalculatable { + public var reusableIdentifier: String { + return CellType.reusableIdentifier() + } - var tableDirector: TableDirector? { get } - - var numberOfRows: Int { get } + public var estimatedHeight: CGFloat { + return CellType.estimatedHeight() + } - func willUpdateDirector(director: TableDirector?) + public init(item: ItemType) { + self.item = item + } - func reusableIdentifier(index: Int) -> String - - func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? + public func configure(cell: UITableViewCell) { + (cell as? CellType)?.configure(item) + } } \ No newline at end of file diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index 752e238..be7777a 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -25,7 +25,7 @@ public typealias ReturnValue = AnyObject? /** Responsible for building cells of given type and passing items to them. */ -public class TableRowBuilder : RowBuilder { +/*public class TableRowBuilder : RowBuilder { public private(set) weak var tableDirector: TableDirector? private var heightStrategy: HeightStrategy? @@ -165,4 +165,4 @@ public class TableRowBuilder (RowBuilder, Int)? { - - var builderIndex = index - for builder in builders { - if builderIndex < builder.numberOfRows { - return (builder, builderIndex) - } - builderIndex -= builder.numberOfRows - } - - return nil + //if let director = tableDirector { rows.forEach { $0.willUpdateDirector(director) } } + //builders.appendContentsOf(rows) } } \ No newline at end of file diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index 84f6fb3..1a824df 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -8,15 +8,14 @@ /* Begin PBXBuildFile section */ DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */; }; - DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */; }; DA539C9F1CFB025C00368ACB /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539C9E1CFB025C00368ACB /* Operators.swift */; }; - DA539CC61D01D44500368ACB /* TableDynamicRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */; }; + DA539CC61D01D44500368ACB /* TableRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539CC51D01D44500368ACB /* TableRow.swift */; }; DA9EA7351D06155E0021F650 /* HeightStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7341D06155E0021F650 /* HeightStrategy.swift */; }; DAC2D6741C9D743D009E9C19 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC2D6691C9D743D009E9C19 /* Tablet.framework */; }; DAC2D6871C9D7517009E9C19 /* Tablet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2D6851C9D7517009E9C19 /* Tablet.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */; }; DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */; }; - DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */; }; + DAC2D6921C9D799E009E9C19 /* TableSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68E1C9D799E009E9C19 /* TableSection.swift */; }; DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68F1C9D799E009E9C19 /* Tablet.swift */; }; DAC2D6991C9D7A3F009E9C19 /* TabletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D6961C9D7A3B009E9C19 /* TabletTests.swift */; }; /* End PBXBuildFile section */ @@ -33,9 +32,8 @@ /* Begin PBXFileReference section */ DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; - DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowBuilder.swift; sourceTree = ""; }; DA539C9E1CFB025C00368ACB /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; - DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDynamicRowBuilder.swift; sourceTree = ""; }; + DA539CC51D01D44500368ACB /* TableRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRow.swift; sourceTree = ""; }; DA9EA7341D06155E0021F650 /* HeightStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeightStrategy.swift; sourceTree = ""; }; DAC2D6691C9D743D009E9C19 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Tablet.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6731C9D743D009E9C19 /* TabletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TabletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -43,7 +41,7 @@ DAC2D6851C9D7517009E9C19 /* Tablet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tablet.h; sourceTree = ""; }; DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDirector.swift; sourceTree = ""; }; DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = ""; }; - DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableSectionBuilder.swift; sourceTree = ""; }; + DAC2D68E1C9D799E009E9C19 /* TableSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableSection.swift; sourceTree = ""; }; DAC2D68F1C9D799E009E9C19 /* Tablet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tablet.swift; sourceTree = ""; }; DAC2D6951C9D7A3B009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DAC2D6961C9D7A3B009E9C19 /* TabletTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabletTests.swift; sourceTree = ""; }; @@ -100,11 +98,10 @@ isa = PBXGroup; children = ( DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */, - DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */, - DA9EA7341D06155E0021F650 /* HeightStrategy.swift */, + DA539CC51D01D44500368ACB /* TableRow.swift */, + DAC2D68E1C9D799E009E9C19 /* TableSection.swift */, DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */, - DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */, - DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */, + DA9EA7341D06155E0021F650 /* HeightStrategy.swift */, DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, DAC2D68F1C9D799E009E9C19 /* Tablet.swift */, DA539C9E1CFB025C00368ACB /* Operators.swift */, @@ -231,10 +228,9 @@ buildActionMask = 2147483647; files = ( DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */, - DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */, + DAC2D6921C9D799E009E9C19 /* TableSection.swift in Sources */, DA9EA7351D06155E0021F650 /* HeightStrategy.swift in Sources */, - DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */, - DA539CC61D01D44500368ACB /* TableDynamicRowBuilder.swift in Sources */, + DA539CC61D01D44500368ACB /* TableRow.swift in Sources */, DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */, DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */, DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */, diff --git a/TabletDemo/Classes/Presentation/Controllers/HeaderFooterController.swift b/TabletDemo/Classes/Presentation/Controllers/HeaderFooterController.swift index 1e1a7c7..47c030d 100644 --- a/TabletDemo/Classes/Presentation/Controllers/HeaderFooterController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/HeaderFooterController.swift @@ -21,13 +21,13 @@ class HeaderFooterController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - let rows = TableRowBuilder(items: ["3", "4", "5"]) + //let rows = TableRowBuilder(items: ["3", "4", "5"]) - let headerView = UIView(frame: CGRectMake(0, 0, 100, 100)) - headerView.backgroundColor = UIColor.lightGrayColor() + //let headerView = UIView(frame: CGRectMake(0, 0, 100, 100)) + //headerView.backgroundColor = UIColor.lightGrayColor() - let section = TableSectionBuilder(headerView: headerView, footerView: nil, rows: [rows]) + //let section = TableSectionBuilder(headerView: headerView, footerView: nil, rows: [rows]) - tableDirector += section + //tableDirector += section } } \ No newline at end of file diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 6b23bfa..7d6b396 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -21,44 +21,32 @@ class MainController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - let rowBuilder = TableRowBuilder(items: ["1", "1", "1", "1"]) + /*let rowBuilder = TableRowBuilder(items: ["1", "1", "1", "1"]) .action(.click) { [unowned self] data in self.performSegueWithIdentifier("headerfooter", sender: nil) - } - - - let section = TableSectionBuilder(headerTitle: "", footerTitle: "", rows: [rowBuilder]) + }*/ - let cellItem = RowItem(item: "1") - let cellItem2 = RowItem(item: "2") - let cellItem3 = RowItem(item: "3") - + + + let row1 = TableRow(item: "1") + let row2 = TableRow(item: "2") + let row3 = TableRow(item: "3") - let b = TableDynamicRowBuilder(items: [cellItem, cellItem2, cellItem3]) - .action { (item, path) in - - if let x = item as? RowItem { - - } - } - .action { (item, path) in - - - } + + + let section = TableSection(headerTitle: "", footerTitle: "", rows: [row1, row2, row3]) - tableDirector += b - - + tableDirector.append(section: section) From 01dc5dfd2118948fa0c0b421fd22078f1158c7cd Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Thu, 9 Jun 2016 01:36:50 +0300 Subject: [PATCH 28/34] table row improvements --- Tablet/TableDirector.swift | 6 ++---- Tablet/TableRow.swift | 5 +++++ Tablet/TableSection.swift | 10 ++-------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 101d3dc..1679148 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -81,8 +81,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate } public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { - - return UITableViewAutomaticDimension + return sections[indexPath.section].items[indexPath.row].defaultHeight } // MARK: UITableViewDataSource - configuration @@ -92,13 +91,12 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate } public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return sections[section].numberOfRowsInSection + return sections[section].numberOfRows } public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let row = sections[indexPath.section].items[indexPath.row] - let cell = tableView.dequeueReusableCellWithIdentifier(row.reusableIdentifier, forIndexPath: indexPath) if cell.frame.size.width != tableView.frame.size.width { diff --git a/Tablet/TableRow.swift b/Tablet/TableRow.swift index 7f48b76..1c59fe4 100644 --- a/Tablet/TableRow.swift +++ b/Tablet/TableRow.swift @@ -24,6 +24,7 @@ public protocol Row { var reusableIdentifier: String { get } var estimatedHeight: CGFloat { get } + var defaultHeight: CGFloat { get } func configure(cell: UITableViewCell) } @@ -39,6 +40,10 @@ public class TableRow Date: Thu, 9 Jun 2016 02:27:25 +0300 Subject: [PATCH 29/34] add row action --- Tablet/TableRow.swift | 12 +++++- Tablet/TableRowAction.swift | 41 +++++++++++++++++++ Tablet/Tablet.swift | 15 ------- Tablet/Tablet.xcodeproj/project.pbxproj | 4 ++ .../Controllers/MainController.swift | 13 ++++-- 5 files changed, 65 insertions(+), 20 deletions(-) create mode 100644 Tablet/TableRowAction.swift diff --git a/Tablet/TableRow.swift b/Tablet/TableRow.swift index 1c59fe4..4c5c0d4 100644 --- a/Tablet/TableRow.swift +++ b/Tablet/TableRow.swift @@ -30,8 +30,9 @@ public protocol Row { } public class TableRow: Row { - + public let item: ItemType + private var actions = [RowAction]() public var reusableIdentifier: String { return CellType.reusableIdentifier() @@ -45,11 +46,18 @@ public class TableRow]? = nil) { self.item = item } public func configure(cell: UITableViewCell) { (cell as? CellType)?.configure(item) } + + // MARK: - actions - + + public func addAction(action: TableRowAction) { + + + } } \ No newline at end of file diff --git a/Tablet/TableRowAction.swift b/Tablet/TableRowAction.swift new file mode 100644 index 0000000..05740e6 --- /dev/null +++ b/Tablet/TableRowAction.swift @@ -0,0 +1,41 @@ +// +// Copyright (c) 2015 Max Sokolov https://twitter.com/max_sokolov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import UIKit + +public enum TableActionType { + + case Click + case Custom(String) +} + +protocol RowAction { + +} + +public class TableRowAction: RowAction { + + public init(_ action: TableActionType, handler: (row: TableRow) -> Void) { + + + + + } +} \ No newline at end of file diff --git a/Tablet/Tablet.swift b/Tablet/Tablet.swift index ad2034b..bf5e653 100644 --- a/Tablet/Tablet.swift +++ b/Tablet/Tablet.swift @@ -24,21 +24,6 @@ struct TabletNotifications { static let CellAction = "TabletNotificationsCellAction" } -public enum TableActionType { - - case Click - case Custom(String) -} - -public class TableRowAction { - - let type: TableActionType - - public init(type: TableActionType, handler: (data: ActionData) -> Void) { - self.type = type - } -} - /** The actions that Tablet provides. */ diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index 1a824df..f562bbc 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ DA539C9F1CFB025C00368ACB /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539C9E1CFB025C00368ACB /* Operators.swift */; }; DA539CC61D01D44500368ACB /* TableRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539CC51D01D44500368ACB /* TableRow.swift */; }; DA9EA7351D06155E0021F650 /* HeightStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7341D06155E0021F650 /* HeightStrategy.swift */; }; + DA9EA73E1D08D6AA0021F650 /* TableRowAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA73D1D08D6AA0021F650 /* TableRowAction.swift */; }; DAC2D6741C9D743D009E9C19 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC2D6691C9D743D009E9C19 /* Tablet.framework */; }; DAC2D6871C9D7517009E9C19 /* Tablet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2D6851C9D7517009E9C19 /* Tablet.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */; }; @@ -35,6 +36,7 @@ DA539C9E1CFB025C00368ACB /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; DA539CC51D01D44500368ACB /* TableRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRow.swift; sourceTree = ""; }; DA9EA7341D06155E0021F650 /* HeightStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeightStrategy.swift; sourceTree = ""; }; + DA9EA73D1D08D6AA0021F650 /* TableRowAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowAction.swift; sourceTree = ""; }; DAC2D6691C9D743D009E9C19 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Tablet.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6731C9D743D009E9C19 /* TabletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TabletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D6841C9D7517009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -99,6 +101,7 @@ children = ( DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */, DA539CC51D01D44500368ACB /* TableRow.swift */, + DA9EA73D1D08D6AA0021F650 /* TableRowAction.swift */, DAC2D68E1C9D799E009E9C19 /* TableSection.swift */, DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */, DA9EA7341D06155E0021F650 /* HeightStrategy.swift */, @@ -230,6 +233,7 @@ DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */, DAC2D6921C9D799E009E9C19 /* TableSection.swift in Sources */, DA9EA7351D06155E0021F650 /* HeightStrategy.swift in Sources */, + DA9EA73E1D08D6AA0021F650 /* TableRowAction.swift in Sources */, DA539CC61D01D44500368ACB /* TableRow.swift in Sources */, DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */, DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */, diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 7d6b396..905c33f 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -30,15 +30,22 @@ class MainController: UIViewController { - + let a = TableRowAction(.Click) { + (row) in + + } let row1 = TableRow(item: "1") let row2 = TableRow(item: "2") - let row3 = TableRow(item: "3") + let row3 = TableRow(item: "3", actions: [a]) - + row1 + + .addAction(TableRowAction(.Click) { (row) in + + }) From 708f164c96f73571d72736a5a0cd1b5b5773c9e1 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Thu, 9 Jun 2016 19:34:28 +0300 Subject: [PATCH 30/34] value actions --- .../UserInterfaceState.xcuserstate | Bin 20594 -> 21675 bytes Tablet/TableRow.swift | 29 ++++++++++++++---- Tablet/TableRowAction.swift | 13 ++++---- .../Controllers/MainController.swift | 11 +++++-- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate b/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate index e78d368dbe66dfbbe53fc8b751489cae939ada4d..b905fecdb7205bfdb2d2572bb0247f4217646129 100644 GIT binary patch literal 21675 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 K-SC+k^nU>NfjFE1 diff --git a/Tablet/TableRow.swift b/Tablet/TableRow.swift index 4c5c0d4..86338d4 100644 --- a/Tablet/TableRow.swift +++ b/Tablet/TableRow.swift @@ -20,13 +20,21 @@ import UIKit -public protocol Row { - +public protocol RowConfigurable { + + func configure(cell: UITableViewCell) +} + +public protocol RowActionable { + + func invoke(action: TableRowActionType, cell: UITableViewCell?, path: NSIndexPath) -> Any? +} + +public protocol Row: RowConfigurable, RowActionable { + var reusableIdentifier: String { get } var estimatedHeight: CGFloat { get } var defaultHeight: CGFloat { get } - - func configure(cell: UITableViewCell) } public class TableRow: Row { @@ -50,14 +58,23 @@ public class TableRow Any? { + + return nil + } + // MARK: - actions - - public func addAction(action: TableRowAction) { - + public func action(action: TableRowAction) -> Self { + return self } } \ No newline at end of file diff --git a/Tablet/TableRowAction.swift b/Tablet/TableRowAction.swift index 05740e6..00cfd18 100644 --- a/Tablet/TableRowAction.swift +++ b/Tablet/TableRowAction.swift @@ -20,7 +20,7 @@ import UIKit -public enum TableActionType { +public enum TableRowActionType { case Click case Custom(String) @@ -32,10 +32,11 @@ protocol RowAction { public class TableRowAction: RowAction { - public init(_ action: TableActionType, handler: (row: TableRow) -> Void) { - - - - + public init(_ action: ActionType, handler: (row: TableRow) -> Void) { + + } + + public init(_ action: ActionType, handler: (row: TableRow) -> T) { + } } \ No newline at end of file diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index 905c33f..b055272 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -30,7 +30,7 @@ class MainController: UIViewController { - let a = TableRowAction(.Click) { + let a = TableRowAction(.click) { (row) in } @@ -41,10 +41,15 @@ class MainController: UIViewController { let row2 = TableRow(item: "2") let row3 = TableRow(item: "3", actions: [a]) + row1 + .action(TableRowAction(.click) { (row) in - .addAction(TableRowAction(.Click) { (row) in - + + }) + .action(TableRowAction(.click) { (row) -> String in + + return "" }) From 96b2a19f1d5e12b11d2f9691058b6c201d6f7e47 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Fri, 10 Jun 2016 00:32:00 +0300 Subject: [PATCH 31/34] store actions --- Tablet/TableDirector.swift | 5 +-- Tablet/TableRow.swift | 13 ++++-- Tablet/TableRowAction.swift | 38 ++++++++++++++--- Tablet/Tablet.swift | 41 ------------------- .../Controllers/MainController.swift | 6 ++- 5 files changed, 48 insertions(+), 55 deletions(-) diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift index 1679148..e77a671 100644 --- a/Tablet/TableDirector.swift +++ b/Tablet/TableDirector.swift @@ -50,9 +50,8 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate // MARK: Public - public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath) -> AnyObject? { - - return nil + public func invoke(action action: TableRowActionType, cell: UITableViewCell?, indexPath: NSIndexPath) -> Any? { + return sections[indexPath.section].items[indexPath.row].invoke(action, cell: cell, path: indexPath) } public override func respondsToSelector(selector: Selector) -> Bool { diff --git a/Tablet/TableRow.swift b/Tablet/TableRow.swift index 86338d4..620342a 100644 --- a/Tablet/TableRow.swift +++ b/Tablet/TableRow.swift @@ -28,6 +28,7 @@ public protocol RowConfigurable { public protocol RowActionable { func invoke(action: TableRowActionType, cell: UITableViewCell?, path: NSIndexPath) -> Any? + func hasAction(action: TableRowActionType) -> Bool } public protocol Row: RowConfigurable, RowActionable { @@ -40,7 +41,7 @@ public protocol Row: RowConfigurable, RowActionable { public class TableRow: Row { public let item: ItemType - private var actions = [RowAction]() + private var actions = [String: RowAction]() public var reusableIdentifier: String { return CellType.reusableIdentifier() @@ -67,14 +68,18 @@ public class TableRow Any? { - - return nil + return actions[action.key]?.invoke() + } + + public func hasAction(action: TableRowActionType) -> Bool { + return actions[action.key] != nil } // MARK: - actions - public func action(action: TableRowAction) -> Self { - + + actions[action.type.key] = action return self } } \ No newline at end of file diff --git a/Tablet/TableRowAction.swift b/Tablet/TableRowAction.swift index 00cfd18..9c73c79 100644 --- a/Tablet/TableRowAction.swift +++ b/Tablet/TableRowAction.swift @@ -22,21 +22,47 @@ import UIKit public enum TableRowActionType { - case Click - case Custom(String) + case click + case select + case deselect + case willSelect + case configure + case willDisplay + case shouldHighlight + case height + case custom(String) + + var key: String { + + switch (self) { + case .custom(let key): + return key + default: + return "_\(self)" + } + } } protocol RowAction { - + + func invoke() -> Any? } public class TableRowAction: RowAction { - public init(_ action: ActionType, handler: (row: TableRow) -> Void) { + public let type: TableRowActionType + public init(_ type: TableRowActionType, handler: (row: TableRow) -> Void) { + self.type = type } - public init(_ action: ActionType, handler: (row: TableRow) -> T) { - + public init(_ type: TableRowActionType, handler: (row: TableRow) -> T) { + self.type = type + } + + // MARK: - RowAction - + + func invoke() -> Any? { + return nil } } \ No newline at end of file diff --git a/Tablet/Tablet.swift b/Tablet/Tablet.swift index bf5e653..fb22bde 100644 --- a/Tablet/Tablet.swift +++ b/Tablet/Tablet.swift @@ -24,31 +24,6 @@ struct TabletNotifications { static let CellAction = "TabletNotificationsCellAction" } -/** - The actions that Tablet provides. -*/ -public enum ActionType { - - case click - case select - case deselect - case willSelect - case configure - case willDisplay - case shouldHighlight - case height - case custom(String) - - var key: String { - - switch (self) { - case .custom(let key): - return key - default: - return "_\(self)" - } - } -} public class ActionData { @@ -68,22 +43,6 @@ public class ActionData { } } -enum ActionHandler { - - case Handler((data: ActionData) -> Void) - case ValueHandler((data: ActionData) -> AnyObject?) - - func invoke(data: ActionData) -> ReturnValue { - - switch (self) { - case .Handler(let handler): - handler(data: data) - return nil - case .ValueHandler(let handler): - return handler(data: data) - } - } -} /** A custom action that you can trigger from your cell. diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TabletDemo/Classes/Presentation/Controllers/MainController.swift index b055272..0a803a5 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TabletDemo/Classes/Presentation/Controllers/MainController.swift @@ -33,6 +33,7 @@ class MainController: UIViewController { let a = TableRowAction(.click) { (row) in + print("3") } @@ -42,13 +43,16 @@ class MainController: UIViewController { let row3 = TableRow(item: "3", actions: [a]) + row1 .action(TableRowAction(.click) { (row) in - + print("1") }) .action(TableRowAction(.click) { (row) -> String in + print("2") + return "" }) From 51de86c81a4fc5d5a57685dfd93d59a45d46eee6 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Sat, 11 Jun 2016 00:51:10 +0300 Subject: [PATCH 32/34] rename to TableKit Thanks a lot to my greatest friend, Alexander Nikishin --- .travis.yml | 2 +- README.md | 179 +------ Tablet.podspec => TableKit.podspec | 14 +- .../contents.xcworkspacedata | 4 +- {Tablet => TableKit}/ConfigurableCell.swift | 0 {Tablet => TableKit}/HeightStrategy.swift | 0 {Tablet => TableKit}/Info.plist | 0 {Tablet => TableKit}/Operators.swift | 0 {Tablet => TableKit}/TableDirector.swift | 0 TableKit/TableKit.h | 19 + TableKit/TableKit.xcodeproj/project.pbxproj | 335 +++++++++++++ {Tablet => TableKit}/TableRow.swift | 0 {Tablet => TableKit}/TableRowAction.swift | 0 {Tablet => TableKit}/TableRowBuilder.swift | 0 {Tablet => TableKit}/TableSection.swift | 0 {Tablet => TableKit}/Tablet.swift | 0 .../Classes/Application/AppDelegate.swift | 0 .../Controllers/HeaderFooterController.swift | 2 +- .../Controllers/MainController.swift | 2 +- .../Views/StoryboardImageTableViewCell.swift | 2 +- .../Views/StoryboardTableViewCell.swift | 2 +- .../AppIcon.appiconset/Contents.json | 0 .../Resources/Info.plist | 0 .../Storyboards/LaunchScreen.storyboard | 0 .../Resources/Storyboards/Main.storyboard | 0 .../TableKitDemo.xcodeproj/project.pbxproj | 362 ++++++++++++++ .../contents.xcworkspacedata | 0 .../UserInterfaceState.xcuserstate | Bin 21675 -> 0 bytes Tablet/Tablet.h | 24 - Tablet/Tablet.xcodeproj/project.pbxproj | 443 ------------------ .../UserInterfaceState.xcuserstate | Bin 19773 -> 0 bytes .../xcshareddata/xcschemes/Tablet.xcscheme | 99 ---- .../xcschemes/xcschememanagement.plist | 19 - .../xcdebugger/Breakpoints_v2.xcbkptlist | 5 - .../xcschemes/xcschememanagement.plist | 27 -- .../project.pbxproj | 6 +- .../contents.xcworkspacedata | 2 +- .../UserInterfaceState.xcuserstate | Bin 17117 -> 0 bytes .../UserInterfaceState.xcuserstate | Bin 35030 -> 0 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 5 - .../xcschemes/TabletDemo.xcscheme | 91 ---- .../xcschemes/xcschememanagement.plist | 22 - .../xcdebugger/Breakpoints_v2.xcbkptlist | 5 - .../xcschemes/TabletDemo.xcscheme | 101 ---- .../xcschemes/xcschememanagement.plist | 27 -- 45 files changed, 738 insertions(+), 1061 deletions(-) rename Tablet.podspec => TableKit.podspec (54%) rename {Tablet.xcworkspace => TableKit.xcworkspace}/contents.xcworkspacedata (53%) rename {Tablet => TableKit}/ConfigurableCell.swift (100%) rename {Tablet => TableKit}/HeightStrategy.swift (100%) rename {Tablet => TableKit}/Info.plist (100%) rename {Tablet => TableKit}/Operators.swift (100%) rename {Tablet => TableKit}/TableDirector.swift (100%) create mode 100644 TableKit/TableKit.h create mode 100644 TableKit/TableKit.xcodeproj/project.pbxproj rename {Tablet => TableKit}/TableRow.swift (100%) rename {Tablet => TableKit}/TableRowAction.swift (100%) rename {Tablet => TableKit}/TableRowBuilder.swift (100%) rename {Tablet => TableKit}/TableSection.swift (100%) rename {Tablet => TableKit}/Tablet.swift (100%) rename {TabletDemo => TableKitDemo}/Classes/Application/AppDelegate.swift (100%) rename {TabletDemo => TableKitDemo}/Classes/Presentation/Controllers/HeaderFooterController.swift (98%) rename {TabletDemo => TableKitDemo}/Classes/Presentation/Controllers/MainController.swift (99%) rename {TabletDemo => TableKitDemo}/Classes/Presentation/Views/StoryboardImageTableViewCell.swift (98%) rename {TabletDemo => TableKitDemo}/Classes/Presentation/Views/StoryboardTableViewCell.swift (95%) rename {TabletDemo => TableKitDemo}/Resources/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {TabletDemo => TableKitDemo}/Resources/Info.plist (100%) rename {TabletDemo => TableKitDemo}/Resources/Storyboards/LaunchScreen.storyboard (100%) rename {TabletDemo => TableKitDemo}/Resources/Storyboards/Main.storyboard (100%) create mode 100644 TableKitDemo/TableKitDemo.xcodeproj/project.pbxproj rename {TabletDemo/TabletDemo.xcodeproj => TableKitDemo/TableKitDemo.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (100%) delete mode 100644 Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 Tablet/Tablet.h delete mode 100644 Tablet/Tablet.xcodeproj/project.pbxproj delete mode 100644 Tablet/Tablet.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 Tablet/Tablet.xcodeproj/xcshareddata/xcschemes/Tablet.xcscheme delete mode 100644 Tablet/Tablet.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist rename TabletDemo/{TabletDemo.xcodeproj => TableKitDemo.xcodeproj}/project.pbxproj (95%) rename {Tablet/Tablet.xcodeproj => TabletDemo/TableKitDemo.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (70%) delete mode 100644 TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/TabletDemo.xcscheme delete mode 100644 TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/TabletDemo.xcscheme delete mode 100644 TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/.travis.yml b/.travis.yml index 99f321d..f57eb70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,4 +8,4 @@ before_install: - brew reinstall --HEAD xctool - cd Tablet script: - - xctool clean build test -project Tablet.xcodeproj -scheme Tablet -sdk iphonesimulator \ No newline at end of file + - xctool clean build test -project TableKit.xcodeproj -scheme TableKit -sdk iphonesimulator \ No newline at end of file diff --git a/README.md b/README.md index c543553..c9c36fd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -![Alamofire: Elegant Networking in Swift](https://raw.githubusercontent.com/maxsokolov/tablet/assets/logo.png) +![TableKit](https://raw.githubusercontent.com/maxsokolov/tablekit/assets/logo.png) -#Tablet.swift +#TableKit

Build Status @@ -10,7 +10,7 @@ License: MIT

-Tablet is a super lightweight yet powerful generic library that handles a complexity of UITableView's datasource and delegate methods in a Swift environment. Tablet's goal is to provide an easiest way to create complex table views. With Tablet you don't have to write a messy code of `switch` or `if` statements when you deal with bunch of different cells in different sections. +TableKit is a super lightweight yet powerful generic library that handles a complexity of UITableView's datasource and delegate methods in a Swift environment. Tablet's goal is to provide an easiest way to create complex table views. With Tablet you don't have to write a messy code of `switch` or `if` statements when you deal with bunch of different cells in different sections. ## Features @@ -24,179 +24,6 @@ Tablet is a super lightweight yet powerful generic library that handles a comple - [x] Extensibility - [x] Tests -That's almost all you need to build a bunch of cells in a section: -```swift -let builder = TableRowBuilder(items: ["1", "2", "3", "4", "5"]) -``` -Tablet relies on self-sizing table view cells, respects cells reusability feature and also built with performace in mind. You don't have to worry about anything, just create your cells, setup autolayout constraints and be happy. See the Usage section to learn more. - -## Requirements - -- iOS 8.0+ -- Xcode 7.0+ -- Swift 2.2 - -## Installation - -### CocoaPods -To integrate Tablet into your Xcode project using CocoaPods, specify it in your `Podfile`: - -```ruby -source 'https://github.com/CocoaPods/Specs.git' -platform :ios, '8.0' -use_frameworks! - -pod 'Tablet' -``` - -Then, run the following command: - -```bash -$ pod install -``` - -## Usage - -### Type-safe configurable cells - -Let's say you want to put your cell configuration logic into cell itself. Say you want to pass your view model (or even model) to your cell. -You could easily do this using the `TableRowBuilder`. Your cell should conforms to `ConfigurableCell` protocol as you may see in example below: - -```swift -import Tablet - -class MyTableViewCell : UITableViewCell, ConfigurableCell { - - typealias T = User - - // this method is not required to be implemented if your cell's id equals to class name - static func reusableIdentifier() -> String { - return "reusable_id" - } - - static func estimatedHeight() -> Float { - return 255 - } - - func configure(item: T) { // item is user here - - textLabel?.text = item.username - detailTextLabel?.text = item.isActive ? "Active" : "Inactive" - } -} -``` -Once you've implemented the protocol, simply use the `TableRowBuilder` to build cells: - -```swift -import Tablet - -let rowBuilder = TableRowBuilder() -rowBuilder += users - -director = TableDirector(tableView: tableView) -tableDirector += TableSectionBuilder(rows: [rowBuilder]) -``` - -### Very basic table view - -You may want to setup a very basic table view, without any custom cells. In that case simply use the `TableBaseRowBuilder`. - -```swift -import Tablet - -let rowBuilder = TableBaseRowBuilder(items: [user1, user2, user3], id: "reusable_id") - .action(.configure) { (data) in - - data.cell?.textLabel?.text = data.item.username - data.cell?.detailTextLabel?.text = data.item.isActive ? "Active" : "Inactive" - } - -let sectionBuilder = TableSectionBuilder(headerTitle: "Users", footerTitle: nil, rows: [rowBuilder]) - -director = TableDirector(tableView: tableView) -director += sectionBuilder -``` - -### Cell actions - -Tablet provides a chaining approach to handle actions from your cells: - -```swift -import Tablet - -let rowBuilder = TableRowBuilder(items: [user1, user2, user3], id: "reusable_id") - .action(.configure) { (data) in - - } - .action(.click) { (data) in - - } - .valueAction(.shouldHighlight) { (data) in - - return false - } -``` - -### Custom cell actions -```swift -import Tablet - -struct MyCellActions { - static let ButtonClicked = "ButtonClicked" -} - -class MyTableViewCell : UITableViewCell { - - @IBAction func buttonClicked(sender: UIButton) { - - Action(key: MyCellActions.ButtonClicked, sender: self, userInfo: nil).invoke() - } -} -``` -And receive this actions with your row builder: -```swift -import Tablet - -let rowBuilder = TableRowBuilder(items: users) - .action(.click) { (data) in - - } - .action(.willDisplay) { (data) in - - } - .action(MyCellActions.ButtonClicked) { (data) in - - } -``` - -## Extensibility - -If you find that Tablet is not provide an action you need, for example you need UITableViewDelegate's `didEndDisplayingCell` method and it's not out of the box, -simply provide an extension for `TableDirector`: -```swift -import Tablet - -struct MyTableActions { - static let DidEndDisplayingCell = "DidEndDisplayingCell" -} - -extension TableDirector { - - public func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { - - invoke(action: .custom(MyTableActions.DidEndDisplayingCell), cell: cell, indexPath: indexPath) - } -} -``` -Catch your action with row builder: -```swift -let rowBuilder = TableRowBuilder(items: users) - .action(MyTableActions.DidEndDisplayingCell) { (data) -> Void in - - } -``` -You could also invoke an action that returns a value. - ## License Tablet is available under the MIT license. See LICENSE for details. \ No newline at end of file diff --git a/Tablet.podspec b/TableKit.podspec similarity index 54% rename from Tablet.podspec rename to TableKit.podspec index c5be448..cdabc6c 100644 --- a/Tablet.podspec +++ b/TableKit.podspec @@ -1,17 +1,17 @@ Pod::Spec.new do |s| - s.name = 'Tablet' - s.module_name = 'Tablet' + s.name = 'TableKit' + s.module_name = 'TableKit' - s.version = '0.5.0' + s.version = '0.6.0' - s.homepage = 'https://github.com/maxsokolov/Tablet.swift' - s.summary = 'Powerful type-safe tool for UITableView. Swift 2.2 is required.' + s.homepage = 'https://github.com/maxsokolov/TableKit' + s.summary = 'Type-safe declarative table views. Swift 2.2 is required.' s.author = { 'Max Sokolov' => 'i@maxsokolov.net' } s.license = { :type => 'MIT', :file => 'LICENSE' } s.platforms = { :ios => '8.0' } s.ios.deployment_target = '8.0' - s.source_files = 'Tablet/*.swift' - s.source = { :git => 'https://github.com/maxsokolov/Tablet.swift.git', :tag => s.version } + s.source_files = 'TableKit/*.swift' + s.source = { :git => 'https://github.com/maxsokolov/TableKit.git', :tag => s.version } end \ No newline at end of file diff --git a/Tablet.xcworkspace/contents.xcworkspacedata b/TableKit.xcworkspace/contents.xcworkspacedata similarity index 53% rename from Tablet.xcworkspace/contents.xcworkspacedata rename to TableKit.xcworkspace/contents.xcworkspacedata index 8a2fad4..134624f 100644 --- a/Tablet.xcworkspace/contents.xcworkspacedata +++ b/TableKit.xcworkspace/contents.xcworkspacedata @@ -2,9 +2,9 @@ + location = "group:TableKit/TableKit.xcodeproj"> + location = "group:TableKitDemo/TableKitDemo.xcodeproj"> diff --git a/Tablet/ConfigurableCell.swift b/TableKit/ConfigurableCell.swift similarity index 100% rename from Tablet/ConfigurableCell.swift rename to TableKit/ConfigurableCell.swift diff --git a/Tablet/HeightStrategy.swift b/TableKit/HeightStrategy.swift similarity index 100% rename from Tablet/HeightStrategy.swift rename to TableKit/HeightStrategy.swift diff --git a/Tablet/Info.plist b/TableKit/Info.plist similarity index 100% rename from Tablet/Info.plist rename to TableKit/Info.plist diff --git a/Tablet/Operators.swift b/TableKit/Operators.swift similarity index 100% rename from Tablet/Operators.swift rename to TableKit/Operators.swift diff --git a/Tablet/TableDirector.swift b/TableKit/TableDirector.swift similarity index 100% rename from Tablet/TableDirector.swift rename to TableKit/TableDirector.swift diff --git a/TableKit/TableKit.h b/TableKit/TableKit.h new file mode 100644 index 0000000..c63484c --- /dev/null +++ b/TableKit/TableKit.h @@ -0,0 +1,19 @@ +// +// TableKit.h +// TableKit +// +// Created by Max Sokolov on 11/06/16. +// Copyright © 2016 Max Sokolov. All rights reserved. +// + +#import + +//! Project version number for TableKit. +FOUNDATION_EXPORT double TableKitVersionNumber; + +//! Project version string for TableKit. +FOUNDATION_EXPORT const unsigned char TableKitVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/TableKit/TableKit.xcodeproj/project.pbxproj b/TableKit/TableKit.xcodeproj/project.pbxproj new file mode 100644 index 0000000..bf9dc87 --- /dev/null +++ b/TableKit/TableKit.xcodeproj/project.pbxproj @@ -0,0 +1,335 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + DA9EA7711D0B68460021F650 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7681D0B68460021F650 /* ConfigurableCell.swift */; }; + DA9EA7721D0B68460021F650 /* HeightStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7691D0B68460021F650 /* HeightStrategy.swift */; }; + DA9EA7731D0B68460021F650 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA76A1D0B68460021F650 /* Operators.swift */; }; + DA9EA7741D0B68460021F650 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA76B1D0B68460021F650 /* TableDirector.swift */; }; + DA9EA7751D0B68460021F650 /* TableRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA76C1D0B68460021F650 /* TableRow.swift */; }; + DA9EA7761D0B68460021F650 /* TableRowAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA76D1D0B68460021F650 /* TableRowAction.swift */; }; + DA9EA7771D0B68460021F650 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA76E1D0B68460021F650 /* TableRowBuilder.swift */; }; + DA9EA7781D0B68460021F650 /* TableSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA76F1D0B68460021F650 /* TableSection.swift */; }; + DA9EA7791D0B68460021F650 /* Tablet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7701D0B68460021F650 /* Tablet.swift */; }; + DA9EA7801D0B689C0021F650 /* TableKit.h in Headers */ = {isa = PBXBuildFile; fileRef = DA9EA77E1D0B689C0021F650 /* TableKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + DA9EA7561D0B679A0021F650 /* TableKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TableKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + DA9EA7681D0B68460021F650 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; + DA9EA7691D0B68460021F650 /* HeightStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeightStrategy.swift; sourceTree = ""; }; + DA9EA76A1D0B68460021F650 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; + DA9EA76B1D0B68460021F650 /* TableDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDirector.swift; sourceTree = ""; }; + DA9EA76C1D0B68460021F650 /* TableRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRow.swift; sourceTree = ""; }; + DA9EA76D1D0B68460021F650 /* TableRowAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowAction.swift; sourceTree = ""; }; + DA9EA76E1D0B68460021F650 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = ""; }; + DA9EA76F1D0B68460021F650 /* TableSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableSection.swift; sourceTree = ""; }; + DA9EA7701D0B68460021F650 /* Tablet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tablet.swift; sourceTree = ""; }; + DA9EA77D1D0B689C0021F650 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + DA9EA77E1D0B689C0021F650 /* TableKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TableKit.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + DA9EA7521D0B679A0021F650 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + DA9EA74C1D0B679A0021F650 = { + isa = PBXGroup; + children = ( + DA9EA7671D0B68340021F650 /* Classes */, + DA9EA7571D0B679A0021F650 /* Products */, + DA9EA77C1D0B68860021F650 /* Supporting Files */, + ); + sourceTree = ""; + }; + DA9EA7571D0B679A0021F650 /* Products */ = { + isa = PBXGroup; + children = ( + DA9EA7561D0B679A0021F650 /* TableKit.framework */, + ); + name = Products; + sourceTree = ""; + }; + DA9EA7671D0B68340021F650 /* Classes */ = { + isa = PBXGroup; + children = ( + DA9EA7681D0B68460021F650 /* ConfigurableCell.swift */, + DA9EA7691D0B68460021F650 /* HeightStrategy.swift */, + DA9EA76A1D0B68460021F650 /* Operators.swift */, + DA9EA76B1D0B68460021F650 /* TableDirector.swift */, + DA9EA76C1D0B68460021F650 /* TableRow.swift */, + DA9EA76D1D0B68460021F650 /* TableRowAction.swift */, + DA9EA76E1D0B68460021F650 /* TableRowBuilder.swift */, + DA9EA76F1D0B68460021F650 /* TableSection.swift */, + DA9EA7701D0B68460021F650 /* Tablet.swift */, + ); + name = Classes; + sourceTree = ""; + }; + DA9EA77C1D0B68860021F650 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + DA9EA77D1D0B689C0021F650 /* Info.plist */, + DA9EA77E1D0B689C0021F650 /* TableKit.h */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + DA9EA7531D0B679A0021F650 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DA9EA7801D0B689C0021F650 /* TableKit.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + DA9EA7551D0B679A0021F650 /* TableKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = DA9EA75E1D0B679A0021F650 /* Build configuration list for PBXNativeTarget "TableKit" */; + buildPhases = ( + DA9EA7511D0B679A0021F650 /* Sources */, + DA9EA7521D0B679A0021F650 /* Frameworks */, + DA9EA7531D0B679A0021F650 /* Headers */, + DA9EA7541D0B679A0021F650 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TableKit; + productName = TableKit; + productReference = DA9EA7561D0B679A0021F650 /* TableKit.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + DA9EA74D1D0B679A0021F650 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = "Max Sokolov"; + TargetAttributes = { + DA9EA7551D0B679A0021F650 = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = DA9EA7501D0B679A0021F650 /* Build configuration list for PBXProject "TableKit" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = DA9EA74C1D0B679A0021F650; + productRefGroup = DA9EA7571D0B679A0021F650 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + DA9EA7551D0B679A0021F650 /* TableKit */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + DA9EA7541D0B679A0021F650 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + DA9EA7511D0B679A0021F650 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DA9EA7711D0B68460021F650 /* ConfigurableCell.swift in Sources */, + DA9EA7721D0B68460021F650 /* HeightStrategy.swift in Sources */, + DA9EA7781D0B68460021F650 /* TableSection.swift in Sources */, + DA9EA7751D0B68460021F650 /* TableRow.swift in Sources */, + DA9EA7761D0B68460021F650 /* TableRowAction.swift in Sources */, + DA9EA7741D0B68460021F650 /* TableDirector.swift in Sources */, + DA9EA7771D0B68460021F650 /* TableRowBuilder.swift in Sources */, + DA9EA7791D0B68460021F650 /* Tablet.swift in Sources */, + DA9EA7731D0B68460021F650 /* Operators.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + DA9EA75C1D0B679A0021F650 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + DA9EA75D1D0B679A0021F650 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + DA9EA75F1D0B679A0021F650 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + DA9EA7601D0B679A0021F650 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + DA9EA7501D0B679A0021F650 /* Build configuration list for PBXProject "TableKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DA9EA75C1D0B679A0021F650 /* Debug */, + DA9EA75D1D0B679A0021F650 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DA9EA75E1D0B679A0021F650 /* Build configuration list for PBXNativeTarget "TableKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DA9EA75F1D0B679A0021F650 /* Debug */, + DA9EA7601D0B679A0021F650 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = DA9EA74D1D0B679A0021F650 /* Project object */; +} diff --git a/Tablet/TableRow.swift b/TableKit/TableRow.swift similarity index 100% rename from Tablet/TableRow.swift rename to TableKit/TableRow.swift diff --git a/Tablet/TableRowAction.swift b/TableKit/TableRowAction.swift similarity index 100% rename from Tablet/TableRowAction.swift rename to TableKit/TableRowAction.swift diff --git a/Tablet/TableRowBuilder.swift b/TableKit/TableRowBuilder.swift similarity index 100% rename from Tablet/TableRowBuilder.swift rename to TableKit/TableRowBuilder.swift diff --git a/Tablet/TableSection.swift b/TableKit/TableSection.swift similarity index 100% rename from Tablet/TableSection.swift rename to TableKit/TableSection.swift diff --git a/Tablet/Tablet.swift b/TableKit/Tablet.swift similarity index 100% rename from Tablet/Tablet.swift rename to TableKit/Tablet.swift diff --git a/TabletDemo/Classes/Application/AppDelegate.swift b/TableKitDemo/Classes/Application/AppDelegate.swift similarity index 100% rename from TabletDemo/Classes/Application/AppDelegate.swift rename to TableKitDemo/Classes/Application/AppDelegate.swift diff --git a/TabletDemo/Classes/Presentation/Controllers/HeaderFooterController.swift b/TableKitDemo/Classes/Presentation/Controllers/HeaderFooterController.swift similarity index 98% rename from TabletDemo/Classes/Presentation/Controllers/HeaderFooterController.swift rename to TableKitDemo/Classes/Presentation/Controllers/HeaderFooterController.swift index 47c030d..6c8d62f 100644 --- a/TabletDemo/Classes/Presentation/Controllers/HeaderFooterController.swift +++ b/TableKitDemo/Classes/Presentation/Controllers/HeaderFooterController.swift @@ -7,7 +7,7 @@ // import UIKit -import Tablet +import TableKit class HeaderFooterController: UIViewController { diff --git a/TabletDemo/Classes/Presentation/Controllers/MainController.swift b/TableKitDemo/Classes/Presentation/Controllers/MainController.swift similarity index 99% rename from TabletDemo/Classes/Presentation/Controllers/MainController.swift rename to TableKitDemo/Classes/Presentation/Controllers/MainController.swift index 0a803a5..9a2f174 100644 --- a/TabletDemo/Classes/Presentation/Controllers/MainController.swift +++ b/TableKitDemo/Classes/Presentation/Controllers/MainController.swift @@ -7,7 +7,7 @@ // import UIKit -import Tablet +import TableKit class MainController: UIViewController { diff --git a/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift b/TableKitDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift similarity index 98% rename from TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift rename to TableKitDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift index 45bf5b6..c809967 100644 --- a/TabletDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift +++ b/TableKitDemo/Classes/Presentation/Views/StoryboardImageTableViewCell.swift @@ -7,7 +7,7 @@ // import UIKit -import Tablet +import TableKit class StoryboardImageTableViewCell: UITableViewCell, ConfigurableCell { diff --git a/TabletDemo/Classes/Presentation/Views/StoryboardTableViewCell.swift b/TableKitDemo/Classes/Presentation/Views/StoryboardTableViewCell.swift similarity index 95% rename from TabletDemo/Classes/Presentation/Views/StoryboardTableViewCell.swift rename to TableKitDemo/Classes/Presentation/Views/StoryboardTableViewCell.swift index 1f06499..8180860 100644 --- a/TabletDemo/Classes/Presentation/Views/StoryboardTableViewCell.swift +++ b/TableKitDemo/Classes/Presentation/Views/StoryboardTableViewCell.swift @@ -7,7 +7,7 @@ // import UIKit -import Tablet +import TableKit class StoryboardTableViewCell: UITableViewCell, ConfigurableCell { diff --git a/TabletDemo/Resources/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json b/TableKitDemo/Resources/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from TabletDemo/Resources/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json rename to TableKitDemo/Resources/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/TabletDemo/Resources/Info.plist b/TableKitDemo/Resources/Info.plist similarity index 100% rename from TabletDemo/Resources/Info.plist rename to TableKitDemo/Resources/Info.plist diff --git a/TabletDemo/Resources/Storyboards/LaunchScreen.storyboard b/TableKitDemo/Resources/Storyboards/LaunchScreen.storyboard similarity index 100% rename from TabletDemo/Resources/Storyboards/LaunchScreen.storyboard rename to TableKitDemo/Resources/Storyboards/LaunchScreen.storyboard diff --git a/TabletDemo/Resources/Storyboards/Main.storyboard b/TableKitDemo/Resources/Storyboards/Main.storyboard similarity index 100% rename from TabletDemo/Resources/Storyboards/Main.storyboard rename to TableKitDemo/Resources/Storyboards/Main.storyboard diff --git a/TableKitDemo/TableKitDemo.xcodeproj/project.pbxproj b/TableKitDemo/TableKitDemo.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9175ff7 --- /dev/null +++ b/TableKitDemo/TableKitDemo.xcodeproj/project.pbxproj @@ -0,0 +1,362 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + DA08A0531CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */; }; + DA9EA7821D0B6B070021F650 /* TableKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9EA7811D0B6B070021F650 /* TableKit.framework */; }; + DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */; }; + DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */; }; + DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */; }; + DAC2D69C1C9E75E3009E9C19 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D69B1C9E75E3009E9C19 /* Assets.xcassets */; }; + DACB71761CC2D63D00432BD3 /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACB71751CC2D63D00432BD3 /* MainController.swift */; }; + DACB71781CC2D6ED00432BD3 /* StoryboardTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACB71771CC2D6ED00432BD3 /* StoryboardTableViewCell.swift */; }; + DACB717A1CC2D89D00432BD3 /* HeaderFooterController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACB71791CC2D89D00432BD3 /* HeaderFooterController.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardImageTableViewCell.swift; sourceTree = ""; }; + DA9EA7811D0B6B070021F650 /* TableKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TableKit.framework; path = "../../../../../Library/Developer/Xcode/DerivedData/TableKit-blgxvmkyvpocltgadmpliruugomo/Build/Products/Debug-iphonesimulator/TableKit.framework"; sourceTree = ""; }; + DAB7EB271BEF787300D2AD5E /* TableKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TableKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; + DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + DAC2D69B1C9E75E3009E9C19 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + DAC2D69D1C9E78B5009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + DACB71751CC2D63D00432BD3 /* MainController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = ""; }; + DACB71771CC2D6ED00432BD3 /* StoryboardTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardTableViewCell.swift; sourceTree = ""; }; + DACB71791CC2D89D00432BD3 /* HeaderFooterController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderFooterController.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + DAB7EB241BEF787300D2AD5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DA9EA7821D0B6B070021F650 /* TableKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + DA539C871CF50B1800368ACB /* Frameworks */ = { + isa = PBXGroup; + children = ( + DA9EA7811D0B6B070021F650 /* TableKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + DAB7EB1E1BEF787300D2AD5E = { + isa = PBXGroup; + children = ( + DAC2D5C61C9D2FE5009E9C19 /* Classes */, + DAC2D5CB1C9D3058009E9C19 /* Resources */, + DA539C871CF50B1800368ACB /* Frameworks */, + DAB7EB281BEF787300D2AD5E /* Products */, + ); + sourceTree = ""; + }; + DAB7EB281BEF787300D2AD5E /* Products */ = { + isa = PBXGroup; + children = ( + DAB7EB271BEF787300D2AD5E /* TableKitDemo.app */, + ); + name = Products; + sourceTree = ""; + }; + DAC2D5C61C9D2FE5009E9C19 /* Classes */ = { + isa = PBXGroup; + children = ( + DAC2D5C81C9D3014009E9C19 /* Application */, + DAC2D5C71C9D3005009E9C19 /* Presentation */, + ); + path = Classes; + sourceTree = ""; + }; + DAC2D5C71C9D3005009E9C19 /* Presentation */ = { + isa = PBXGroup; + children = ( + DACB71731CC2D5ED00432BD3 /* Controllers */, + DACB71741CC2D5FD00432BD3 /* Views */, + ); + path = Presentation; + sourceTree = ""; + }; + DAC2D5C81C9D3014009E9C19 /* Application */ = { + isa = PBXGroup; + children = ( + DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */, + ); + path = Application; + sourceTree = ""; + }; + DAC2D5CB1C9D3058009E9C19 /* Resources */ = { + isa = PBXGroup; + children = ( + DAC2D69D1C9E78B5009E9C19 /* Info.plist */, + DAC2D69A1C9E75BE009E9C19 /* Assets */, + DAC2D5CC1C9D306C009E9C19 /* Storyboards */, + ); + path = Resources; + sourceTree = ""; + }; + DAC2D5CC1C9D306C009E9C19 /* Storyboards */ = { + isa = PBXGroup; + children = ( + DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */, + DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */, + ); + path = Storyboards; + sourceTree = ""; + }; + DAC2D69A1C9E75BE009E9C19 /* Assets */ = { + isa = PBXGroup; + children = ( + DAC2D69B1C9E75E3009E9C19 /* Assets.xcassets */, + ); + path = Assets; + sourceTree = ""; + }; + DACB71731CC2D5ED00432BD3 /* Controllers */ = { + isa = PBXGroup; + children = ( + DACB71751CC2D63D00432BD3 /* MainController.swift */, + DACB71791CC2D89D00432BD3 /* HeaderFooterController.swift */, + ); + path = Controllers; + sourceTree = ""; + }; + DACB71741CC2D5FD00432BD3 /* Views */ = { + isa = PBXGroup; + children = ( + DACB71771CC2D6ED00432BD3 /* StoryboardTableViewCell.swift */, + DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */, + ); + path = Views; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + DAB7EB261BEF787300D2AD5E /* TableKitDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = DAB7EB391BEF787300D2AD5E /* Build configuration list for PBXNativeTarget "TableKitDemo" */; + buildPhases = ( + DAB7EB231BEF787300D2AD5E /* Sources */, + DAB7EB241BEF787300D2AD5E /* Frameworks */, + DAB7EB251BEF787300D2AD5E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TableKitDemo; + productName = TabletDemo; + productReference = DAB7EB271BEF787300D2AD5E /* TableKitDemo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + DAB7EB1F1BEF787300D2AD5E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0700; + ORGANIZATIONNAME = Tablet; + TargetAttributes = { + DAB7EB261BEF787300D2AD5E = { + CreatedOnToolsVersion = 7.0.1; + DevelopmentTeam = Z48R734SJX; + }; + }; + }; + buildConfigurationList = DAB7EB221BEF787300D2AD5E /* Build configuration list for PBXProject "TableKitDemo" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = DAB7EB1E1BEF787300D2AD5E; + productRefGroup = DAB7EB281BEF787300D2AD5E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + DAB7EB261BEF787300D2AD5E /* TableKitDemo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + DAB7EB251BEF787300D2AD5E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */, + DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */, + DAC2D69C1C9E75E3009E9C19 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + DAB7EB231BEF787300D2AD5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DACB71781CC2D6ED00432BD3 /* StoryboardTableViewCell.swift in Sources */, + DACB71761CC2D63D00432BD3 /* MainController.swift in Sources */, + DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */, + DACB717A1CC2D89D00432BD3 /* HeaderFooterController.swift in Sources */, + DA08A0531CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + DAB7EB371BEF787300D2AD5E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + DAB7EB381BEF787300D2AD5E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + DAB7EB3A1BEF787300D2AD5E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + INFOPLIST_FILE = Resources/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo; + PRODUCT_NAME = TableKitDemo; + PROVISIONING_PROFILE = ""; + }; + name = Debug; + }; + DAB7EB3B1BEF787300D2AD5E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + INFOPLIST_FILE = Resources/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo; + PRODUCT_NAME = TableKitDemo; + PROVISIONING_PROFILE = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + DAB7EB221BEF787300D2AD5E /* Build configuration list for PBXProject "TableKitDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DAB7EB371BEF787300D2AD5E /* Debug */, + DAB7EB381BEF787300D2AD5E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DAB7EB391BEF787300D2AD5E /* Build configuration list for PBXNativeTarget "TableKitDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DAB7EB3A1BEF787300D2AD5E /* Debug */, + DAB7EB3B1BEF787300D2AD5E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = DAB7EB1F1BEF787300D2AD5E /* Project object */; +} diff --git a/TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/TableKitDemo/TableKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to TableKitDemo/TableKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate b/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index b905fecdb7205bfdb2d2572bb0247f4217646129..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21675 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Tablet/Tablet.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/xcschememanagement.plist b/Tablet/Tablet.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index d54e643..0000000 --- a/Tablet/Tablet.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,19 +0,0 @@ - - - - - SuppressBuildableAutocreation - - DAC2D6681C9D743D009E9C19 - - primary - - - DAC2D6721C9D743D009E9C19 - - primary - - - - - diff --git a/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index fe2b454..0000000 --- a/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist b/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 96dcbf8..0000000 --- a/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,27 +0,0 @@ - - - - - SchemeUserState - - Tablet.xcscheme_^#shared#^_ - - orderHint - 0 - - - SuppressBuildableAutocreation - - DAC2D6681C9D743D009E9C19 - - primary - - - DAC2D6721C9D743D009E9C19 - - primary - - - - - diff --git a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj b/TabletDemo/TableKitDemo.xcodeproj/project.pbxproj similarity index 95% rename from TabletDemo/TabletDemo.xcodeproj/project.pbxproj rename to TabletDemo/TableKitDemo.xcodeproj/project.pbxproj index e5a839f..dac2c73 100644 --- a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj +++ b/TabletDemo/TableKitDemo.xcodeproj/project.pbxproj @@ -8,7 +8,7 @@ /* Begin PBXBuildFile section */ DA08A0531CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */; }; - DA539C941CF6610400368ACB /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA539C931CF6610400368ACB /* Tablet.framework */; }; + DA9EA7421D0B63E20021F650 /* TableKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9EA7411D0B63E20021F650 /* TableKit.framework */; }; DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */; }; DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */; }; DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */; }; @@ -21,6 +21,7 @@ /* Begin PBXFileReference section */ DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardImageTableViewCell.swift; sourceTree = ""; }; DA539C931CF6610400368ACB /* Tablet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Tablet.framework; path = "../../../../../Library/Developer/Xcode/DerivedData/Tablet-hgommdyxtgxijceamltarpblrbwc/Build/Products/Debug-iphoneos/Tablet.framework"; sourceTree = ""; }; + DA9EA7411D0B63E20021F650 /* TableKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TableKit.framework; path = "../../../../../Library/Developer/Xcode/DerivedData/Tablet-hgommdyxtgxijceamltarpblrbwc/Build/Products/Debug-iphonesimulator/TableKit.framework"; sourceTree = ""; }; DAB7EB271BEF787300D2AD5E /* TabletDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabletDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; @@ -37,7 +38,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DA539C941CF6610400368ACB /* Tablet.framework in Frameworks */, + DA9EA7421D0B63E20021F650 /* TableKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -47,6 +48,7 @@ DA539C871CF50B1800368ACB /* Frameworks */ = { isa = PBXGroup; children = ( + DA9EA7411D0B63E20021F650 /* TableKit.framework */, DA539C931CF6610400368ACB /* Tablet.framework */, ); name = Frameworks; diff --git a/Tablet/Tablet.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/TabletDemo/TableKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 70% rename from Tablet/Tablet.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to TabletDemo/TableKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 78fd6b2..9fbb493 100644 --- a/Tablet/Tablet.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/TabletDemo/TableKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:TabletDemo.xcodeproj"> diff --git a/TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate b/TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index ae39eebc9875e02408a70b7047d5e176092e3a70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17117 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 diff --git a/TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate b/TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 6fe613053bcb6cea09e7d7012eac75a7444f9698..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35030 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 D$j(G< diff --git a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index fe2b454..0000000 --- a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/TabletDemo.xcscheme b/TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/TabletDemo.xcscheme deleted file mode 100644 index 6db4123..0000000 --- a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/TabletDemo.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/xcschememanagement.plist b/TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index c382e1a..0000000 --- a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/max.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - TabletDemo.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - DAB7EB261BEF787300D2AD5E - - primary - - - - - diff --git a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index fe2b454..0000000 --- a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/TabletDemo.xcscheme b/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/TabletDemo.xcscheme deleted file mode 100644 index 5b59ce8..0000000 --- a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/TabletDemo.xcscheme +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist b/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 08916f9..0000000 --- a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,27 +0,0 @@ - - - - - SchemeUserState - - TabletDemo.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - DAB7EB261BEF787300D2AD5E - - primary - - - DAC2D5DB1C9D6433009E9C19 - - primary - - - - - From 87821ac3c4725087f4cf41e7f4fc576ac61fe2cf Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Sat, 11 Jun 2016 00:52:03 +0300 Subject: [PATCH 33/34] fix --- .../TableKitDemo.xcodeproj/project.pbxproj | 364 ------------------ .../contents.xcworkspacedata | 7 - 2 files changed, 371 deletions(-) delete mode 100644 TabletDemo/TableKitDemo.xcodeproj/project.pbxproj delete mode 100644 TabletDemo/TableKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/TabletDemo/TableKitDemo.xcodeproj/project.pbxproj b/TabletDemo/TableKitDemo.xcodeproj/project.pbxproj deleted file mode 100644 index dac2c73..0000000 --- a/TabletDemo/TableKitDemo.xcodeproj/project.pbxproj +++ /dev/null @@ -1,364 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - DA08A0531CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */; }; - DA9EA7421D0B63E20021F650 /* TableKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9EA7411D0B63E20021F650 /* TableKit.framework */; }; - DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */; }; - DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */; }; - DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */; }; - DAC2D69C1C9E75E3009E9C19 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D69B1C9E75E3009E9C19 /* Assets.xcassets */; }; - DACB71761CC2D63D00432BD3 /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACB71751CC2D63D00432BD3 /* MainController.swift */; }; - DACB71781CC2D6ED00432BD3 /* StoryboardTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACB71771CC2D6ED00432BD3 /* StoryboardTableViewCell.swift */; }; - DACB717A1CC2D89D00432BD3 /* HeaderFooterController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACB71791CC2D89D00432BD3 /* HeaderFooterController.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardImageTableViewCell.swift; sourceTree = ""; }; - DA539C931CF6610400368ACB /* Tablet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Tablet.framework; path = "../../../../../Library/Developer/Xcode/DerivedData/Tablet-hgommdyxtgxijceamltarpblrbwc/Build/Products/Debug-iphoneos/Tablet.framework"; sourceTree = ""; }; - DA9EA7411D0B63E20021F650 /* TableKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TableKit.framework; path = "../../../../../Library/Developer/Xcode/DerivedData/Tablet-hgommdyxtgxijceamltarpblrbwc/Build/Products/Debug-iphonesimulator/TableKit.framework"; sourceTree = ""; }; - DAB7EB271BEF787300D2AD5E /* TabletDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabletDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; - DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; - DAC2D69B1C9E75E3009E9C19 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - DAC2D69D1C9E78B5009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - DACB71751CC2D63D00432BD3 /* MainController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = ""; }; - DACB71771CC2D6ED00432BD3 /* StoryboardTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardTableViewCell.swift; sourceTree = ""; }; - DACB71791CC2D89D00432BD3 /* HeaderFooterController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderFooterController.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - DAB7EB241BEF787300D2AD5E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - DA9EA7421D0B63E20021F650 /* TableKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - DA539C871CF50B1800368ACB /* Frameworks */ = { - isa = PBXGroup; - children = ( - DA9EA7411D0B63E20021F650 /* TableKit.framework */, - DA539C931CF6610400368ACB /* Tablet.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - DAB7EB1E1BEF787300D2AD5E = { - isa = PBXGroup; - children = ( - DAC2D5C61C9D2FE5009E9C19 /* Classes */, - DAC2D5CB1C9D3058009E9C19 /* Resources */, - DA539C871CF50B1800368ACB /* Frameworks */, - DAB7EB281BEF787300D2AD5E /* Products */, - ); - sourceTree = ""; - }; - DAB7EB281BEF787300D2AD5E /* Products */ = { - isa = PBXGroup; - children = ( - DAB7EB271BEF787300D2AD5E /* TabletDemo.app */, - ); - name = Products; - sourceTree = ""; - }; - DAC2D5C61C9D2FE5009E9C19 /* Classes */ = { - isa = PBXGroup; - children = ( - DAC2D5C81C9D3014009E9C19 /* Application */, - DAC2D5C71C9D3005009E9C19 /* Presentation */, - ); - path = Classes; - sourceTree = ""; - }; - DAC2D5C71C9D3005009E9C19 /* Presentation */ = { - isa = PBXGroup; - children = ( - DACB71731CC2D5ED00432BD3 /* Controllers */, - DACB71741CC2D5FD00432BD3 /* Views */, - ); - path = Presentation; - sourceTree = ""; - }; - DAC2D5C81C9D3014009E9C19 /* Application */ = { - isa = PBXGroup; - children = ( - DAC2D5C91C9D303E009E9C19 /* AppDelegate.swift */, - ); - path = Application; - sourceTree = ""; - }; - DAC2D5CB1C9D3058009E9C19 /* Resources */ = { - isa = PBXGroup; - children = ( - DAC2D69D1C9E78B5009E9C19 /* Info.plist */, - DAC2D69A1C9E75BE009E9C19 /* Assets */, - DAC2D5CC1C9D306C009E9C19 /* Storyboards */, - ); - path = Resources; - sourceTree = ""; - }; - DAC2D5CC1C9D306C009E9C19 /* Storyboards */ = { - isa = PBXGroup; - children = ( - DAC2D5CD1C9D30A7009E9C19 /* Main.storyboard */, - DAC2D5CE1C9D30A7009E9C19 /* LaunchScreen.storyboard */, - ); - path = Storyboards; - sourceTree = ""; - }; - DAC2D69A1C9E75BE009E9C19 /* Assets */ = { - isa = PBXGroup; - children = ( - DAC2D69B1C9E75E3009E9C19 /* Assets.xcassets */, - ); - path = Assets; - sourceTree = ""; - }; - DACB71731CC2D5ED00432BD3 /* Controllers */ = { - isa = PBXGroup; - children = ( - DACB71751CC2D63D00432BD3 /* MainController.swift */, - DACB71791CC2D89D00432BD3 /* HeaderFooterController.swift */, - ); - path = Controllers; - sourceTree = ""; - }; - DACB71741CC2D5FD00432BD3 /* Views */ = { - isa = PBXGroup; - children = ( - DACB71771CC2D6ED00432BD3 /* StoryboardTableViewCell.swift */, - DA08A0521CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift */, - ); - path = Views; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - DAB7EB261BEF787300D2AD5E /* TabletDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = DAB7EB391BEF787300D2AD5E /* Build configuration list for PBXNativeTarget "TabletDemo" */; - buildPhases = ( - DAB7EB231BEF787300D2AD5E /* Sources */, - DAB7EB241BEF787300D2AD5E /* Frameworks */, - DAB7EB251BEF787300D2AD5E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = TabletDemo; - productName = TabletDemo; - productReference = DAB7EB271BEF787300D2AD5E /* TabletDemo.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - DAB7EB1F1BEF787300D2AD5E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0700; - ORGANIZATIONNAME = Tablet; - TargetAttributes = { - DAB7EB261BEF787300D2AD5E = { - CreatedOnToolsVersion = 7.0.1; - DevelopmentTeam = Z48R734SJX; - }; - }; - }; - buildConfigurationList = DAB7EB221BEF787300D2AD5E /* Build configuration list for PBXProject "TabletDemo" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = DAB7EB1E1BEF787300D2AD5E; - productRefGroup = DAB7EB281BEF787300D2AD5E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - DAB7EB261BEF787300D2AD5E /* TabletDemo */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - DAB7EB251BEF787300D2AD5E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */, - DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */, - DAC2D69C1C9E75E3009E9C19 /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - DAB7EB231BEF787300D2AD5E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - DACB71781CC2D6ED00432BD3 /* StoryboardTableViewCell.swift in Sources */, - DACB71761CC2D63D00432BD3 /* MainController.swift in Sources */, - DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */, - DACB717A1CC2D89D00432BD3 /* HeaderFooterController.swift in Sources */, - DA08A0531CF4E9B500BBF1F8 /* StoryboardImageTableViewCell.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - DAB7EB371BEF787300D2AD5E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - DAB7EB381BEF787300D2AD5E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - DAB7EB3A1BEF787300D2AD5E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - INFOPLIST_FILE = Resources/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.tablet.demo; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - }; - name = Debug; - }; - DAB7EB3B1BEF787300D2AD5E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - INFOPLIST_FILE = Resources/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.tablet.demo; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - DAB7EB221BEF787300D2AD5E /* Build configuration list for PBXProject "TabletDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DAB7EB371BEF787300D2AD5E /* Debug */, - DAB7EB381BEF787300D2AD5E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - DAB7EB391BEF787300D2AD5E /* Build configuration list for PBXNativeTarget "TabletDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DAB7EB3A1BEF787300D2AD5E /* Debug */, - DAB7EB3B1BEF787300D2AD5E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = DAB7EB1F1BEF787300D2AD5E /* Project object */; -} diff --git a/TabletDemo/TableKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/TabletDemo/TableKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 9fbb493..0000000 --- a/TabletDemo/TableKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - From e3ddb25b22bfc8dcee1ec48f61217f2e2282da66 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Sat, 11 Jun 2016 12:28:46 +0300 Subject: [PATCH 34/34] bump readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c9c36fd..a4b452c 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,11 @@ -![TableKit](https://raw.githubusercontent.com/maxsokolov/tablekit/assets/logo.png) - #TableKit

-Build Status +Build Status Swift 2.2 compatible Platform iOS -CocoaPods compatible -License: MIT +CocoaPods compatible +License: MIT

TableKit is a super lightweight yet powerful generic library that handles a complexity of UITableView's datasource and delegate methods in a Swift environment. Tablet's goal is to provide an easiest way to create complex table views. With Tablet you don't have to write a messy code of `switch` or `if` statements when you deal with bunch of different cells in different sections. @@ -24,6 +22,8 @@ TableKit is a super lightweight yet powerful generic library that handles a comp - [x] Extensibility - [x] Tests +Docs will be updated soon. + ## License Tablet is available under the MIT license. See LICENSE for details. \ No newline at end of file