Compare commits
No commits in common. "master" and "2.6.0" have entirely different histories.
|
|
@ -1 +1 @@
|
||||||
5.7
|
4.0
|
||||||
14
.travis.yml
14
.travis.yml
|
|
@ -1,5 +1,5 @@
|
||||||
language: objective-c
|
language: objective-c
|
||||||
osx_image: xcode11
|
osx_image: xcode9
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
|
|
@ -7,15 +7,17 @@ env:
|
||||||
global:
|
global:
|
||||||
- LC_CTYPE=en_US.UTF-8
|
- LC_CTYPE=en_US.UTF-8
|
||||||
- LANG=en_US.UTF-8
|
- LANG=en_US.UTF-8
|
||||||
- IOS_SDK=iphonesimulator13.0
|
- IOS_SDK=iphonesimulator11.0
|
||||||
- SCHEME_IOS="TableKit"
|
- SCHEME_IOS="TableKit"
|
||||||
- PROJECT_FRAMEWORK="TableKit.xcodeproj"
|
- PROJECT_FRAMEWORK="TableKit.xcodeproj"
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
- DESTINATION="OS=10.3.1,name=iPhone 5" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
- DESTINATION="OS=9.0,name=iPhone 6" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||||
- DESTINATION="OS=11.1,name=iPhone 6" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
- DESTINATION="OS=9.1,name=iPhone 6 Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||||
- DESTINATION="OS=12.0,name=iPhone 7 Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
- DESTINATION="OS=9.2,name=iPhone 6S" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||||
- DESTINATION="OS=13.0,name=iPhone 11" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
- DESTINATION="OS=9.3,name=iPhone 6S Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||||
|
- DESTINATION="OS=10.0,name=iPhone 5" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||||
|
- DESTINATION="OS=10.0,name=iPhone 7 Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- set -o pipefail
|
- set -o pipefail
|
||||||
|
|
|
||||||
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -2,18 +2,6 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## [2.10.0](https://github.com/maxsokolov/TableKit/releases/tag/2.10.0)
|
|
||||||
Released on 2019-09-29.
|
|
||||||
- Swift 5.1 support.
|
|
||||||
|
|
||||||
## [2.9.0](https://github.com/maxsokolov/TableKit/releases/tag/2.9.0)
|
|
||||||
Released on 2019-04-04.
|
|
||||||
- Swift 5.0 support.
|
|
||||||
|
|
||||||
## [2.8.0](https://github.com/maxsokolov/TableKit/releases/tag/2.8.0)
|
|
||||||
Released on 2018-09-30.
|
|
||||||
- Swift 4.2 support.
|
|
||||||
|
|
||||||
## [2.5.0](https://github.com/maxsokolov/TableKit/releases/tag/2.5.0)
|
## [2.5.0](https://github.com/maxsokolov/TableKit/releases/tag/2.5.0)
|
||||||
Released on 2017-09-24.
|
Released on 2017-09-24.
|
||||||
- Swift 4.0 support.
|
- Swift 4.0 support.
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,6 @@ class AutolayoutCellsController: UIViewController {
|
||||||
view.setNeedsLayout()
|
view.setNeedsLayout()
|
||||||
view.layoutIfNeeded()
|
view.layoutIfNeeded()
|
||||||
|
|
||||||
return view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
|
return view.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -233,13 +233,13 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastSwiftUpdateCheck = 0720;
|
LastSwiftUpdateCheck = 0720;
|
||||||
LastUpgradeCheck = 1000;
|
LastUpgradeCheck = 0900;
|
||||||
ORGANIZATIONNAME = Tablet;
|
ORGANIZATIONNAME = Tablet;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
DAB7EB261BEF787300D2AD5E = {
|
DAB7EB261BEF787300D2AD5E = {
|
||||||
CreatedOnToolsVersion = 7.0.1;
|
CreatedOnToolsVersion = 7.0.1;
|
||||||
DevelopmentTeam = Z48R734SJX;
|
DevelopmentTeam = Z48R734SJX;
|
||||||
LastSwiftMigration = 1000;
|
LastSwiftMigration = 0800;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -248,7 +248,6 @@
|
||||||
developmentRegion = English;
|
developmentRegion = English;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
English,
|
|
||||||
en,
|
en,
|
||||||
Base,
|
Base,
|
||||||
);
|
);
|
||||||
|
|
@ -339,14 +338,12 @@
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
CLANG_WARN_COMMA = YES;
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
|
@ -378,7 +375,7 @@
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 4.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
|
@ -394,14 +391,12 @@
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
CLANG_WARN_COMMA = YES;
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
|
@ -426,7 +421,7 @@
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 4.0;
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
|
@ -444,7 +439,7 @@
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo;
|
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo;
|
||||||
PRODUCT_NAME = TableKitDemo;
|
PRODUCT_NAME = TableKitDemo;
|
||||||
PROVISIONING_PROFILE = "";
|
PROVISIONING_PROFILE = "";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 4.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
|
@ -461,7 +456,7 @@
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo;
|
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo;
|
||||||
PRODUCT_NAME = TableKitDemo;
|
PRODUCT_NAME = TableKitDemo;
|
||||||
PROVISIONING_PROFILE = "";
|
PROVISIONING_PROFILE = "";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 4.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
|
|
@ -1,19 +1,5 @@
|
||||||
// swift-tools-version:5.7
|
|
||||||
|
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "TableKit",
|
name: "TableKit"
|
||||||
|
|
||||||
products: [
|
|
||||||
.library(
|
|
||||||
name: "TableKit",
|
|
||||||
targets: ["TableKit"]),
|
|
||||||
],
|
|
||||||
|
|
||||||
targets: [
|
|
||||||
.target(
|
|
||||||
name: "TableKit",
|
|
||||||
path: "Sources")
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
<p align="left">
|
<p align="left">
|
||||||
<a href="https://travis-ci.org/maxsokolov/TableKit"><img src="https://api.travis-ci.org/maxsokolov/TableKit.svg" alt="Build Status" /></a>
|
<a href="https://travis-ci.org/maxsokolov/TableKit"><img src="https://api.travis-ci.org/maxsokolov/TableKit.svg" alt="Build Status" /></a>
|
||||||
<a href="https://developer.apple.com/swift"><img src="https://img.shields.io/badge/Swift_5.1-compatible-4BC51D.svg?style=flat" alt="Swift 5.1 compatible" /></a>
|
<a href="https://developer.apple.com/swift"><img src="https://img.shields.io/badge/Swift_4.0-compatible-4BC51D.svg?style=flat" alt="Swift 4.0 compatible" /></a>
|
||||||
<a href="https://github.com/Carthage/Carthage"><img src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat" alt="Carthage compatible" /></a>
|
<a href="https://github.com/Carthage/Carthage"><img src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat" alt="Carthage compatible" /></a>
|
||||||
<a href="https://cocoapods.org/pods/tablekit"><img src="https://img.shields.io/badge/pod-2.11.0-blue.svg" alt="CocoaPods compatible" /></a>
|
<a href="https://cocoapods.org/pods/tablekit"><img src="https://img.shields.io/badge/pod-2.6.0-blue.svg" alt="CocoaPods compatible" /></a>
|
||||||
<img src="https://img.shields.io/badge/platform-iOS-blue.svg?style=flat" alt="Platform iOS" />
|
<img src="https://img.shields.io/badge/platform-iOS-blue.svg?style=flat" alt="Platform iOS" />
|
||||||
<a href="https://raw.githubusercontent.com/maxsokolov/tablekit/master/LICENSE"><img src="http://img.shields.io/badge/license-MIT-blue.svg?style=flat" alt="License: MIT" /></a>
|
<a href="https://raw.githubusercontent.com/maxsokolov/tablekit/master/LICENSE"><img src="http://img.shields.io/badge/license-MIT-blue.svg?style=flat" alt="License: MIT" /></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -204,7 +204,7 @@ tableDirector += rows
|
||||||
Done, your table is ready.
|
Done, your table is ready.
|
||||||
## Automatic cell registration
|
## Automatic cell registration
|
||||||
|
|
||||||
TableKit can register your cells in a table view automatically. In case if your reusable cell id matches cell's xib name:
|
TableKit can register your cells in a table view automatically. In case if your reusable cell id mathces cell's xib name:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
MyTableViewCell.swift
|
MyTableViewCell.swift
|
||||||
|
|
@ -237,7 +237,7 @@ Clone the repo and drag files from `Sources` folder into your Xcode project.
|
||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
Keep an eye on [changes](CHANGELOG.md).
|
Keep eye on [changes](CHANGELOG.md).
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,18 +22,13 @@ import UIKit
|
||||||
|
|
||||||
public protocol ConfigurableCell {
|
public protocol ConfigurableCell {
|
||||||
|
|
||||||
associatedtype CellData
|
associatedtype T
|
||||||
|
|
||||||
static var reuseIdentifier: String { get }
|
static var reuseIdentifier: String { get }
|
||||||
|
|
||||||
static var estimatedHeight: CGFloat? { get }
|
static var estimatedHeight: CGFloat? { get }
|
||||||
|
|
||||||
static var defaultHeight: CGFloat? { get }
|
static var defaultHeight: CGFloat? { get }
|
||||||
|
|
||||||
static var layoutType: LayoutType { get }
|
func configure(with _: T)
|
||||||
|
|
||||||
func configure(with _: CellData)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension ConfigurableCell where Self: UITableViewCell {
|
public extension ConfigurableCell where Self: UITableViewCell {
|
||||||
|
|
@ -49,9 +44,4 @@ public extension ConfigurableCell where Self: UITableViewCell {
|
||||||
static var defaultHeight: CGFloat? {
|
static var defaultHeight: CGFloat? {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
static var layoutType: LayoutType {
|
|
||||||
return .auto
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
import UIKit
|
|
||||||
|
|
||||||
public extension TimeInterval {
|
|
||||||
|
|
||||||
static let defaultExpandableAnimationDuration: TimeInterval = 0.3
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public protocol Expandable {
|
|
||||||
|
|
||||||
associatedtype ViewModelType: ExpandableCellViewModel
|
|
||||||
|
|
||||||
var viewModel: ViewModelType? { get }
|
|
||||||
|
|
||||||
func configure(state: ExpandableState)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Expandable where Self: UITableViewCell & ConfigurableCell {
|
|
||||||
|
|
||||||
public func initState() {
|
|
||||||
guard let viewModel = viewModel else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
changeState(expandableState: viewModel.expandableState)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func changeState(expandableState: ExpandableState) {
|
|
||||||
// layout to get right frames, frame of bottom subview can be used to get expanded height
|
|
||||||
setNeedsLayout()
|
|
||||||
layoutIfNeeded()
|
|
||||||
|
|
||||||
// apply changes
|
|
||||||
configure(state: expandableState)
|
|
||||||
layoutIfNeeded()
|
|
||||||
}
|
|
||||||
|
|
||||||
public func toggleState(animated: Bool = true,
|
|
||||||
animationDuration: TimeInterval = .defaultExpandableAnimationDuration) {
|
|
||||||
|
|
||||||
guard let viewModel = viewModel,
|
|
||||||
let stateIndex = viewModel.availableStates.firstIndex(where: { $0 == viewModel.expandableState }) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let targetState = stateIndex == viewModel.availableStates.count - 1
|
|
||||||
? viewModel.availableStates[0]
|
|
||||||
: viewModel.availableStates[stateIndex + 1]
|
|
||||||
|
|
||||||
transition(to: targetState,
|
|
||||||
animated: animated,
|
|
||||||
animationDuration: animationDuration)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func transition(to state: ExpandableState,
|
|
||||||
animated: Bool = true,
|
|
||||||
animationDuration: TimeInterval = .defaultExpandableAnimationDuration) {
|
|
||||||
|
|
||||||
guard let tableView = tableView,
|
|
||||||
let viewModel = viewModel,
|
|
||||||
viewModel.expandableState != state else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let contentOffset = tableView.contentOffset
|
|
||||||
|
|
||||||
if animated {
|
|
||||||
UIView.animate(withDuration: animationDuration,
|
|
||||||
animations: { [weak self] in
|
|
||||||
self?.applyChanges(expandableState: state)
|
|
||||||
}, completion: { _ in
|
|
||||||
viewModel.expandableState = state
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
applyChanges(expandableState: state)
|
|
||||||
viewModel.expandableState = state
|
|
||||||
}
|
|
||||||
|
|
||||||
tableView.beginUpdates()
|
|
||||||
tableView.endUpdates()
|
|
||||||
|
|
||||||
tableView.setContentOffset(contentOffset, animated: false)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func applyChanges(expandableState: ExpandableState) {
|
|
||||||
changeState(expandableState: expandableState)
|
|
||||||
|
|
||||||
if let indexPath = indexPath,
|
|
||||||
let tableDirector = (tableView?.delegate as? TableDirector),
|
|
||||||
let cellHeightCalculator = tableDirector.rowHeightCalculator as? ExpandableCellHeightCalculator {
|
|
||||||
cellHeightCalculator.updateCached(height: expandableState.height ?? height(layoutType: Self.layoutType), for: indexPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
import UIKit
|
|
||||||
|
|
||||||
public final class ExpandableCellHeightCalculator: RowHeightCalculator {
|
|
||||||
|
|
||||||
private weak var tableView: UITableView?
|
|
||||||
|
|
||||||
private var prototypes = [String: UITableViewCell]()
|
|
||||||
|
|
||||||
private var cachedHeights = [IndexPath: CGFloat]()
|
|
||||||
|
|
||||||
public init(tableView: UITableView?) {
|
|
||||||
self.tableView = tableView
|
|
||||||
}
|
|
||||||
|
|
||||||
public func updateCached(height: CGFloat, for indexPath: IndexPath) {
|
|
||||||
cachedHeights[indexPath] = height
|
|
||||||
}
|
|
||||||
|
|
||||||
public func height(forRow row: Row, at indexPath: IndexPath) -> CGFloat {
|
|
||||||
|
|
||||||
guard let tableView = tableView else {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if let height = cachedHeights[indexPath] {
|
|
||||||
return height
|
|
||||||
}
|
|
||||||
|
|
||||||
var prototypeCell = prototypes[row.reuseIdentifier]
|
|
||||||
if prototypeCell == nil {
|
|
||||||
prototypeCell = tableView.dequeueReusableCell(withIdentifier: row.reuseIdentifier)
|
|
||||||
prototypes[row.reuseIdentifier] = prototypeCell
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let cell = prototypeCell else {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
row.configure(cell)
|
|
||||||
cell.layoutIfNeeded()
|
|
||||||
|
|
||||||
let height = cell.height(layoutType: row.layoutType)
|
|
||||||
cachedHeights[indexPath] = height
|
|
||||||
return height
|
|
||||||
}
|
|
||||||
|
|
||||||
public func estimatedHeight(forRow row: Row, at indexPath: IndexPath) -> CGFloat {
|
|
||||||
return height(forRow: row, at: indexPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func invalidate() {
|
|
||||||
cachedHeights.removeAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
public protocol ExpandableCellViewModel: AnyObject {
|
|
||||||
|
|
||||||
var expandableState: ExpandableState { get set }
|
|
||||||
|
|
||||||
var availableStates: [ExpandableState] { get }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension ExpandableCellViewModel {
|
|
||||||
|
|
||||||
var availableStates: [ExpandableState] {
|
|
||||||
return [.collapsed, .expanded]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import UIKit
|
|
||||||
|
|
||||||
public enum ExpandableState {
|
|
||||||
|
|
||||||
case collapsed
|
|
||||||
|
|
||||||
case expanded
|
|
||||||
|
|
||||||
case height(value: CGFloat)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ExpandableState: Equatable { }
|
|
||||||
|
|
||||||
extension ExpandableState {
|
|
||||||
|
|
||||||
public var isCollapsed: Bool {
|
|
||||||
guard case .collapsed = self else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
public var isExpanded: Bool {
|
|
||||||
guard case .expanded = self else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
public var height: CGFloat? {
|
|
||||||
guard case let .height(value: height) = self else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return height
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
public enum LayoutType {
|
|
||||||
|
|
||||||
case manual
|
|
||||||
|
|
||||||
case auto
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -27,13 +27,13 @@ import UIKit
|
||||||
open class TableCellAction {
|
open class TableCellAction {
|
||||||
|
|
||||||
/// The cell that triggers an action.
|
/// The cell that triggers an action.
|
||||||
public let cell: UITableViewCell
|
open let cell: UITableViewCell
|
||||||
|
|
||||||
/// The action unique key.
|
/// The action unique key.
|
||||||
public let key: String
|
open let key: String
|
||||||
|
|
||||||
/// The custom user info.
|
/// The custom user info.
|
||||||
public let userInfo: [AnyHashable: Any]?
|
open let userInfo: [AnyHashable: Any]?
|
||||||
|
|
||||||
public init(key: String, sender: UITableViewCell, userInfo: [AnyHashable: Any]? = nil) {
|
public init(key: String, sender: UITableViewCell, userInfo: [AnyHashable: Any]? = nil) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,14 +95,6 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||||
tableView?.reloadData()
|
tableView?.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
|
||||||
private func row(at indexPath: IndexPath) -> Row? {
|
|
||||||
if indexPath.section < sections.count && indexPath.row < sections[indexPath.section].rows.count {
|
|
||||||
return sections[indexPath.section].rows[indexPath.row]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Public
|
// MARK: Public
|
||||||
@discardableResult
|
@discardableResult
|
||||||
open func invoke(
|
open func invoke(
|
||||||
|
|
@ -110,14 +102,16 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||||
cell: UITableViewCell?, indexPath: IndexPath,
|
cell: UITableViewCell?, indexPath: IndexPath,
|
||||||
userInfo: [AnyHashable: Any]? = nil) -> Any?
|
userInfo: [AnyHashable: Any]? = nil) -> Any?
|
||||||
{
|
{
|
||||||
guard let row = row(at: indexPath) else { return nil }
|
if indexPath.section < sections.count && indexPath.row < sections[indexPath.section].rows.count {
|
||||||
return row.invoke(
|
return sections[indexPath.section].rows[indexPath.row].invoke(
|
||||||
action: action,
|
action: action,
|
||||||
cell: cell,
|
cell: cell,
|
||||||
path: indexPath,
|
path: indexPath,
|
||||||
userInfo: userInfo
|
userInfo: userInfo
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
open override func responds(to selector: Selector) -> Bool {
|
open override func responds(to selector: Selector) -> Bool {
|
||||||
return super.responds(to: selector) || scrollDelegate?.responds(to: selector) == true
|
return super.responds(to: selector) || scrollDelegate?.responds(to: selector) == true
|
||||||
|
|
@ -131,8 +125,7 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||||
|
|
||||||
// MARK: - Internal
|
// MARK: - Internal
|
||||||
func hasAction(_ action: TableRowActionType, atIndexPath indexPath: IndexPath) -> Bool {
|
func hasAction(_ action: TableRowActionType, atIndexPath indexPath: IndexPath) -> Bool {
|
||||||
guard let row = row(at: indexPath) else { return false }
|
return sections[indexPath.section].rows[indexPath.row].has(action: action)
|
||||||
return row.has(action: action)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
|
|
@ -154,7 +147,7 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||||
return row.defaultHeight
|
return row.defaultHeight
|
||||||
?? row.estimatedHeight
|
?? row.estimatedHeight
|
||||||
?? rowHeightCalculator?.estimatedHeight(forRow: row, at: indexPath)
|
?? rowHeightCalculator?.estimatedHeight(forRow: row, at: indexPath)
|
||||||
?? UITableView.automaticDimension
|
?? UITableViewAutomaticDimension
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||||
|
|
@ -170,7 +163,7 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||||
return rowHeight
|
return rowHeight
|
||||||
?? row.defaultHeight
|
?? row.defaultHeight
|
||||||
?? rowHeightCalculator?.height(forRow: row, at: indexPath)
|
?? rowHeightCalculator?.height(forRow: row, at: indexPath)
|
||||||
?? UITableView.automaticDimension
|
?? UITableViewAutomaticDimension
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: UITableViewDataSource - configuration
|
// MARK: UITableViewDataSource - configuration
|
||||||
|
|
@ -179,8 +172,6 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
guard section < sections.count else { return 0 }
|
|
||||||
|
|
||||||
return sections[section].numberOfRows
|
return sections[section].numberOfRows
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,44 +196,34 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||||
|
|
||||||
// MARK: UITableViewDataSource - section setup
|
// MARK: UITableViewDataSource - section setup
|
||||||
open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||||
guard section < sections.count else { return nil }
|
|
||||||
|
|
||||||
return sections[section].headerTitle
|
return sections[section].headerTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
|
open func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
|
||||||
guard section < sections.count else { return nil }
|
|
||||||
|
|
||||||
return sections[section].footerTitle
|
return sections[section].footerTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: UITableViewDelegate - section setup
|
// MARK: UITableViewDelegate - section setup
|
||||||
open func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
open func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||||
guard section < sections.count else { return nil }
|
|
||||||
|
|
||||||
return sections[section].headerView
|
return sections[section].headerView
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
open func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
||||||
guard section < sections.count else { return nil }
|
|
||||||
|
|
||||||
return sections[section].footerView
|
return sections[section].footerView
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
open func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||||
guard section < sections.count else { return 0 }
|
|
||||||
|
|
||||||
let section = sections[section]
|
let section = sections[section]
|
||||||
return section.headerHeight ?? section.headerView?.frame.size.height ?? UITableView.automaticDimension
|
return section.headerHeight ?? section.headerView?.frame.size.height ?? UITableViewAutomaticDimension
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
|
open func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
|
||||||
guard section < sections.count else { return 0 }
|
|
||||||
|
|
||||||
let section = sections[section]
|
let section = sections[section]
|
||||||
return section.footerHeight
|
return section.footerHeight
|
||||||
?? section.footerView?.frame.size.height
|
?? section.footerView?.frame.size.height
|
||||||
?? UITableView.automaticDimension
|
?? UITableViewAutomaticDimension
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: UITableViewDataSource - Index
|
// MARK: UITableViewDataSource - Index
|
||||||
|
|
@ -276,6 +257,7 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||||
|
|
||||||
// MARK: UITableViewDelegate - actions
|
// MARK: UITableViewDelegate - actions
|
||||||
open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
|
||||||
let cell = tableView.cellForRow(at: indexPath)
|
let cell = tableView.cellForRow(at: indexPath)
|
||||||
|
|
||||||
if invoke(action: .click, cell: cell, indexPath: indexPath) != nil {
|
if invoke(action: .click, cell: cell, indexPath: indexPath) != nil {
|
||||||
|
|
@ -302,140 +284,67 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
open func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||||
|
|
||||||
if hasAction(.willSelect, atIndexPath: indexPath) {
|
if hasAction(.willSelect, atIndexPath: indexPath) {
|
||||||
return invoke(action: .willSelect, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? IndexPath
|
return invoke(action: .willSelect, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? IndexPath
|
||||||
}
|
}
|
||||||
|
|
||||||
return indexPath
|
return indexPath
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
|
|
||||||
if hasAction(.willDeselect, atIndexPath: indexPath) {
|
|
||||||
return invoke(action: .willDeselect, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? IndexPath
|
|
||||||
}
|
|
||||||
|
|
||||||
return indexPath
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 13.0, *)
|
|
||||||
open func tableView(
|
|
||||||
_ tableView: UITableView,
|
|
||||||
shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath) -> Bool
|
|
||||||
{
|
|
||||||
invoke(action: .shouldBeginMultipleSelection, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? Bool ?? false
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 13.0, *)
|
|
||||||
open func tableView(
|
|
||||||
_ tableView: UITableView,
|
|
||||||
didBeginMultipleSelectionInteractionAt indexPath: IndexPath)
|
|
||||||
{
|
|
||||||
invoke(action: .didBeginMultipleSelection, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 13.0, *)
|
|
||||||
open func tableView(
|
|
||||||
_ tableView: UITableView,
|
|
||||||
contextMenuConfigurationForRowAt indexPath: IndexPath,
|
|
||||||
point: CGPoint) -> UIContextMenuConfiguration?
|
|
||||||
{
|
|
||||||
invoke(action: .showContextMenu, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath, userInfo: [TableKitUserInfoKeys.ContextMenuInvokePoint: point]) as? UIContextMenuConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Row editing
|
// MARK: - Row editing
|
||||||
open func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
open func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
||||||
return sections[indexPath.section].rows[indexPath.row].isEditingAllowed(forIndexPath: indexPath)
|
return sections[indexPath.section].rows[indexPath.row].isEditingAllowed(forIndexPath: indexPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView,
|
open func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
|
||||||
leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
|
return sections[indexPath.section].rows[indexPath.row].editingActions
|
||||||
let currentRow = sections[indexPath.section].rows[indexPath.row]
|
|
||||||
let configuration = UISwipeActionsConfiguration(actions: currentRow.leadingContextualActions)
|
|
||||||
|
|
||||||
configuration.performsFirstActionWithFullSwipe = currentRow.performsFirstActionWithFullSwipe
|
|
||||||
|
|
||||||
return configuration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView,
|
open func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
|
||||||
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
|
|
||||||
let currentRow = sections[indexPath.section].rows[indexPath.row]
|
|
||||||
let configuration = UISwipeActionsConfiguration(actions: currentRow.trailingContextualActions)
|
|
||||||
|
|
||||||
configuration.performsFirstActionWithFullSwipe = currentRow.performsFirstActionWithFullSwipe
|
|
||||||
|
|
||||||
return configuration
|
|
||||||
}
|
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
|
|
||||||
if invoke(action: .canDelete, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? Bool ?? false {
|
|
||||||
return UITableViewCell.EditingStyle.delete
|
|
||||||
}
|
|
||||||
|
|
||||||
return UITableViewCell.EditingStyle.none
|
|
||||||
}
|
|
||||||
|
|
||||||
public func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
public func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
|
|
||||||
return invoke(action: .canMoveTo, cell: tableView.cellForRow(at: sourceIndexPath), indexPath: sourceIndexPath, userInfo: [TableKitUserInfoKeys.CellCanMoveProposedIndexPath: proposedDestinationIndexPath]) as? IndexPath ?? proposedDestinationIndexPath
|
|
||||||
}
|
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
|
||||||
if editingStyle == .delete {
|
if editingStyle == .delete {
|
||||||
invoke(action: .clickDelete, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath)
|
invoke(action: .clickDelete, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
|
|
||||||
return invoke(action: .canMove, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? Bool ?? false
|
|
||||||
}
|
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
|
open func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
|
||||||
invoke(action: .move, cell: tableView.cellForRow(at: sourceIndexPath), indexPath: sourceIndexPath, userInfo: [TableKitUserInfoKeys.CellMoveDestinationIndexPath: destinationIndexPath])
|
invoke(action: .move, cell: tableView.cellForRow(at: sourceIndexPath), indexPath: sourceIndexPath, userInfo: [TableKitUserInfoKeys.CellMoveDestinationIndexPath: destinationIndexPath])
|
||||||
}
|
}
|
||||||
|
|
||||||
open func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
|
||||||
let cell = tableView.cellForRow(at: indexPath)
|
|
||||||
invoke(action: .accessoryButtonTap, cell: cell, indexPath: indexPath)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Sections manipulation
|
// MARK: - Sections manipulation
|
||||||
extension TableDirector {
|
extension TableDirector {
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func append(section: TableSection) -> Self {
|
open func append(section: TableSection) -> Self {
|
||||||
|
|
||||||
append(sections: [section])
|
append(sections: [section])
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func append(sections: [TableSection]) -> Self {
|
open func append(sections: [TableSection]) -> Self {
|
||||||
|
|
||||||
self.sections.append(contentsOf: sections)
|
self.sections.append(contentsOf: sections)
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func append(rows: [Row]) -> Self {
|
open func append(rows: [Row]) -> Self {
|
||||||
|
|
||||||
append(section: TableSection(rows: rows))
|
append(section: TableSection(rows: rows))
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func insert(section: TableSection, atIndex index: Int) -> Self {
|
open func insert(section: TableSection, atIndex index: Int) -> Self {
|
||||||
|
|
||||||
sections.insert(section, at: index)
|
sections.insert(section, at: index)
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func replaceSection(at index: Int, with section: TableSection) -> Self {
|
open func replaceSection(at index: Int, with section: TableSection) -> Self {
|
||||||
|
|
||||||
if index < sections.count {
|
if index < sections.count {
|
||||||
sections[index] = section
|
sections[index] = section
|
||||||
|
|
@ -444,19 +353,19 @@ extension TableDirector {
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func delete(sectionAt index: Int) -> Self {
|
open func delete(sectionAt index: Int) -> Self {
|
||||||
|
|
||||||
sections.remove(at: index)
|
sections.remove(at: index)
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func remove(sectionAt index: Int) -> Self {
|
open func remove(sectionAt index: Int) -> Self {
|
||||||
return delete(sectionAt: index)
|
return delete(sectionAt: index)
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func clear() -> Self {
|
open func clear() -> Self {
|
||||||
|
|
||||||
rowHeightCalculator?.invalidate()
|
rowHeightCalculator?.invalidate()
|
||||||
sections.removeAll()
|
sections.removeAll()
|
||||||
|
|
@ -467,7 +376,7 @@ extension TableDirector {
|
||||||
// MARK: - deprecated methods
|
// MARK: - deprecated methods
|
||||||
@available(*, deprecated, message: "Use 'delete(sectionAt:)' method instead")
|
@available(*, deprecated, message: "Use 'delete(sectionAt:)' method instead")
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func delete(index: Int) -> Self {
|
open func delete(index: Int) -> Self {
|
||||||
|
|
||||||
sections.remove(at: index)
|
sections.remove(at: index)
|
||||||
return self
|
return self
|
||||||
|
|
|
||||||
|
|
@ -26,21 +26,16 @@ struct TableKitNotifications {
|
||||||
|
|
||||||
public struct TableKitUserInfoKeys {
|
public struct TableKitUserInfoKeys {
|
||||||
public static let CellMoveDestinationIndexPath = "TableKitCellMoveDestinationIndexPath"
|
public static let CellMoveDestinationIndexPath = "TableKitCellMoveDestinationIndexPath"
|
||||||
public static let CellCanMoveProposedIndexPath = "CellCanMoveProposedIndexPath"
|
|
||||||
public static let ContextMenuInvokePoint = "ContextMenuInvokePoint"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol RowConfigurable {
|
public protocol RowConfigurable {
|
||||||
|
|
||||||
func configure(_ cell: UITableViewCell)
|
func configure(_ cell: UITableViewCell)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol RowActionable {
|
public protocol RowActionable {
|
||||||
var leadingContextualActions: [UIContextualAction] { get }
|
|
||||||
var trailingContextualActions: [UIContextualAction] { get }
|
|
||||||
var performsFirstActionWithFullSwipe: Bool { get }
|
|
||||||
|
|
||||||
|
var editingActions: [UITableViewRowAction]? { get }
|
||||||
func isEditingAllowed(forIndexPath indexPath: IndexPath) -> Bool
|
func isEditingAllowed(forIndexPath indexPath: IndexPath) -> Bool
|
||||||
|
|
||||||
func invoke(
|
func invoke(
|
||||||
|
|
@ -62,7 +57,6 @@ public protocol Row: RowConfigurable, RowActionable, RowHashable {
|
||||||
var reuseIdentifier: String { get }
|
var reuseIdentifier: String { get }
|
||||||
var cellType: AnyClass { get }
|
var cellType: AnyClass { get }
|
||||||
|
|
||||||
var layoutType: LayoutType { get }
|
|
||||||
var estimatedHeight: CGFloat? { get }
|
var estimatedHeight: CGFloat? { get }
|
||||||
var defaultHeight: CGFloat? { get }
|
var defaultHeight: CGFloat? { get }
|
||||||
}
|
}
|
||||||
|
|
@ -74,21 +68,13 @@ public enum TableRowActionType {
|
||||||
case select
|
case select
|
||||||
case deselect
|
case deselect
|
||||||
case willSelect
|
case willSelect
|
||||||
case willDeselect
|
|
||||||
case willDisplay
|
case willDisplay
|
||||||
case didEndDisplaying
|
case didEndDisplaying
|
||||||
case shouldHighlight
|
case shouldHighlight
|
||||||
case shouldBeginMultipleSelection
|
|
||||||
case didBeginMultipleSelection
|
|
||||||
case height
|
case height
|
||||||
case canEdit
|
case canEdit
|
||||||
case configure
|
case configure
|
||||||
case canDelete
|
|
||||||
case canMove
|
|
||||||
case canMoveTo
|
|
||||||
case move
|
case move
|
||||||
case showContextMenu
|
|
||||||
case accessoryButtonTap
|
|
||||||
case custom(String)
|
case custom(String)
|
||||||
|
|
||||||
var key: String {
|
var key: String {
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ open class TablePrototypeCellHeightCalculator: RowHeightCalculator {
|
||||||
cell.setNeedsLayout()
|
cell.setNeedsLayout()
|
||||||
cell.layoutIfNeeded()
|
cell.layoutIfNeeded()
|
||||||
|
|
||||||
let height = cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height + (tableView.separatorStyle != .none ? separatorHeight : 0)
|
let height = cell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height + (tableView.separatorStyle != .none ? separatorHeight : 0)
|
||||||
|
|
||||||
cachedHeights[hash] = height
|
cachedHeights[hash] = height
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@ open class TablePrototypeCellHeightCalculator: RowHeightCalculator {
|
||||||
return estimatedHeight
|
return estimatedHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
return UITableView.automaticDimension
|
return UITableViewAutomaticDimension
|
||||||
}
|
}
|
||||||
|
|
||||||
open func invalidate() {
|
open func invalidate() {
|
||||||
|
|
|
||||||
|
|
@ -22,20 +22,9 @@ import UIKit
|
||||||
|
|
||||||
open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableViewCell {
|
open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableViewCell {
|
||||||
|
|
||||||
public let item: CellType.CellData
|
open let item: CellType.T
|
||||||
private lazy var actions = [String: [TableRowAction<CellType>]]()
|
private lazy var actions = [String: [TableRowAction<CellType>]]()
|
||||||
|
private(set) open var editingActions: [UITableViewRowAction]?
|
||||||
open var leadingContextualActions: [UIContextualAction] {
|
|
||||||
[]
|
|
||||||
}
|
|
||||||
|
|
||||||
open var trailingContextualActions: [UIContextualAction] {
|
|
||||||
[]
|
|
||||||
}
|
|
||||||
|
|
||||||
open var performsFirstActionWithFullSwipe: Bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
open var hashValue: Int {
|
open var hashValue: Int {
|
||||||
return ObjectIdentifier(self).hashValue
|
return ObjectIdentifier(self).hashValue
|
||||||
|
|
@ -53,19 +42,14 @@ open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableView
|
||||||
return CellType.defaultHeight
|
return CellType.defaultHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
open var layoutType: LayoutType {
|
|
||||||
return CellType.layoutType
|
|
||||||
}
|
|
||||||
|
|
||||||
open var cellType: AnyClass {
|
open var cellType: AnyClass {
|
||||||
return CellType.self
|
return CellType.self
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(item: CellType.CellData,
|
public init(item: CellType.T, actions: [TableRowAction<CellType>]? = nil, editingActions: [UITableViewRowAction]? = nil) {
|
||||||
actions: [TableRowAction<CellType>]? = nil) {
|
|
||||||
|
|
||||||
self.item = item
|
self.item = item
|
||||||
|
self.editingActions = editingActions
|
||||||
actions?.forEach { on($0) }
|
actions?.forEach { on($0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,7 +64,7 @@ open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableView
|
||||||
|
|
||||||
open func invoke(action: TableRowActionType, cell: UITableViewCell?, path: IndexPath, userInfo: [AnyHashable: Any]? = nil) -> Any? {
|
open func invoke(action: TableRowActionType, cell: UITableViewCell?, path: IndexPath, userInfo: [AnyHashable: Any]? = nil) -> Any? {
|
||||||
|
|
||||||
return actions[action.key]?.compactMap({ $0.invokeActionOn(cell: cell, item: item, path: path, userInfo: userInfo) }).last
|
return actions[action.key]?.flatMap({ $0.invokeActionOn(cell: cell, item: item, path: path, userInfo: userInfo) }).last
|
||||||
}
|
}
|
||||||
|
|
||||||
open func has(action: TableRowActionType) -> Bool {
|
open func has(action: TableRowActionType) -> Bool {
|
||||||
|
|
@ -93,10 +77,7 @@ open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableView
|
||||||
if actions[TableRowActionType.canEdit.key] != nil {
|
if actions[TableRowActionType.canEdit.key] != nil {
|
||||||
return invoke(action: .canEdit, cell: nil, path: indexPath) as? Bool ?? false
|
return invoke(action: .canEdit, cell: nil, path: indexPath) as? Bool ?? false
|
||||||
}
|
}
|
||||||
|
return editingActions?.isEmpty == false || actions[TableRowActionType.clickDelete.key] != nil
|
||||||
return !leadingContextualActions.isEmpty
|
|
||||||
|| !trailingContextualActions.isEmpty
|
|
||||||
|| actions[TableRowActionType.clickDelete.key] != nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - actions -
|
// MARK: - actions -
|
||||||
|
|
@ -132,7 +113,7 @@ open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableView
|
||||||
open func removeAction(forActionId actionId: String) {
|
open func removeAction(forActionId actionId: String) {
|
||||||
|
|
||||||
for (key, value) in actions {
|
for (key, value) in actions {
|
||||||
if let actionIndex = value.firstIndex(where: { $0.id == actionId }) {
|
if let actionIndex = value.index(where: { $0.id == actionId }) {
|
||||||
actions[key]?.remove(at: actionIndex)
|
actions[key]?.remove(at: actionIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,12 @@ import UIKit
|
||||||
|
|
||||||
open class TableRowActionOptions<CellType: ConfigurableCell> where CellType: UITableViewCell {
|
open class TableRowActionOptions<CellType: ConfigurableCell> where CellType: UITableViewCell {
|
||||||
|
|
||||||
public let item: CellType.CellData
|
open let item: CellType.T
|
||||||
public let cell: CellType?
|
open let cell: CellType?
|
||||||
public let indexPath: IndexPath
|
open let indexPath: IndexPath
|
||||||
public let userInfo: [AnyHashable: Any]?
|
open let userInfo: [AnyHashable: Any]?
|
||||||
|
|
||||||
init(item: CellType.CellData, cell: CellType?, path: IndexPath, userInfo: [AnyHashable: Any]?) {
|
init(item: CellType.T, cell: CellType?, path: IndexPath, userInfo: [AnyHashable: Any]?) {
|
||||||
|
|
||||||
self.item = item
|
self.item = item
|
||||||
self.cell = cell
|
self.cell = cell
|
||||||
|
|
@ -55,7 +55,7 @@ private enum TableRowActionHandler<CellType: ConfigurableCell> where CellType: U
|
||||||
open class TableRowAction<CellType: ConfigurableCell> where CellType: UITableViewCell {
|
open class TableRowAction<CellType: ConfigurableCell> where CellType: UITableViewCell {
|
||||||
|
|
||||||
open var id: String?
|
open var id: String?
|
||||||
public let type: TableRowActionType
|
open let type: TableRowActionType
|
||||||
private let handler: TableRowActionHandler<CellType>
|
private let handler: TableRowActionHandler<CellType>
|
||||||
|
|
||||||
public init(_ type: TableRowActionType, handler: @escaping (_ options: TableRowActionOptions<CellType>) -> Void) {
|
public init(_ type: TableRowActionType, handler: @escaping (_ options: TableRowActionOptions<CellType>) -> Void) {
|
||||||
|
|
@ -76,7 +76,7 @@ open class TableRowAction<CellType: ConfigurableCell> where CellType: UITableVie
|
||||||
self.handler = .action(handler)
|
self.handler = .action(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func invokeActionOn(cell: UITableViewCell?, item: CellType.CellData, path: IndexPath, userInfo: [AnyHashable: Any]?) -> Any? {
|
public func invokeActionOn(cell: UITableViewCell?, item: CellType.T, path: IndexPath, userInfo: [AnyHashable: Any]?) -> Any? {
|
||||||
|
|
||||||
return handler.invoke(withOptions: TableRowActionOptions(item: item, cell: cell as? CellType, path: path, userInfo: userInfo))
|
return handler.invoke(withOptions: TableRowActionOptions(item: item, cell: cell as? CellType, path: path, userInfo: userInfo))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
import UIKit
|
|
||||||
|
|
||||||
extension UITableViewCell {
|
|
||||||
|
|
||||||
var tableView: UITableView? {
|
|
||||||
var view = superview
|
|
||||||
|
|
||||||
while view != nil && !(view is UITableView) {
|
|
||||||
view = view?.superview
|
|
||||||
}
|
|
||||||
|
|
||||||
return view as? UITableView
|
|
||||||
}
|
|
||||||
|
|
||||||
var indexPath: IndexPath? {
|
|
||||||
guard let indexPath = tableView?.indexPath(for: self) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return indexPath
|
|
||||||
}
|
|
||||||
|
|
||||||
public func height(layoutType: LayoutType) -> CGFloat {
|
|
||||||
switch layoutType {
|
|
||||||
case .auto:
|
|
||||||
return contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
|
|
||||||
case .manual:
|
|
||||||
return contentView.subviews.map { $0.frame.maxY }.max() ?? 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -2,16 +2,16 @@ Pod::Spec.new do |s|
|
||||||
s.name = 'TableKit'
|
s.name = 'TableKit'
|
||||||
s.module_name = 'TableKit'
|
s.module_name = 'TableKit'
|
||||||
|
|
||||||
s.version = '2.12'
|
s.version = '2.6.0'
|
||||||
|
|
||||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/TableKit'
|
s.homepage = 'https://github.com/maxsokolov/TableKit'
|
||||||
s.summary = 'Type-safe declarative table views with Swift.'
|
s.summary = 'Type-safe declarative table views with Swift.'
|
||||||
|
|
||||||
s.author = { 'Max Sokolov' => 'i@maxsokolov.net' }
|
s.author = { 'Max Sokolov' => 'i@maxsokolov.net' }
|
||||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||||
s.platforms = { :ios => '12.0' }
|
s.platforms = { :ios => '8.0' }
|
||||||
s.ios.deployment_target = '12.0'
|
s.ios.deployment_target = '8.0'
|
||||||
|
|
||||||
s.source_files = 'Sources/*.swift'
|
s.source_files = 'Sources/*.swift'
|
||||||
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/TableKit.git', :tag => s.version }
|
s.source = { :git => 'https://github.com/maxsokolov/TableKit.git', :tag => s.version }
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,6 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
2CBFA2F521F692F100147B56 /* ExpandableState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CBFA2F421F692F100147B56 /* ExpandableState.swift */; };
|
|
||||||
3201E78421BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78321BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift */; };
|
|
||||||
3201E78621BE9E25001DF9E7 /* UITableViewCell+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */; };
|
|
||||||
3201E78821BE9EB2001DF9E7 /* Expandable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78721BE9EB2001DF9E7 /* Expandable.swift */; };
|
|
||||||
3201E78A21BE9ED4001DF9E7 /* ExpandableCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */; };
|
|
||||||
32BDFE9F21C167F400D0BBB4 /* LayoutType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */; };
|
|
||||||
50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */; };
|
50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */; };
|
||||||
50E858581DB153F500A9AA55 /* TableKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E858571DB153F500A9AA55 /* TableKit.swift */; };
|
50E858581DB153F500A9AA55 /* TableKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E858571DB153F500A9AA55 /* TableKit.swift */; };
|
||||||
DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */; };
|
DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */; };
|
||||||
|
|
@ -38,12 +32,6 @@
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
2CBFA2F421F692F100147B56 /* ExpandableState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableState.swift; sourceTree = "<group>"; };
|
|
||||||
3201E78321BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellHeightCalculator.swift; sourceTree = "<group>"; };
|
|
||||||
3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+Extensions.swift"; sourceTree = "<group>"; };
|
|
||||||
3201E78721BE9EB2001DF9E7 /* Expandable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Expandable.swift; sourceTree = "<group>"; };
|
|
||||||
3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellViewModel.swift; sourceTree = "<group>"; };
|
|
||||||
32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutType.swift; sourceTree = "<group>"; };
|
|
||||||
50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableCellRegisterer.swift; sourceTree = "<group>"; };
|
50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableCellRegisterer.swift; sourceTree = "<group>"; };
|
||||||
50E858571DB153F500A9AA55 /* TableKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableKit.swift; sourceTree = "<group>"; };
|
50E858571DB153F500A9AA55 /* TableKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableKit.swift; sourceTree = "<group>"; };
|
||||||
DA9EA7561D0B679A0021F650 /* TableKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TableKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
DA9EA7561D0B679A0021F650 /* TableKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TableKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
|
@ -102,22 +90,16 @@
|
||||||
DA9EA7A51D0EC2B90021F650 /* Sources */ = {
|
DA9EA7A51D0EC2B90021F650 /* Sources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */,
|
|
||||||
3201E78321BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift */,
|
|
||||||
DA9EA7A81D0EC2C90021F650 /* Operators.swift */,
|
|
||||||
DA9EA7A91D0EC2C90021F650 /* TableCellAction.swift */,
|
|
||||||
50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */,
|
|
||||||
DA9EA7AA1D0EC2C90021F650 /* TableDirector.swift */,
|
|
||||||
50E858571DB153F500A9AA55 /* TableKit.swift */,
|
50E858571DB153F500A9AA55 /* TableKit.swift */,
|
||||||
DA9EA7A71D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift */,
|
DA9EA7AA1D0EC2C90021F650 /* TableDirector.swift */,
|
||||||
|
50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */,
|
||||||
DA9EA7AB1D0EC2C90021F650 /* TableRow.swift */,
|
DA9EA7AB1D0EC2C90021F650 /* TableRow.swift */,
|
||||||
DA9EA7AC1D0EC2C90021F650 /* TableRowAction.swift */,
|
DA9EA7AC1D0EC2C90021F650 /* TableRowAction.swift */,
|
||||||
DA9EA7AE1D0EC2C90021F650 /* TableSection.swift */,
|
DA9EA7AE1D0EC2C90021F650 /* TableSection.swift */,
|
||||||
3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */,
|
DA9EA7A91D0EC2C90021F650 /* TableCellAction.swift */,
|
||||||
3201E78721BE9EB2001DF9E7 /* Expandable.swift */,
|
DA9EA7A71D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift */,
|
||||||
3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */,
|
DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */,
|
||||||
32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */,
|
DA9EA7A81D0EC2C90021F650 /* Operators.swift */,
|
||||||
2CBFA2F421F692F100147B56 /* ExpandableState.swift */,
|
|
||||||
);
|
);
|
||||||
path = Sources;
|
path = Sources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -195,16 +177,16 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastSwiftUpdateCheck = 0730;
|
LastSwiftUpdateCheck = 0730;
|
||||||
LastUpgradeCheck = 1000;
|
LastUpgradeCheck = 0900;
|
||||||
ORGANIZATIONNAME = "Max Sokolov";
|
ORGANIZATIONNAME = "Max Sokolov";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
DA9EA7551D0B679A0021F650 = {
|
DA9EA7551D0B679A0021F650 = {
|
||||||
CreatedOnToolsVersion = 7.3;
|
CreatedOnToolsVersion = 7.3;
|
||||||
LastSwiftMigration = 1000;
|
LastSwiftMigration = 0800;
|
||||||
};
|
};
|
||||||
DA9EA7C31D0EC45F0021F650 = {
|
DA9EA7C31D0EC45F0021F650 = {
|
||||||
CreatedOnToolsVersion = 7.3;
|
CreatedOnToolsVersion = 7.3;
|
||||||
LastSwiftMigration = 1000;
|
LastSwiftMigration = 0800;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -213,7 +195,6 @@
|
||||||
developmentRegion = English;
|
developmentRegion = English;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
English,
|
|
||||||
en,
|
en,
|
||||||
);
|
);
|
||||||
mainGroup = DA9EA74C1D0B679A0021F650;
|
mainGroup = DA9EA74C1D0B679A0021F650;
|
||||||
|
|
@ -249,19 +230,13 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
3201E78A21BE9ED4001DF9E7 /* ExpandableCellViewModel.swift in Sources */,
|
|
||||||
50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */,
|
50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */,
|
||||||
DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */,
|
DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */,
|
||||||
DA9EA7B31D0EC2C90021F650 /* TableDirector.swift in Sources */,
|
DA9EA7B31D0EC2C90021F650 /* TableDirector.swift in Sources */,
|
||||||
3201E78821BE9EB2001DF9E7 /* Expandable.swift in Sources */,
|
|
||||||
2CBFA2F521F692F100147B56 /* ExpandableState.swift in Sources */,
|
|
||||||
DA9EA7B71D0EC2C90021F650 /* TableSection.swift in Sources */,
|
DA9EA7B71D0EC2C90021F650 /* TableSection.swift in Sources */,
|
||||||
DA9EA7B01D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift in Sources */,
|
DA9EA7B01D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift in Sources */,
|
||||||
3201E78421BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift in Sources */,
|
|
||||||
DA9EA7B51D0EC2C90021F650 /* TableRowAction.swift in Sources */,
|
DA9EA7B51D0EC2C90021F650 /* TableRowAction.swift in Sources */,
|
||||||
DA9EA7B21D0EC2C90021F650 /* TableCellAction.swift in Sources */,
|
DA9EA7B21D0EC2C90021F650 /* TableCellAction.swift in Sources */,
|
||||||
32BDFE9F21C167F400D0BBB4 /* LayoutType.swift in Sources */,
|
|
||||||
3201E78621BE9E25001DF9E7 /* UITableViewCell+Extensions.swift in Sources */,
|
|
||||||
DA9EA7B11D0EC2C90021F650 /* Operators.swift in Sources */,
|
DA9EA7B11D0EC2C90021F650 /* Operators.swift in Sources */,
|
||||||
DA9EA7B41D0EC2C90021F650 /* TableRow.swift in Sources */,
|
DA9EA7B41D0EC2C90021F650 /* TableRow.swift in Sources */,
|
||||||
50E858581DB153F500A9AA55 /* TableKit.swift in Sources */,
|
50E858581DB153F500A9AA55 /* TableKit.swift in Sources */,
|
||||||
|
|
@ -300,14 +275,12 @@
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
CLANG_WARN_COMMA = YES;
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
|
@ -340,7 +313,7 @@
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 4.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
VERSION_INFO_PREFIX = "";
|
VERSION_INFO_PREFIX = "";
|
||||||
|
|
@ -360,14 +333,12 @@
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
CLANG_WARN_COMMA = YES;
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
|
@ -393,7 +364,7 @@
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 4.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
|
@ -418,7 +389,7 @@
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 4.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
|
@ -438,7 +409,7 @@
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKit;
|
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKit;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 4.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
|
@ -450,7 +421,7 @@
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKitTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKitTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 4.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
|
@ -462,7 +433,7 @@
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKitTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKitTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 4.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1000"
|
LastUpgradeVersion = "0900"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
|
|
@ -55,6 +56,7 @@
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,7 @@ class TableKitTests: XCTestCase {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
|
|
||||||
testController = TestController()
|
testController = TestController()
|
||||||
testController.tableView.frame = UIScreen.main.bounds
|
testController.view.isHidden = false
|
||||||
testController.tableView.isHidden = false
|
|
||||||
testController.tableView.setNeedsLayout()
|
|
||||||
testController.tableView.layoutIfNeeded()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue