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
-
+
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
zcmZvAcVHC7`}fYy%=JJZce}ZgtH~wTTXJ^^B?Lk!38924C4>+#k`M?%n(=lhQWOOj
zK}3)wG(kYRib#`Qly1N-h@c_@0;1?|F9(Y6`^_IaH_tQknVHY?%skJNc|3S|E|{l6
z_$K~!zS;)f-_)TTM5<^)Po<~P)9D%X3-nBS7X2dq5?xO>&@1Sb^eTEay@r09UQ4f|
z-=R0sTj=fd`}BwOZu$Uyj6Or3rO(k{&|lJD(O2mo=xg+^^ey@}eFuu57)qcN%Ag!7
zU>sy&B2+^SG(#&)g%0S1VVDWCV5*uq
z;W#)EJ_l#P+3*#(0KN&A!j*6pTn*R3ci|@ZKKuagguCHa@H==J{s6DRpWzL73*LtJ
z;C=Wfe24&|kqC*A94SydYJpUUK^mk*24qB$WR!w@$d3Xj9koL_s6Fa{x}zSbC+dZY
zP;b-+^+m%_DH@K-&{$NB#-Rw}5J6MX%jgv}56wqQ(K7TFT8`d9>(K_Z5$!}DqFv|+
zI*N{=&c_9~FYbr?;{mt?kHQtW5|74Jcnltkr{L#sEq)%)!n5%l{33o0
zFT{)R68sk4h~LGV@MgRP@4z46o%ln%2cN*F@M(M=U%;2}=Q!?b{0+W>zsJ|{kN6k<
z3~UR&+|m*SY4IoAMJ}29VoP_?OvE^|+7wS5I3*)J-D&juLm9OLrlk8a8h(}mpy%&f
z^>jSuv0?)#;DIB+KeVd(dx~YM;&^64c|}E^F~du0%5uxA%Svmis<$kSyN#P>8Te%m
z(U$cI`(Zok2d;A+J(AnP^*%#MDH$cFpP?%#YaO+Q%dMl$+=_n{W9W&Lbu~SfuBOM)
zHS~D;S$YD$oK=D;Teh(nfZ6=cL~r-G^didoHvKaF3O$dWPrpj@^aA=ddLg%)+r#bU
z_Hp~UkGTWfLGIAoR5yAt{RX{6XqVEgD2#>ntng#U=O`d-~hDeM%K~$xvWpQ-mw`6L4E^$h(1go;ZAX9xeMIb
z$1{%8pHMC9K_TeQJ;RNvr$41nai_U6{EVcO9`t#-@juFo^d;^bcb>~0+$FbT$KmCI
zb#ki9N-XW>zeGj<9)o^OfA^nxm+33qXIvxyAStCeeVzW9vewf-(m!#RxX*dFz8mPs
zpR(pfjoXp_jeZz4)?NA@eV_iFen9_0|H*yDea(Htean5vUFNQ=rjqHuAq4@XA%uwQ
z$9+%0vjj{cU?u@?6R?&?hJB`Huq9<}fX!h%Y{6aSe&DV(zyzp-D(*S~ECCh#Rl_2e
z7V3q~Kpjlte&l|xhX!cmejz|Ccn?679AN4m5W^IX;)=MRc(0`^^Q7F~B)?G{pWWof
zIVNSA3;HSR3h0I&=!HJ+Cig3Mi@Uu724FhOfI;pK_XqbU0V007>BHPMFgt3lQCv+O
zY{&if$Xc)i$ghXFup@Vu`~4qF!Ok%MNm5|}?8e>W?(?(FA+{In^P~=3g#Ea=+ynkI
zv(+<*^4Gz^+(WL}SvZusL*1t2umlc+rEvIwab*?49V@RIO#sFH&HY6H77jU3`!pOC
zrKKD`LjWLvu7?${k^o2m;#XQyluz}JdTmW^S!Gp|H^Uk@o_}C5;s*FEoWS3=w9B3Z
zCsWqt%m2BCuoh1Jml+ach5*S5I1NsRGvEsZNC{|8Ks*5q*PCx{_C@Bvm;T{rE&;N~
z1kH;QG#|c7fSiE1e<^wmzWyW)0!43d_XtpM*_L+0hekd0v5UfGuW_HS!_c^Z8A4#p1!n?7ai8r+#FNJ@^dKN*~mH*2Y
z&wr7YETLk;6n>K;kLR-FQiNlYRKYvF{99HLY+o{tugcOXkSwOL6~|{aUBbn-1bOqA
z%uyWwj39IId+c%ip0p&sncW~)#&oXY_*_Bf=117g5_L@G;pf>$Nc6Fe@9|Q6y2B{9
z#Dsy^x!n9*MzD@&>;
zEgQ*?b)~?5Xi#)NEeE3^!o;BjbR-}zIDp&5Ej9&qi|u^-BcwAfRVd-Rsd|Gb)aZA23BANMI`{
zuoZ2dJnE}xQ4}Eib+lLjSVBN=0{TP&`aS|+`UX!An&MB-3<((C%qZgm;s0U04y}q}
zcvqt}0>)Yb`V%l9it$to!*OdU+cLHZZ+fNx5by^wg-!5Acd9}lWDo&^qr*G#T|7GY
z5!&B$q>s@70qqb0#RLqEs!JZB-D_;#s|n2)4u+!J5t=8DbON1@0{G6LvjTvCUrNC6
zCj1zHdcn-WZ}e~CBqRMFx4DGAj?QZN4f1dNQ%dYadHZ3taQzeM$YZ=zpg
zsKPrw>IqcGgVJSeY+J!l@E_Rw=z;LwqTdOqtV4egQ1zetj~`vj(fn3#n-&mbVJt=j
zjH$yS0><*RFWD#)UP~-I%GF%6bCjIAgPT#eadR9`-J>RB3M=_MpMf3EQ4#`#m^1DS
zW-u#+*=(GM)%_Hsd>5{C-HlHN|ON_g&a{xJ_@Qv
zKK9;%s?w5Z2y4J5Z03LSWwuDhR;pzkP9b1I9Zn@+BA@NI^m5`1s^uE&!fx!rUhKnu
z9Kga$IGKPc1UyH8;IGdU5FvmgfULnmDw*nrGjSGfgcP#kxECOZ|FsA|c!bQ>d{zU@TM4$ZIfvSS1K>kWR5D&tG@enLH
zif{vX0u~VeODyg*#MLR8<#^DJd<>^BKKHFBK2?>d?Z$&r#E;
z7paBRVrmJslv+;JQ!A)d)Ou