diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..b570850
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+language: objective-c
+osx_image: xcode7.2
+branches:
+ only:
+ - master
+before_install:
+ - cd Tablet
+script:
+ - xctool clean build test -project Tablet.xcodeproj -scheme Tablet -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES
+after_success:
+ - cd $TRAVIS_BUILD_DIR
\ No newline at end of file
diff --git a/README.md b/README.md
index 84a933e..565e953 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,32 @@
-
+#Tablet
+
-
+
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.
-That's almost all you need in your controller to build a bunch of cells in a section:
+## Features
+
+- [x] Type-safe cells based on generics
+- [x] The easiest way to map your models or view models to cells
+- [x] Correctly handles autolayout cells with multiline labels
+- [x] Chainable cell actions
+- [x] Support cells created from code, xib, or storyboard
+- [x] Automatic xib/classes registration
+- [x] No need to subclass
+- [x] Extensibility
+- [x] Tests
+
+That's almost all you need in your controller to build a bunch of cells in a section 😘:
```swift
-TableConfigurableRowBuilder(items: ["1", "2", "3", "4", "5"], estimatedRowHeight: 42)
+TableConfigurableRowBuilder(items: ["1", "2", "3", "4", "5"])
```
-Tablet respects cells reusability feature and it's type-safe. See the Usage section to learn more.
+Tablet respects cells reusability feature and built with performace in mind. See the Usage section to learn more.
## Requirements
@@ -55,7 +68,7 @@ let rowBuilder = TableRowBuilder(items: [user1, user2, us
data.cell?.detailTextLabel?.text = data.item.isActive ? "Active" : "Inactive"
}
-let sectionBuilder = TableSectionBuilder(headerTitle: "Users", rowBuilders: [rowBuilder])
+let sectionBuilder = TableSectionBuilder(headerTitle: "Users", rows: [rowBuilder])
director = TableDirector(tableView: tableView)
director.appendSections(sectionBuilder)
@@ -77,6 +90,10 @@ class MyTableViewCell : UITableViewCell, ConfigurableCell {
return "reusable_id"
}
+ static func estimatedHeight() -> Float {
+ return 255
+ }
+
func configureWithItem(item: Item) { // item is user here
textLabel?.text = item.username
@@ -89,11 +106,11 @@ Once you've implemented the protocol, simply use the `TableConfigurableRowBuilde
```swift
import Tablet
-let rowBuilder = TableConfigurableRowBuilder(estimatedRowHeight: 42)
+let rowBuilder = TableConfigurableRowBuilder()
rowBuilder.appendItems(users)
director = TableDirector(tableView: tableView)
-tableDirector.appendSection(TableSectionBuilder(rowBuilders: [rowBuilder]))
+tableDirector.appendSection(TableSectionBuilder(rows: [rowBuilder]))
```
### Cell actions
@@ -134,7 +151,7 @@ And receive this actions with your row builder:
```swift
import Tablet
-let rowBuilder = TableConfigurableRowBuilder(items: users, id: "reusable_id", estimatedRowHeight: 42)
+let rowBuilder = TableConfigurableRowBuilder(items: users, id: "reusable_id")
.action(.click) { data -> Void in
}
@@ -165,7 +182,7 @@ extension TableDirector {
```
Catch your action with row builder:
```swift
-let rowBuilder = TableConfigurableRowBuilder(items: users, estimatedRowHeight: 42)
+let rowBuilder = TableConfigurableRowBuilder(items: users)
.action(kTableDirectorDidEndDisplayingCell) { data -> Void in
}
diff --git a/Tablet.podspec b/Tablet.podspec
index 373dac0..c285709 100644
--- a/Tablet.podspec
+++ b/Tablet.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Tablet'
- s.version = '0.2.6'
+ s.version = '0.3.0'
s.homepage = 'https://github.com/maxsokolov/tablet'
s.summary = 'Powerful type-safe tool for UITableView. Swift 2.0 is required.'
diff --git a/Tablet.xcworkspace/contents.xcworkspacedata b/Tablet.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..8a2fad4
--- /dev/null
+++ b/Tablet.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/Tablet.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate b/Tablet.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..2abe584
Binary files /dev/null and b/Tablet.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/Tablet/Info.plist b/Tablet/Info.plist
new file mode 100644
index 0000000..d3de8ee
--- /dev/null
+++ b/Tablet/Info.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+ NSPrincipalClass
+
+
+
diff --git a/Tablet/TableDirector.swift b/Tablet/TableDirector.swift
index 957b933..d50bd79 100644
--- a/Tablet/TableDirector.swift
+++ b/Tablet/TableDirector.swift
@@ -27,9 +27,9 @@ import Foundation
public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
public private(set) weak var tableView: UITableView!
- private var sections = [TableSectionBuilder]()
public weak var scrollDelegate: UIScrollViewDelegate?
-
+ private var sections = [TableSectionBuilder]()
+
public init(tableView: UITableView) {
super.init()
@@ -37,7 +37,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
self.tableView.delegate = self
self.tableView.dataSource = self
- NSNotificationCenter.defaultCenter().addObserver(self, selector: "didReceiveAction:", name: kActionPerformedNotificationKey, object: nil)
+ NSNotificationCenter.defaultCenter().addObserver(self, selector: "didReceiveAction:", name: TabletNotifications.CellAction, object: nil)
}
deinit {
@@ -56,24 +56,16 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
- Returns: A touple - (builder, builderItemIndex)
*/
private func builderAtIndexPath(indexPath: NSIndexPath) -> (RowBuilder, Int) {
-
return sections[indexPath.section].builderAtIndex(indexPath.row)!
}
+ // MARK: Public
+
public func invokeAction(action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath) -> AnyObject? {
let builder = builderAtIndexPath(indexPath)
return builder.0.invokeAction(action, cell: cell, indexPath: indexPath, itemIndex: builder.1, userInfo: nil)
}
-
- internal func didReceiveAction(notification: NSNotification) {
-
- if let action = notification.object as? Action, indexPath = tableView.indexPathForCell(action.cell) {
-
- let builder = builderAtIndexPath(indexPath)
- builder.0.invokeAction(.custom(action.key), cell: action.cell, indexPath: indexPath, itemIndex: builder.1, userInfo: action.userInfo)
- }
- }
public override func respondsToSelector(selector: Selector) -> Bool {
return super.respondsToSelector(selector) || scrollDelegate?.respondsToSelector(selector) == true
@@ -82,19 +74,28 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
public override func forwardingTargetForSelector(selector: Selector) -> AnyObject? {
return scrollDelegate?.respondsToSelector(selector) == true ? scrollDelegate : super.forwardingTargetForSelector(selector)
}
+
+ // MARK: Internal
+
+ func didReceiveAction(notification: NSNotification) {
+
+ if let action = notification.object as? Action, indexPath = tableView.indexPathForCell(action.cell) {
+
+ let builder = builderAtIndexPath(indexPath)
+ builder.0.invokeAction(.custom(action.key), cell: action.cell, indexPath: indexPath, itemIndex: builder.1, userInfo: notification.userInfo)
+ }
+ }
}
public extension TableDirector {
-
+
// MARK: UITableViewDataSource - configuration
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
-
return sections.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
-
return sections[section].numberOfRowsInSection
}
@@ -120,34 +121,28 @@ public extension TableDirector {
// MARK: UITableViewDataSource - section setup
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
-
return sections[section].headerTitle
}
func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? {
-
return sections[section].footerTitle
}
// MARK: UITableViewDelegate - section setup
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
-
return sections[section].headerView
}
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
-
return sections[section].footerView
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
-
return sections[section].headerHeight
}
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
-
return sections[section].footerHeight
}
}
@@ -157,19 +152,17 @@ public extension TableDirector {
// MARK: UITableViewDelegate - actions
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
-
- return builderAtIndexPath(indexPath).0.estimatedRowHeight
+ return CGFloat(builderAtIndexPath(indexPath).0.estimatedRowHeight)
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
-
return invokeAction(.height, cell: nil, indexPath: indexPath) as? CGFloat ?? UITableViewAutomaticDimension
}
- func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
+ /*func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
- return invokeAction(.willSelect, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath) as? NSIndexPath ?? indexPath
- }
+ return invokeAction(.willSelect, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath) as? NSIndexPath
+ }*/
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
@@ -183,17 +176,14 @@ public extension TableDirector {
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
-
invokeAction(.deselect, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath)
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
-
invokeAction(.willDisplay, cell: cell, indexPath: indexPath)
}
func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
-
return invokeAction(.shouldHighlight, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath) as? Bool ?? true
}
}
@@ -218,21 +208,17 @@ public extension TableDirector {
}
public func +=(left: TableDirector, right: RowBuilder) {
-
- left.appendSection(TableSectionBuilder(rowBuilders: [right]))
+ left.appendSection(TableSectionBuilder(rows: [right]))
}
public func +=(left: TableDirector, right: [RowBuilder]) {
-
- left.appendSection(TableSectionBuilder(rowBuilders: right))
+ left.appendSection(TableSectionBuilder(rows: right))
}
public func +=(left: TableDirector, right: TableSectionBuilder) {
-
left.appendSection(right)
}
public func +=(left: TableDirector, right: [TableSectionBuilder]) {
-
left.appendSections(right)
}
\ No newline at end of file
diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift
index 6a77c5c..fed1d6a 100644
--- a/Tablet/TableRowBuilder.swift
+++ b/Tablet/TableRowBuilder.swift
@@ -23,13 +23,13 @@ import Foundation
public typealias ReturnValue = AnyObject?
-internal enum ActionHandler {
-
+enum ActionHandler {
+
case actionBlock((data: ActionData) -> Void)
case actionReturnBlock((data: ActionData) -> AnyObject?)
func invoke(data: ActionData) -> ReturnValue {
-
+
switch (self) {
case .actionBlock(let closure):
closure(data: data)
@@ -40,33 +40,50 @@ internal enum ActionHandler {
}
}
-/**
- Responsible for building cells of given type and passing items to them.
-*/
-public class TableRowBuilder : RowBuilder {
-
- private var actions = Dictionary>()
- private var items = [I]()
-
- public var reusableIdentifier: String
- public var estimatedRowHeight: CGFloat
+public class RowBuilder : NSObject {
+
+ public private(set) var reusableIdentifier: String
public var numberOfRows: Int {
- get {
- return items.count
- }
+ return 0
+ }
+ public var estimatedRowHeight: Float {
+ return 44
}
- public init(item: I, id: String? = nil, estimatedRowHeight: CGFloat = 48) {
+ init(id: String) {
+ reusableIdentifier = id
+ }
+
+ // MARK: internal methods, must be overriden in subclass
+
+ func invokeAction(actionType: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? {
+ return nil
+ }
+
+ func registerCell(inTableView tableView: UITableView) {
+ }
+}
+
+/**
+ Responsible for building cells of given type and passing items to them.
+ */
+public class TableRowBuilder : RowBuilder {
+
+ private var actions = Dictionary>()
+ private var items = [I]()
+
+ public override var numberOfRows: Int {
+ return items.count
+ }
+
+ public init(item: I, id: String? = nil) {
+ super.init(id: id ?? NSStringFromClass(C).componentsSeparatedByString(".").last ?? "")
- reusableIdentifier = id ?? NSStringFromClass(C).componentsSeparatedByString(".").last ?? ""
- self.estimatedRowHeight = estimatedRowHeight
items.append(item)
}
- public init(items: [I]? = nil, id: String? = nil, estimatedRowHeight: CGFloat = 48) {
-
- reusableIdentifier = id ?? NSStringFromClass(C).componentsSeparatedByString(".").last ?? ""
- self.estimatedRowHeight = estimatedRowHeight
+ public init(items: [I]? = nil, id: String? = nil) {
+ super.init(id: id ?? NSStringFromClass(C).componentsSeparatedByString(".").last ?? "")
if items != nil {
self.items.appendContentsOf(items!)
@@ -74,101 +91,101 @@ public class TableRowBuilder : RowBuilder {
}
// MARK: Chaining actions
-
+
public func action(key: String, closure: (data: ActionData) -> Void) -> Self {
-
+
actions[key] = .actionBlock(closure)
return self
}
public func action(actionType: ActionType, closure: (data: ActionData) -> Void) -> Self {
-
+
actions[actionType.key] = .actionBlock(closure)
return self
}
public func action(actionType: ActionType, closure: (data: ActionData) -> ReturnValue) -> Self {
-
+
actions[actionType.key] = .actionReturnBlock(closure)
return self
}
- // MARK: Triggers
+ // MARK: Internal
- public func invokeAction(actionType: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]? = nil) -> AnyObject? {
-
+ override func invokeAction(actionType: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? {
+
if let action = actions[actionType.key] {
- return action.invoke(ActionData(cell: cell as? C, indexPath: indexPath, item: items[itemIndex], itemIndex: itemIndex))
+ return action.invoke(ActionData(cell: cell as? C, indexPath: indexPath, item: items[itemIndex], itemIndex: itemIndex, userInfo: userInfo))
}
return nil
}
-
- public func registerCell(inTableView tableView: UITableView) {
-
+
+ override func registerCell(inTableView tableView: UITableView) {
+
if tableView.dequeueReusableCellWithIdentifier(reusableIdentifier) != nil {
return
}
-
+
guard let resource = NSStringFromClass(C).componentsSeparatedByString(".").last else { return }
-
+
let bundle = NSBundle(forClass: C.self)
if let _ = bundle.pathForResource(resource, ofType: "nib") { // existing cell
-
+
tableView.registerNib(UINib(nibName: resource, bundle: bundle), forCellReuseIdentifier: reusableIdentifier)
} else {
-
+
tableView.registerClass(C.self, forCellReuseIdentifier: reusableIdentifier)
}
}
}
/**
- Responsible for building configurable cells of given type and passing items to them.
-*/
+ Responsible for building configurable cells of given type and passing items to them.
+ */
public class TableConfigurableRowBuilder : TableRowBuilder {
-
- public init(item: I, estimatedRowHeight: CGFloat = 48) {
- super.init(item: item, id: C.reusableIdentifier(), estimatedRowHeight: estimatedRowHeight)
+
+ public override var estimatedRowHeight: Float {
+ return C.estimatedHeight()
}
-
- public init(items: [I]? = nil, estimatedRowHeight: CGFloat = 48) {
- super.init(items: items, id: C.reusableIdentifier(), estimatedRowHeight: estimatedRowHeight)
+
+ public init(item: I) {
+ super.init(item: item, id: C.reusableIdentifier())
}
-
- public override func invokeAction(actionType: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]? = nil) -> AnyObject? {
-
+
+ public init(items: [I]? = nil) {
+ super.init(items: items, id: C.reusableIdentifier())
+ }
+
+ override func invokeAction(actionType: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? {
+
switch actionType {
case .configure:
(cell as? C)?.configureWithItem(items[itemIndex])
default: break
}
- return super.invokeAction(actionType, cell: cell, indexPath: indexPath, itemIndex: itemIndex)
+ return super.invokeAction(actionType, cell: cell, indexPath: indexPath, itemIndex: itemIndex, userInfo: userInfo)
}
}
public extension TableRowBuilder {
-
+
// MARK: Items manipulation
public func appendItems(items: [I]) {
-
self.items.appendContentsOf(items)
}
public func clear() {
-
items.removeAll()
}
}
public func +=(left: TableRowBuilder, right: I) {
-
left.appendItems([right])
}
public func +=(left: TableRowBuilder, right: [I]) {
-
left.appendItems(right)
}
\ No newline at end of file
diff --git a/Tablet/TableSectionBuilder.swift b/Tablet/TableSectionBuilder.swift
index 5912ff0..57a2f3b 100644
--- a/Tablet/TableSectionBuilder.swift
+++ b/Tablet/TableSectionBuilder.swift
@@ -27,7 +27,7 @@ import Foundation
*/
public class TableSectionBuilder {
- internal weak var tableView: UITableView?
+ weak var tableView: UITableView?
private var builders = [RowBuilder]()
public var headerTitle: String?
@@ -38,19 +38,18 @@ public class TableSectionBuilder {
public var footerView: UIView?
public var footerHeight: CGFloat = UITableViewAutomaticDimension
-
+
/// A total number of rows in section of each row builder.
public var numberOfRowsInSection: Int {
-
return builders.reduce(0) { $0 + $1.numberOfRows }
}
- public init(headerTitle: String? = nil, footerTitle: String? = nil, rowBuilders: [RowBuilder]? = nil) {
+ public init(headerTitle: String? = nil, footerTitle: String? = nil, rows: [RowBuilder]? = nil) {
self.headerTitle = headerTitle
self.footerTitle = footerTitle
- if let initialRows = rowBuilders {
+ if let initialRows = rows {
builders.appendContentsOf(initialRows)
}
}
@@ -63,11 +62,26 @@ public class TableSectionBuilder {
self.footerView = footerView
self.footerHeight = footerHeight
}
-}
-internal extension TableSectionBuilder {
+ // MARK: Public
+
+ public func clear() {
+ builders.removeAll()
+ }
- internal func builderAtIndex(var index: Int) -> (RowBuilder, Int)? {
+ public func appendRow(row: RowBuilder) {
+ appendRows([row])
+ }
+
+ public func appendRows(rowBuilders: [RowBuilder]) {
+
+ if let tableView = tableView { rowBuilders.forEach { $0.registerCell(inTableView: tableView) } }
+ builders.appendContentsOf(rowBuilders)
+ }
+
+ // MARK: Internal
+
+ func builderAtIndex(var index: Int) -> (RowBuilder, Int)? {
for builder in builders {
if index < builder.numberOfRows {
@@ -78,38 +92,18 @@ internal extension TableSectionBuilder {
return nil
}
+
+ func willMoveToDirector(tableView: UITableView) {
- internal func willMoveToDirector(tableView: UITableView) {
self.tableView = tableView
self.builders.forEach { $0.registerCell(inTableView: tableView) }
}
}
-public extension TableSectionBuilder {
-
- public func clear() {
-
- builders.removeAll()
- }
-
- public func appendRowBuilder(rowBuilder: RowBuilder) {
-
- appendRowBuilders([rowBuilder])
- }
-
- public func appendRowBuilders(rowBuilders: [RowBuilder]) {
-
- if let tableView = tableView { rowBuilders.forEach { $0.registerCell(inTableView: tableView) } }
- builders.appendContentsOf(rowBuilders)
- }
-}
-
public func +=(left: TableSectionBuilder, right: RowBuilder) {
-
- left.appendRowBuilder(right)
+ left.appendRow(right)
}
public func +=(left: TableSectionBuilder, right: [RowBuilder]) {
-
- left.appendRowBuilders(right)
+ left.appendRows(right)
}
\ No newline at end of file
diff --git a/Tablet/Tablet.h b/Tablet/Tablet.h
new file mode 100644
index 0000000..c09efa2
--- /dev/null
+++ b/Tablet/Tablet.h
@@ -0,0 +1,24 @@
+//
+// 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 Foundation;
+
+FOUNDATION_EXPORT double TabletVersionNumber;
+FOUNDATION_EXPORT const unsigned char TabletVersionString[];
\ No newline at end of file
diff --git a/Tablet/Tablet.swift b/Tablet/Tablet.swift
index ce40387..0cfc919 100644
--- a/Tablet/Tablet.swift
+++ b/Tablet/Tablet.swift
@@ -21,7 +21,9 @@
import UIKit
import Foundation
-internal let kActionPerformedNotificationKey = "_action"
+struct TabletNotifications {
+ static let CellAction = "TabletNotificationsCellAction"
+}
/**
The actions that Tablet provides.
@@ -55,13 +57,15 @@ public class ActionData {
public let item: I
public let itemIndex: Int
public let indexPath: NSIndexPath
-
- init(cell: C?, indexPath: NSIndexPath, item: I, itemIndex: Int) {
-
+ public let userInfo: [NSObject: AnyObject]?
+
+ init(cell: C?, indexPath: NSIndexPath, item: I, itemIndex: Int, userInfo: [NSObject: AnyObject]?) {
+
self.cell = cell
self.indexPath = indexPath
self.item = item
self.itemIndex = itemIndex
+ self.userInfo = userInfo
}
}
@@ -88,8 +92,7 @@ public class Action {
}
public func invoke() {
-
- NSNotificationCenter.defaultCenter().postNotificationName(kActionPerformedNotificationKey, object: self)
+ NSNotificationCenter.defaultCenter().postNotificationName(TabletNotifications.CellAction, object: self, userInfo: userInfo)
}
}
@@ -102,27 +105,13 @@ public protocol ConfigurableCell {
typealias Item
static func reusableIdentifier() -> String
+ static func estimatedHeight() -> Float
func configureWithItem(item: Item)
}
public extension ConfigurableCell where Self: UITableViewCell {
static func reusableIdentifier() -> String {
-
return NSStringFromClass(self).componentsSeparatedByString(".").last ?? ""
}
-}
-
-/**
- A protocol that every row builder should follow.
- A certain section can only works with row builders that respect this protocol.
-*/
-public protocol RowBuilder {
-
- var numberOfRows: Int { get }
- var reusableIdentifier: String { get }
- var estimatedRowHeight: CGFloat { get }
-
- func registerCell(inTableView tableView: UITableView)
- func invokeAction(actionType: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject?
}
\ No newline at end of file
diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..49ea0b1
--- /dev/null
+++ b/Tablet/Tablet.xcodeproj/project.pbxproj
@@ -0,0 +1,423 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 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 */; };
+ 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 */
+
+/* Begin PBXContainerItemProxy section */
+ DAC2D6751C9D743D009E9C19 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = DAC2D6601C9D743D009E9C19 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DAC2D6681C9D743D009E9C19;
+ remoteInfo = Tablet;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 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 = ""; };
+ 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 = ""; };
+ 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 = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ DAC2D6651C9D743D009E9C19 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DAC2D6701C9D743D009E9C19 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DAC2D6741C9D743D009E9C19 /* Tablet.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ DAC2D65F1C9D743D009E9C19 = {
+ isa = PBXGroup;
+ children = (
+ DAC2D68B1C9D7990009E9C19 /* Classes */,
+ DAC2D6941C9D7A03009E9C19 /* Tests */,
+ DAC2D6831C9D74EE009E9C19 /* Supporting Files */,
+ DAC2D66A1C9D743D009E9C19 /* Products */,
+ );
+ sourceTree = "";
+ };
+ DAC2D66A1C9D743D009E9C19 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ DAC2D6691C9D743D009E9C19 /* Tablet.framework */,
+ DAC2D6731C9D743D009E9C19 /* TabletTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ DAC2D6831C9D74EE009E9C19 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ DAC2D6841C9D7517009E9C19 /* Info.plist */,
+ DAC2D6851C9D7517009E9C19 /* Tablet.h */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ DAC2D68B1C9D7990009E9C19 /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ DAC2D68F1C9D799E009E9C19 /* Tablet.swift */,
+ DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */,
+ DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */,
+ DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */,
+ );
+ name = Classes;
+ sourceTree = "";
+ };
+ DAC2D6941C9D7A03009E9C19 /* Tests */ = {
+ isa = PBXGroup;
+ children = (
+ DAC2D6951C9D7A3B009E9C19 /* Info.plist */,
+ DAC2D6961C9D7A3B009E9C19 /* TabletTests.swift */,
+ );
+ name = Tests;
+ path = ../Tests;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ DAC2D6661C9D743D009E9C19 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DAC2D6871C9D7517009E9C19 /* Tablet.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ DAC2D6681C9D743D009E9C19 /* Tablet */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DAC2D67D1C9D743D009E9C19 /* Build configuration list for PBXNativeTarget "Tablet" */;
+ buildPhases = (
+ DAC2D6641C9D743D009E9C19 /* Sources */,
+ DAC2D6651C9D743D009E9C19 /* Frameworks */,
+ DAC2D6661C9D743D009E9C19 /* Headers */,
+ DAC2D6671C9D743D009E9C19 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Tablet;
+ productName = Tablet;
+ productReference = DAC2D6691C9D743D009E9C19 /* Tablet.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ DAC2D6721C9D743D009E9C19 /* TabletTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DAC2D6801C9D743D009E9C19 /* Build configuration list for PBXNativeTarget "TabletTests" */;
+ buildPhases = (
+ DAC2D66F1C9D743D009E9C19 /* Sources */,
+ DAC2D6701C9D743D009E9C19 /* Frameworks */,
+ DAC2D6711C9D743D009E9C19 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ DAC2D6761C9D743D009E9C19 /* PBXTargetDependency */,
+ );
+ name = TabletTests;
+ productName = TabletTests;
+ productReference = DAC2D6731C9D743D009E9C19 /* TabletTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ DAC2D6601C9D743D009E9C19 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastSwiftUpdateCheck = 0720;
+ LastUpgradeCheck = 0720;
+ ORGANIZATIONNAME = Tablet;
+ TargetAttributes = {
+ DAC2D6681C9D743D009E9C19 = {
+ CreatedOnToolsVersion = 7.2;
+ };
+ DAC2D6721C9D743D009E9C19 = {
+ CreatedOnToolsVersion = 7.2;
+ };
+ };
+ };
+ buildConfigurationList = DAC2D6631C9D743D009E9C19 /* Build configuration list for PBXProject "Tablet" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = DAC2D65F1C9D743D009E9C19;
+ productRefGroup = DAC2D66A1C9D743D009E9C19 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ DAC2D6681C9D743D009E9C19 /* Tablet */,
+ DAC2D6721C9D743D009E9C19 /* TabletTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ DAC2D6671C9D743D009E9C19 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DAC2D6711C9D743D009E9C19 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ DAC2D6641C9D743D009E9C19 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */,
+ DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */,
+ DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */,
+ DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DAC2D66F1C9D743D009E9C19 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DAC2D6991C9D7A3F009E9C19 /* TabletTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ DAC2D6761C9D743D009E9C19 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DAC2D6681C9D743D009E9C19 /* Tablet */;
+ targetProxy = DAC2D6751C9D743D009E9C19 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ DAC2D67B1C9D743D009E9C19 /* 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;
+ 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 = 8.0;
+ 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;
+ };
+ DAC2D67C1C9D743D009E9C19 /* 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;
+ 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 = 8.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ DAC2D67E1C9D743D009E9C19 /* 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 = 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.tablet.tablet;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ DAC2D67F1C9D743D009E9C19 /* 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 = 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.tablet.tablet;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ };
+ name = Release;
+ };
+ DAC2D6811C9D743D009E9C19 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INFOPLIST_FILE = ../Tests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.tablet.tablet.TabletTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ DAC2D6821C9D743D009E9C19 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INFOPLIST_FILE = ../Tests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.tablet.tablet.TabletTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ DAC2D6631C9D743D009E9C19 /* Build configuration list for PBXProject "Tablet" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DAC2D67B1C9D743D009E9C19 /* Debug */,
+ DAC2D67C1C9D743D009E9C19 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ DAC2D67D1C9D743D009E9C19 /* Build configuration list for PBXNativeTarget "Tablet" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DAC2D67E1C9D743D009E9C19 /* Debug */,
+ DAC2D67F1C9D743D009E9C19 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ DAC2D6801C9D743D009E9C19 /* Build configuration list for PBXNativeTarget "TabletTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DAC2D6811C9D743D009E9C19 /* Debug */,
+ DAC2D6821C9D743D009E9C19 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = DAC2D6601C9D743D009E9C19 /* Project object */;
+}
diff --git a/Tablet/Tablet.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Tablet/Tablet.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..78fd6b2
--- /dev/null
+++ b/Tablet/Tablet.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Tablet/Tablet.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate b/Tablet/Tablet.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..fbea635
Binary files /dev/null and b/Tablet/Tablet.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/Tablet/Tablet.xcodeproj/xcshareddata/xcschemes/Tablet.xcscheme b/Tablet/Tablet.xcodeproj/xcshareddata/xcschemes/Tablet.xcscheme
new file mode 100644
index 0000000..b6e3630
--- /dev/null
+++ b/Tablet/Tablet.xcodeproj/xcshareddata/xcschemes/Tablet.xcscheme
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..fe2b454
--- /dev/null
+++ b/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,5 @@
+
+
+
diff --git a/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist b/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..96dcbf8
--- /dev/null
+++ b/Tablet/Tablet.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ Tablet.xcscheme_^#shared#^_
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ DAC2D6681C9D743D009E9C19
+
+ primary
+
+
+ DAC2D6721C9D743D009E9C19
+
+ primary
+
+
+
+
+
diff --git a/TabletDemo/TabletDemo/AppDelegate.swift b/TabletDemo/Classes/Application/AppDelegate.swift
similarity index 100%
rename from TabletDemo/TabletDemo/AppDelegate.swift
rename to TabletDemo/Classes/Application/AppDelegate.swift
diff --git a/TabletDemo/Classes/Presentation/Main/ViewControllers/MainViewController.swift b/TabletDemo/Classes/Presentation/Main/ViewControllers/MainViewController.swift
new file mode 100644
index 0000000..3bb415a
--- /dev/null
+++ b/TabletDemo/Classes/Presentation/Main/ViewControllers/MainViewController.swift
@@ -0,0 +1,33 @@
+//
+// MainViewController.swift
+// TabletDemo
+//
+// Created by Max Sokolov on 19/03/16.
+// Copyright © 2016 Tablet. All rights reserved.
+//
+
+import Foundation
+import UIKit
+import Tablet
+
+class MainViewController : UITableViewController {
+
+ var tableDirector: TableDirector!
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ tableDirector = TableDirector(tableView: tableView)
+
+ tableDirector += TableRowBuilder(items: [1, 2, 3, 4], id: "cell")
+ .action(.configure) { data -> Void in
+
+ data.cell?.accessoryType = .DisclosureIndicator
+ data.cell?.textLabel?.text = "\(data.item)"
+ }
+ .action(.click) { data -> Void in
+
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/TabletDemo/TabletDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/TabletDemo/Resources/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json
similarity index 100%
rename from TabletDemo/TabletDemo/Assets.xcassets/AppIcon.appiconset/Contents.json
rename to TabletDemo/Resources/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json
diff --git a/TabletDemo/TabletDemo/Info.plist b/TabletDemo/Resources/Info.plist
similarity index 100%
rename from TabletDemo/TabletDemo/Info.plist
rename to TabletDemo/Resources/Info.plist
diff --git a/TabletDemo/TabletDemo/Base.lproj/LaunchScreen.storyboard b/TabletDemo/Resources/Storyboards/LaunchScreen.storyboard
similarity index 92%
rename from TabletDemo/TabletDemo/Base.lproj/LaunchScreen.storyboard
rename to TabletDemo/Resources/Storyboards/LaunchScreen.storyboard
index ffacbd6..c9b7564 100644
--- a/TabletDemo/TabletDemo/Base.lproj/LaunchScreen.storyboard
+++ b/TabletDemo/Resources/Storyboards/LaunchScreen.storyboard
@@ -1,8 +1,8 @@
-
+
-
+
@@ -16,7 +16,6 @@
-
diff --git a/TabletDemo/Resources/Storyboards/Main.storyboard b/TabletDemo/Resources/Storyboards/Main.storyboard
new file mode 100644
index 0000000..2cf7895
--- /dev/null
+++ b/TabletDemo/Resources/Storyboards/Main.storyboard
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj b/TabletDemo/TabletDemo.xcodeproj/project.pbxproj
index c043d8b..4d330c4 100644
--- a/TabletDemo/TabletDemo.xcodeproj/project.pbxproj
+++ b/TabletDemo/TabletDemo.xcodeproj/project.pbxproj
@@ -7,39 +7,21 @@
objects = {
/* Begin PBXBuildFile section */
- 508B71841BF48DD300272920 /* TableSectionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508B71831BF48DD300272920 /* TableSectionBuilder.swift */; };
- 508B71861BF48E0D00272920 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508B71851BF48E0D00272920 /* TableRowBuilder.swift */; };
- DA1BCD0F1BF5472C00CC0479 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA1BCD0E1BF5472C00CC0479 /* TableDirector.swift */; };
- DA1BCD111BF7388C00CC0479 /* CustomTableActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA1BCD101BF7388C00CC0479 /* CustomTableActions.swift */; };
- DAB7EB2B1BEF787300D2AD5E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB7EB2A1BEF787300D2AD5E /* AppDelegate.swift */; };
- DAB7EB2D1BEF787300D2AD5E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB7EB2C1BEF787300D2AD5E /* ViewController.swift */; };
- DAB7EB301BEF787300D2AD5E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAB7EB2E1BEF787300D2AD5E /* Main.storyboard */; };
- DAB7EB321BEF787300D2AD5E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DAB7EB311BEF787300D2AD5E /* Assets.xcassets */; };
- DAB7EB351BEF787300D2AD5E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAB7EB331BEF787300D2AD5E /* LaunchScreen.storyboard */; };
- DAB7EB3E1BEF78A400D2AD5E /* Tablet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB7EB3D1BEF78A400D2AD5E /* Tablet.swift */; };
- DAB7EB401BEFD07E00D2AD5E /* ConfigurableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB7EB3F1BEFD07E00D2AD5E /* ConfigurableTableViewCell.swift */; };
- DAED08F11C14DE7E006C04D8 /* MyTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAED08F01C14DE7E006C04D8 /* MyTableViewCell.swift */; };
- DAF003961C14DC0C0028C3D6 /* MyNibTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAF003951C14DC0C0028C3D6 /* MyNibTableViewCell.swift */; };
- DAF003981C14DC250028C3D6 /* MyNibTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DAF003971C14DC250028C3D6 /* MyNibTableViewCell.xib */; };
+ 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 */; };
+ DAC2D5D41C9D3118009E9C19 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D5D31C9D3118009E9C19 /* MainViewController.swift */; };
+ DAC2D69C1C9E75E3009E9C19 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DAC2D69B1C9E75E3009E9C19 /* Assets.xcassets */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
- 508B71831BF48DD300272920 /* TableSectionBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableSectionBuilder.swift; sourceTree = ""; };
- 508B71851BF48E0D00272920 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = ""; };
- DA1BCD0E1BF5472C00CC0479 /* TableDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDirector.swift; sourceTree = ""; };
- DA1BCD101BF7388C00CC0479 /* CustomTableActions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTableActions.swift; sourceTree = ""; };
DAB7EB271BEF787300D2AD5E /* TabletDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabletDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
- DAB7EB2A1BEF787300D2AD5E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
- DAB7EB2C1BEF787300D2AD5E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
- DAB7EB2F1BEF787300D2AD5E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
- DAB7EB311BEF787300D2AD5E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
- DAB7EB341BEF787300D2AD5E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
- DAB7EB361BEF787300D2AD5E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
- DAB7EB3D1BEF78A400D2AD5E /* Tablet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tablet.swift; sourceTree = ""; };
- DAB7EB3F1BEFD07E00D2AD5E /* ConfigurableTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableTableViewCell.swift; sourceTree = ""; };
- DAED08F01C14DE7E006C04D8 /* MyTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyTableViewCell.swift; sourceTree = ""; };
- DAF003951C14DC0C0028C3D6 /* MyNibTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyNibTableViewCell.swift; sourceTree = ""; };
- DAF003971C14DC250028C3D6 /* MyNibTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyNibTableViewCell.xib; sourceTree = ""; };
+ 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 = ""; };
+ DAC2D5D31C9D3118009E9C19 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; 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 = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -56,8 +38,8 @@
DAB7EB1E1BEF787300D2AD5E = {
isa = PBXGroup;
children = (
- DAB7EB3C1BEF789500D2AD5E /* Tablet */,
- DAB7EB291BEF787300D2AD5E /* TabletDemo */,
+ DAC2D5C61C9D2FE5009E9C19 /* Classes */,
+ DAC2D5CB1C9D3058009E9C19 /* Resources */,
DAB7EB281BEF787300D2AD5E /* Products */,
);
sourceTree = "";
@@ -70,34 +52,72 @@
name = Products;
sourceTree = "";
};
- DAB7EB291BEF787300D2AD5E /* TabletDemo */ = {
+ DAC2D5C61C9D2FE5009E9C19 /* Classes */ = {
isa = PBXGroup;
children = (
- DAB7EB2A1BEF787300D2AD5E /* AppDelegate.swift */,
- DAB7EB2C1BEF787300D2AD5E /* ViewController.swift */,
- DAB7EB3F1BEFD07E00D2AD5E /* ConfigurableTableViewCell.swift */,
- DA1BCD101BF7388C00CC0479 /* CustomTableActions.swift */,
- DAF003951C14DC0C0028C3D6 /* MyNibTableViewCell.swift */,
- DAF003971C14DC250028C3D6 /* MyNibTableViewCell.xib */,
- DAED08F01C14DE7E006C04D8 /* MyTableViewCell.swift */,
- DAB7EB2E1BEF787300D2AD5E /* Main.storyboard */,
- DAB7EB311BEF787300D2AD5E /* Assets.xcassets */,
- DAB7EB331BEF787300D2AD5E /* LaunchScreen.storyboard */,
- DAB7EB361BEF787300D2AD5E /* Info.plist */,
+ DAC2D5C81C9D3014009E9C19 /* Application */,
+ DAC2D5C71C9D3005009E9C19 /* Presentation */,
);
- path = TabletDemo;
+ path = Classes;
sourceTree = "";
};
- DAB7EB3C1BEF789500D2AD5E /* Tablet */ = {
+ DAC2D5C71C9D3005009E9C19 /* Presentation */ = {
isa = PBXGroup;
children = (
- DAB7EB3D1BEF78A400D2AD5E /* Tablet.swift */,
- DA1BCD0E1BF5472C00CC0479 /* TableDirector.swift */,
- 508B71851BF48E0D00272920 /* TableRowBuilder.swift */,
- 508B71831BF48DD300272920 /* TableSectionBuilder.swift */,
+ DAC2D5D11C9D30D8009E9C19 /* Main */,
);
- name = Tablet;
- path = ../Tablet;
+ 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 = "";
+ };
+ DAC2D5D11C9D30D8009E9C19 /* Main */ = {
+ isa = PBXGroup;
+ children = (
+ DAC2D5D21C9D30E4009E9C19 /* ViewControllers */,
+ );
+ path = Main;
+ sourceTree = "";
+ };
+ DAC2D5D21C9D30E4009E9C19 /* ViewControllers */ = {
+ isa = PBXGroup;
+ children = (
+ DAC2D5D31C9D3118009E9C19 /* MainViewController.swift */,
+ );
+ path = ViewControllers;
+ sourceTree = "";
+ };
+ DAC2D69A1C9E75BE009E9C19 /* Assets */ = {
+ isa = PBXGroup;
+ children = (
+ DAC2D69B1C9E75E3009E9C19 /* Assets.xcassets */,
+ );
+ path = Assets;
sourceTree = "";
};
/* End PBXGroup section */
@@ -126,6 +146,7 @@
DAB7EB1F1BEF787300D2AD5E /* Project object */ = {
isa = PBXProject;
attributes = {
+ LastSwiftUpdateCheck = 0720;
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = Tablet;
TargetAttributes = {
@@ -158,10 +179,9 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- DAB7EB351BEF787300D2AD5E /* LaunchScreen.storyboard in Resources */,
- DAF003981C14DC250028C3D6 /* MyNibTableViewCell.xib in Resources */,
- DAB7EB321BEF787300D2AD5E /* Assets.xcassets in Resources */,
- DAB7EB301BEF787300D2AD5E /* Main.storyboard in Resources */,
+ DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */,
+ DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */,
+ DAC2D69C1C9E75E3009E9C19 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -172,40 +192,13 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 508B71841BF48DD300272920 /* TableSectionBuilder.swift in Sources */,
- DAB7EB2D1BEF787300D2AD5E /* ViewController.swift in Sources */,
- DAB7EB3E1BEF78A400D2AD5E /* Tablet.swift in Sources */,
- DAED08F11C14DE7E006C04D8 /* MyTableViewCell.swift in Sources */,
- DAF003961C14DC0C0028C3D6 /* MyNibTableViewCell.swift in Sources */,
- 508B71861BF48E0D00272920 /* TableRowBuilder.swift in Sources */,
- DA1BCD0F1BF5472C00CC0479 /* TableDirector.swift in Sources */,
- DAB7EB401BEFD07E00D2AD5E /* ConfigurableTableViewCell.swift in Sources */,
- DAB7EB2B1BEF787300D2AD5E /* AppDelegate.swift in Sources */,
- DA1BCD111BF7388C00CC0479 /* CustomTableActions.swift in Sources */,
+ DAC2D5D41C9D3118009E9C19 /* MainViewController.swift in Sources */,
+ DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
-/* Begin PBXVariantGroup section */
- DAB7EB2E1BEF787300D2AD5E /* Main.storyboard */ = {
- isa = PBXVariantGroup;
- children = (
- DAB7EB2F1BEF787300D2AD5E /* Base */,
- );
- name = Main.storyboard;
- sourceTree = "";
- };
- DAB7EB331BEF787300D2AD5E /* LaunchScreen.storyboard */ = {
- isa = PBXVariantGroup;
- children = (
- DAB7EB341BEF787300D2AD5E /* Base */,
- );
- name = LaunchScreen.storyboard;
- sourceTree = "";
- };
-/* End PBXVariantGroup section */
-
/* Begin XCBuildConfiguration section */
DAB7EB371BEF787300D2AD5E /* Debug */ = {
isa = XCBuildConfiguration;
@@ -294,10 +287,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- INFOPLIST_FILE = TabletDemo/Info.plist;
+ INFOPLIST_FILE = Resources/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- PRODUCT_BUNDLE_IDENTIFIER = com.tablet.TabletDemo;
+ PRODUCT_BUNDLE_IDENTIFIER = com.tablet.tablet;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
};
@@ -309,10 +302,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- INFOPLIST_FILE = TabletDemo/Info.plist;
+ INFOPLIST_FILE = Resources/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- PRODUCT_BUNDLE_IDENTIFIER = com.tablet.TabletDemo;
+ PRODUCT_BUNDLE_IDENTIFIER = com.tablet.tablet;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
};
diff --git a/TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate b/TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate
index da29aef..6fe6130 100644
Binary files a/TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate and b/TabletDemo/TabletDemo.xcodeproj/project.xcworkspace/xcuserdata/maxsokolov.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/TabletDemo.xcscheme b/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/TabletDemo.xcscheme
index 6db4123..5b59ce8 100644
--- a/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/TabletDemo.xcscheme
+++ b/TabletDemo/TabletDemo.xcodeproj/xcuserdata/maxsokolov.xcuserdatad/xcschemes/TabletDemo.xcscheme
@@ -28,6 +28,16 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
+
+
+
+
primary
+ DAC2D5DB1C9D6433009E9C19
+
+ primary
+
+
diff --git a/TabletDemo/TabletDemo/Base.lproj/Main.storyboard b/TabletDemo/TabletDemo/Base.lproj/Main.storyboard
deleted file mode 100644
index 65ef436..0000000
--- a/TabletDemo/TabletDemo/Base.lproj/Main.storyboard
+++ /dev/null
@@ -1,130 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/TabletDemo/TabletDemo/ConfigurableTableViewCell.swift b/TabletDemo/TabletDemo/ConfigurableTableViewCell.swift
deleted file mode 100644
index 05da583..0000000
--- a/TabletDemo/TabletDemo/ConfigurableTableViewCell.swift
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// ConfigurableTableViewCell.swift
-// TabletDemo
-//
-// Created by Max Sokolov on 08/11/15.
-// Copyright © 2015 Tablet. All rights reserved.
-//
-
-import UIKit
-
-let kConfigurableTableViewCellButtonClickedAction = "button_clicked"
-
-class ConfigurableTableViewCell: UITableViewCell, ConfigurableCell {
-
- typealias Item = String
-
- @IBOutlet weak var button: UIButton!
- @IBOutlet weak var contentLabel: UILabel!
-
- static func reusableIdentifier() -> String {
-
- return "ConfigurableTableViewCell"
- }
-
- func configureWithItem(item: Item) {
-
- button.setTitle("Button \(item)", forState: .Normal)
- }
-
- @IBAction func buttonClicked(sender: UIButton) {
-
- Action(key: kConfigurableTableViewCellButtonClickedAction, sender: self).invoke()
- }
-}
\ No newline at end of file
diff --git a/TabletDemo/TabletDemo/CustomTableActions.swift b/TabletDemo/TabletDemo/CustomTableActions.swift
deleted file mode 100644
index 5466099..0000000
--- a/TabletDemo/TabletDemo/CustomTableActions.swift
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// CustomTableActions.swift
-// TabletDemo
-//
-// Created by Max Sokolov on 14/11/15.
-// Copyright © 2015 Tablet. All rights reserved.
-//
-
-import UIKit
-import Foundation
-
-let kTableDirectorDidEndDisplayingCell = "enddisplaycell"
-
-extension TableDirector {
-
- public func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
-
- invokeAction(.custom(kTableDirectorDidEndDisplayingCell), cell: cell, indexPath: indexPath)
- }
-}
\ No newline at end of file
diff --git a/TabletDemo/TabletDemo/MyNibTableViewCell.swift b/TabletDemo/TabletDemo/MyNibTableViewCell.swift
deleted file mode 100644
index 4888fb9..0000000
--- a/TabletDemo/TabletDemo/MyNibTableViewCell.swift
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// MyNibTableViewCell.swift
-// TabletDemo
-//
-// Created by Max Sokolov on 07/12/15.
-// Copyright © 2015 Tablet. All rights reserved.
-//
-
-import Foundation
-import UIKit
-
-class MyNibTableViewCell : UITableViewCell {
-
-
-}
\ No newline at end of file
diff --git a/TabletDemo/TabletDemo/MyNibTableViewCell.xib b/TabletDemo/TabletDemo/MyNibTableViewCell.xib
deleted file mode 100644
index 02401db..0000000
--- a/TabletDemo/TabletDemo/MyNibTableViewCell.xib
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/TabletDemo/TabletDemo/MyTableViewCell.swift b/TabletDemo/TabletDemo/MyTableViewCell.swift
deleted file mode 100644
index 9f03cea..0000000
--- a/TabletDemo/TabletDemo/MyTableViewCell.swift
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-// MyTableViewCell.swift
-// TabletDemo
-//
-// Created by Max Sokolov on 07/12/15.
-// Copyright © 2015 Tablet. All rights reserved.
-//
-
-import Foundation
-import UIKit
-
-class MyTableViewCell : UITableViewCell {
-
- override func layoutSubviews() {
- super.layoutSubviews()
-
- backgroundColor = UIColor.redColor()
- }
-}
\ No newline at end of file
diff --git a/TabletDemo/TabletDemo/ViewController.swift b/TabletDemo/TabletDemo/ViewController.swift
deleted file mode 100644
index 50d971f..0000000
--- a/TabletDemo/TabletDemo/ViewController.swift
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// ViewController.swift
-// TabletDemo
-//
-// Created by Max Sokolov on 08/11/15.
-// Copyright © 2015 Tablet. All rights reserved.
-//
-
-import UIKit
-
-class ViewController: UIViewController, UIScrollViewDelegate {
-
- @IBOutlet weak var tableView: UITableView!
- var tableDirector: TableDirector!
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- tableDirector = TableDirector(tableView: tableView)
- tableDirector.scrollDelegate = self
-
- let rowBuilder = TableRowBuilder(items: [1, 2, 3, 4], id: "cell", estimatedRowHeight: 44)
- .action(.configure) { data in
-
- data.cell?.textLabel?.text = "\(data.item)"
- }
- .action(.shouldHighlight) { data in
-
- return false
- }
- .action(kTableDirectorDidEndDisplayingCell) { data -> Void in
-
- print("end display: \(data.indexPath)")
- }
-
-
- let configurableRowBuilder = TableConfigurableRowBuilder(items: ["5", "6", "7", "8"], estimatedRowHeight: 300)
- .action(.click) { data -> Void in
-
- print("click action indexPath: \(data.indexPath), item: \(data.item)")
- }
- .action(kConfigurableTableViewCellButtonClickedAction) { data -> Void in
-
- print("custom action indexPath: \(data.indexPath), item: \(data.item)")
- }
- .action(.height) { data -> ReturnValue in
-
- if data.item == "5" {
- return 70
- }
- return nil
- }
- .action(.configure) { (data) -> Void in
-
- data.cell!.contentLabel.text = "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."
- }
-
- let myRowBuilder = TableRowBuilder(item: 0, id: "cellll", estimatedRowHeight: 44)
-
- let sectionBuilder = TableSectionBuilder(headerTitle: "Tablet", footerTitle: "Deal with table view like a boss.", rowBuilders: [rowBuilder, configurableRowBuilder, myRowBuilder])
-
- tableDirector += sectionBuilder
-
- sectionBuilder.appendRowBuilder(TableRowBuilder(item: 0, estimatedRowHeight: 44))
- }
-
- func scrollViewWillBeginDragging(scrollView: UIScrollView) {
- print("begin dragging")
- }
-}
\ No newline at end of file
diff --git a/Tests/Info.plist b/Tests/Info.plist
new file mode 100644
index 0000000..ba72822
--- /dev/null
+++ b/Tests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/Tests/TabletTests.swift b/Tests/TabletTests.swift
new file mode 100644
index 0000000..4d5c7b9
--- /dev/null
+++ b/Tests/TabletTests.swift
@@ -0,0 +1,200 @@
+//
+// 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 XCTest
+import Tablet
+
+class TestController: UITableViewController {
+
+ var tableDirector: TableDirector!
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ tableDirector = TableDirector(tableView: tableView)
+ }
+}
+
+struct TestData {
+
+ let title: String
+}
+
+struct TestTableViewCellOptions {
+
+ static let ReusableIdentifier: String = "ReusableIdentifier"
+ static let CellAction: String = "CellAction"
+ static let CellActionUserInfoKey: String = "CellActionUserInfoKey"
+ static let CellActionUserInfoValue: String = "CellActionUserInfoValue"
+ static let EstimatedHeight: Float = 255
+}
+
+class TestTableViewCell: UITableViewCell, ConfigurableCell {
+
+ typealias Item = TestData
+
+ static func reusableIdentifier() -> String {
+ return TestTableViewCellOptions.ReusableIdentifier
+ }
+
+ static func estimatedHeight() -> Float {
+ return TestTableViewCellOptions.EstimatedHeight
+ }
+
+ func configureWithItem(item: Item) {
+ textLabel?.text = item.title
+ }
+
+ func raiseAction() {
+ Action(key: TestTableViewCellOptions.CellAction, sender: self, userInfo: [TestTableViewCellOptions.CellActionUserInfoKey: TestTableViewCellOptions.CellActionUserInfoValue]).invoke()
+ }
+}
+
+class TabletTests: XCTestCase {
+
+ var testController: TestController!
+
+ override func setUp() {
+ super.setUp()
+
+ testController = TestController()
+ }
+
+ override func tearDown() {
+
+ testController = nil
+ super.tearDown()
+ }
+
+ func testTableDirectorHasTableView() {
+
+ XCTAssertNotNil(testController.tableView, "TestController should have table view")
+ XCTAssertNotNil(testController.tableDirector, "TestController should have table director")
+ XCTAssertNotNil(testController.tableDirector.tableView, "TableDirector should have table view")
+ }
+
+ func testSimpleRowBuilderCreatesRowsAndSection() {
+
+ let source = ["1", "2", "3"]
+
+ let rows = TableRowBuilder(items: source)
+ .action(.configure) { data -> Void in
+
+ XCTAssertNotNil(data.cell, "Action should have a cell")
+ data.cell?.textLabel?.text = "\(data.item)"
+ }
+
+ testController.view.hidden = false
+ testController.tableDirector += rows
+ testController.tableView.reloadData()
+
+ XCTAssertTrue(testController.tableView.dataSource?.numberOfSectionsInTableView?(testController.tableView) == 1, "Table view should have a section")
+ XCTAssertTrue(testController.tableView.dataSource?.tableView(testController.tableView, numberOfRowsInSection: 0) == source.count, "Table view should have certain number of rows in a section")
+
+ for (index, element) in source.enumerate() {
+
+ let cell = testController.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: index, inSection: 0))
+
+ XCTAssertNotNil(cell)
+ XCTAssertTrue(cell?.textLabel?.text == element)
+ }
+ }
+
+ func testConfigurableRowBuilderCreatesRowsAndSection() {
+
+ let testData = TestData(title: "title")
+
+ testController.view.hidden = false
+ testController.tableDirector += TableConfigurableRowBuilder(item: testData)
+ testController.tableView.reloadData()
+
+ let cell = testController.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0)) as? TestTableViewCell
+
+ XCTAssertNotNil(cell, "Cell should exists and should be TestTableViewCell")
+ XCTAssertTrue(cell?.textLabel?.text == testData.title, "Cell's textLabel.text should equal to testData's title")
+ }
+
+ func testSectionBuilderCreatesSectionWithHeaderAndFooterTitles() {
+
+ let row = TableConfigurableRowBuilder(items: [TestData(title: "title")])
+
+ let sectionHeaderTitle = "Header Title"
+ let sectionFooterTitle = "Footer Title"
+
+ let section = TableSectionBuilder(headerTitle: sectionHeaderTitle, footerTitle: sectionFooterTitle, rows: [row])
+
+ testController.view.hidden = false
+ testController.tableDirector += section
+ testController.tableView.reloadData()
+
+ XCTAssertTrue(testController.tableView.dataSource?.numberOfSectionsInTableView?(testController.tableView) == 1, "Table view should have a section")
+ XCTAssertTrue(testController.tableView.dataSource?.tableView(testController.tableView, numberOfRowsInSection: 0) == 1, "Table view should have certain number of rows in a section")
+
+ XCTAssertTrue(testController.tableView.dataSource?.tableView?(testController.tableView, titleForHeaderInSection: 0) == sectionHeaderTitle)
+ XCTAssertTrue(testController.tableView.dataSource?.tableView?(testController.tableView, titleForFooterInSection: 0) == sectionFooterTitle)
+ }
+
+ func testSectionBuilderCreatesSectionWithHeaderAndFooterViews() {
+
+ let row = TableConfigurableRowBuilder(items: [TestData(title: "title")])
+
+ let sectionHeaderView = UIView()
+ let sectionFooterView = UIView()
+
+ let section = TableSectionBuilder(headerView: sectionHeaderView, headerHeight: 44, footerView: sectionFooterView, footerHeight: 44)
+ section += row
+
+ testController.view.hidden = false
+ testController.tableDirector += section
+ testController.tableView.reloadData()
+
+ XCTAssertTrue(testController.tableView.dataSource?.numberOfSectionsInTableView?(testController.tableView) == 1, "Table view should have a section")
+ XCTAssertTrue(testController.tableView.dataSource?.tableView(testController.tableView, numberOfRowsInSection: 0) == 1, "Table view should have certain number of rows in a section")
+
+ XCTAssertTrue(testController.tableView.delegate?.tableView?(testController.tableView, viewForHeaderInSection: 0) == sectionHeaderView)
+ XCTAssertTrue(testController.tableView.delegate?.tableView?(testController.tableView, viewForFooterInSection: 0) == sectionFooterView)
+ }
+
+ func testRowBuilderCustomActionInvokedAndSentUserInfo() {
+
+ let expectation = expectationWithDescription("cell action")
+
+ let row = TableConfigurableRowBuilder(items: [TestData(title: "title")])
+ .action(TestTableViewCellOptions.CellAction) { data -> Void in
+
+ XCTAssertNotNil(data.cell, "Action data should have a cell")
+ XCTAssertNotNil(data.userInfo, "Action data should have a user info dictionary")
+ XCTAssertTrue(data.userInfo?[TestTableViewCellOptions.CellActionUserInfoKey] as? String == TestTableViewCellOptions.CellActionUserInfoValue, "UserInfo should have correct value for key")
+
+ expectation.fulfill()
+ }
+
+ testController.view.hidden = false
+ testController.tableDirector += row
+ testController.tableView.reloadData()
+
+ let cell = testController.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0)) as? TestTableViewCell
+
+ XCTAssertNotNil(cell, "Cell should exists and should be TestTableViewCell")
+
+ cell?.raiseAction()
+
+ waitForExpectationsWithTimeout(1.0, handler: nil)
+ }
+}
\ No newline at end of file