diff --git a/.gitignore b/.gitignore
index 9004ef49..835c021b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,16 +1,18 @@
-# ================
-# Swift.gitignore
-# ================
-
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
-## Build generated
-build/
-DerivedData
+## User settings
+xcuserdata/
-## Various settings
+## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
+*.xcscmblueprint
+*.xccheckout
+
+## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
+build/
+DerivedData/
+*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
@@ -19,17 +21,14 @@ DerivedData
!default.mode2v3
*.perspectivev3
!default.perspectivev3
-xcuserdata
-
-## Other
-*.xccheckout
-*.moved-aside
-*.xcuserstate
-*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
+
+## App packaging
*.ipa
+*.dSYM.zip
+*.dSYM
## Playgrounds
timeline.xctimeline
@@ -39,6 +38,14 @@ playground.xcworkspace
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
+# Package.pins
+# Package.resolved
+# *.xcodeproj
+#
+# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
+# hence it is not needed unless you have added a package configuration file to your project
+.swiftpm
+
.build/
# CocoaPods
@@ -48,33 +55,51 @@ playground.xcworkspace
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
Pods/
+#
+# Add this line if you want to avoid checking in source code from the Xcode workspace
+# *.xcworkspace
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
Carthage/Checkouts
-Carthage/Build
+Carthage/Build/
+
+# Accio dependency management
+Dependencies/
+.accio/
# fastlane
#
-# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
-# screenshots whenever they are needed.
+# It is recommended to not store the screenshots in the git repo.
+# Instead, use fastlane to re-generate the screenshots whenever they are needed.
# For more information about the recommended setup visit:
-# https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
-fastlane/screenshots
+fastlane/Preview.html
+fastlane/screenshots/**/*.png
+fastlane/test_output
+# Code Injection
+#
+# After new code Injection tools there's a generated folder /iOSInjectionProject
+# https://github.com/johnno1962/injectionforxcode
-# AppCode
-# https://intellij-support.jetbrains.com/hc/en-us/articles/206544839-How-to-manage-projects-under-Version-Control-Systems
+iOSInjectionProject/
-.idea/workspace.xml
-.idea/tasks.xml
+# homebrew-bundle
+Brewfile.lock.json
-cpd-output.xml
+# Node.js
+# Dependency directories
+node_modules/
# Touch Instinct custom
Downloads/
-
+fastlane/README.md
+Templates/
+cpd-output.xml
+*.swp
+*IDEWorkspaceChecks.plist
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 80043749..1e06c8f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+### 0.11.0
+- **Add**: Cocoapods support for TI-family libraries.
+- **Add**: `SeparatorConfigurable` and all helper types for separator configuration.
+- **Add**: `BaseSeparatorCell` - `BaseInitializeableCell` subclass with separators support.
+- **Add**: `TITableKitUtils` - set of helpers for TableKit classes.
+- **Add**: `BaseTextAttributes` and `ViewText` implementation form LeadKit.
+- **Update**: `BaseInitializableView` and `BaseInitializableControl` are moved to `TIUIElements` from `TIUIKitCore`.
+
### 0.10.9
- **Fix**: `change presentedOrTopViewController to open`.
diff --git a/Package.resolved b/Package.resolved
new file mode 100644
index 00000000..7c8c1236
--- /dev/null
+++ b/Package.resolved
@@ -0,0 +1,16 @@
+{
+ "object": {
+ "pins": [
+ {
+ "package": "TableKit",
+ "repositoryURL": "https://github.com/maxsokolov/TableKit.git",
+ "state": {
+ "branch": null,
+ "revision": "8bf4840d9d0475a92352f02f368f88b74eced447",
+ "version": "2.11.0"
+ }
+ }
+ ]
+ },
+ "version": 1
+}
diff --git a/Package.swift b/Package.swift
index 698d8992..7e976793 100644
--- a/Package.swift
+++ b/Package.swift
@@ -12,14 +12,19 @@ let package = Package(
.library(name: "TISwiftUtils", targets: ["TISwiftUtils"]),
.library(name: "TIFoundationUtils", targets: ["TIFoundationUtils"]),
.library(name: "TIUIElements", targets: ["TIUIElements"]),
+ .library(name: "TITableKitUtils", targets: ["TITableKitUtils"]),
.library(name: "OTPSwiftView", targets: ["OTPSwiftView"])
],
+ dependencies: [
+ .package(url: "https://github.com/maxsokolov/TableKit.git", from: "2.11.0")
+ ],
targets: [
.target(name: "TITransitions", path: "TITransitions/Sources"),
.target(name: "TIUIKitCore", path: "TIUIKitCore/Sources"),
.target(name: "TISwiftUtils", path: "TISwiftUtils/Sources"),
.target(name: "TIFoundationUtils", dependencies: ["TISwiftUtils"], path: "TIFoundationUtils/Sources"),
.target(name: "TIUIElements", dependencies: ["TIUIKitCore"], path: "TIUIElements/Sources"),
+ .target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"),
.target(name: "OTPSwiftView", dependencies: ["TIUIKitCore", "TISwiftUtils"], path: "OTPSwiftView/Sources")
]
)
diff --git a/README.md b/README.md
index 6cda623b..73a91c28 100644
--- a/README.md
+++ b/README.md
@@ -8,4 +8,25 @@ This repository contains the following additional frameworks:
- [TIUIElements](TIUIElements) - bunch of of useful protocols and views.
- [OTPSwiftView](OTPSwiftView) - a fully customizable OTP view.
- [TISwiftUtils](TISwiftUtils) - a bunch of useful helpers for development.
+- [TITableKitUtils](TITableKitUtils) - Set of helpers for TableKit classes.
+
+## Installation
+
+### SPM
+
+```swift
+dependencies: [
+ .package(url: "https://github.com/TouchInstinct/LeadKit.git", from: "x.y.z"),
+],
+```
+
+### Cocoapods
+
+```ruby
+source 'https://github.com/TouchInstinct/Podspecs.git'
+
+pod 'TISwiftUtils', 'x.y.z'
+pod 'TIFoundationUtils', 'x.y.z'
+# ...
+```
diff --git a/TIFoundationUtils/TIFoundationUtils.podspec b/TIFoundationUtils/TIFoundationUtils.podspec
new file mode 100644
index 00000000..384ae080
--- /dev/null
+++ b/TIFoundationUtils/TIFoundationUtils.podspec
@@ -0,0 +1,17 @@
+Pod::Spec.new do |s|
+ s.name = 'TIFoundationUtils'
+ s.version = '0.11.0'
+ s.summary = 'Set of helpers for Foundation framework classes.'
+ s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
+ s.license = { :type => 'MIT', :file => 'LICENSE' }
+ s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
+ s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
+
+ s.ios.deployment_target = '11.0'
+ s.swift_versions = ['5.3']
+
+ s.source_files = s.name + '/Sources/**/*'
+
+ s.dependency 'TISwiftUtils', s.version.to_s
+ s.framework = 'Foundation'
+end
diff --git a/TISwiftUtils/README.md b/TISwiftUtils/README.md
index 993c9cfe..1a9f1a94 100644
--- a/TISwiftUtils/README.md
+++ b/TISwiftUtils/README.md
@@ -18,7 +18,3 @@ final class ViewModel {
var hasFinishedOnboarding: Bool
}
```
-
-# Installation via SPM
-
-You can install this framework as a target of LeadKit.
diff --git a/TISwiftUtils/Sources/Extensions/Optional/Optional+Extensions.swift b/TISwiftUtils/Sources/Extensions/Optional/Optional+Extensions.swift
index 0bddd3bb..af793186 100644
--- a/TISwiftUtils/Sources/Extensions/Optional/Optional+Extensions.swift
+++ b/TISwiftUtils/Sources/Extensions/Optional/Optional+Extensions.swift
@@ -20,8 +20,6 @@
// THE SOFTWARE.
//
-import UIKit
-
public extension Optional where Wrapped == String {
var orEmpty: String {
self ?? ""
diff --git a/TISwiftUtils/Sources/Extensions/Substring/Substring+Extensions.swift b/TISwiftUtils/Sources/Extensions/Substring/Substring+Extensions.swift
index 61d0812f..e68fc6f3 100644
--- a/TISwiftUtils/Sources/Extensions/Substring/Substring+Extensions.swift
+++ b/TISwiftUtils/Sources/Extensions/Substring/Substring+Extensions.swift
@@ -20,8 +20,6 @@
// THE SOFTWARE.
//
-import Foundation
-
public extension Substring {
var string: String {
String(self)
diff --git a/TISwiftUtils/Sources/Helpers/Typealias.swift b/TISwiftUtils/Sources/Helpers/Typealias.swift
index 897d1f09..3ece5296 100644
--- a/TISwiftUtils/Sources/Helpers/Typealias.swift
+++ b/TISwiftUtils/Sources/Helpers/Typealias.swift
@@ -20,8 +20,6 @@
// THE SOFTWARE.
//
-import UIKit
-
/// Closure with custom arguments and return value.
public typealias Closure = (Input) -> Output
diff --git a/TISwiftUtils/TISwiftUtils.podspec b/TISwiftUtils/TISwiftUtils.podspec
new file mode 100644
index 00000000..4a256658
--- /dev/null
+++ b/TISwiftUtils/TISwiftUtils.podspec
@@ -0,0 +1,14 @@
+Pod::Spec.new do |s|
+ s.name = 'TISwiftUtils'
+ s.version = '0.11.0'
+ s.summary = 'Bunch of useful helpers for Swift development.'
+ s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
+ s.license = { :type => 'MIT', :file => 'LICENSE' }
+ s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
+ s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
+
+ s.ios.deployment_target = '9.0'
+ s.swift_versions = ['5.3']
+
+ s.source_files = s.name + '/Sources/**/*'
+end
diff --git a/TITableKitUtils/README.md b/TITableKitUtils/README.md
new file mode 100644
index 00000000..1401a1b5
--- /dev/null
+++ b/TITableKitUtils/README.md
@@ -0,0 +1,4 @@
+# TITableKitUtils
+
+Set of helpers for TableKit classes.
+
diff --git a/TITableKitUtils/Sources/Extensions/TableDirector/TableDirector+Extensions.swift b/TITableKitUtils/Sources/Extensions/TableDirector/TableDirector+Extensions.swift
new file mode 100644
index 00000000..4156c963
--- /dev/null
+++ b/TITableKitUtils/Sources/Extensions/TableDirector/TableDirector+Extensions.swift
@@ -0,0 +1,243 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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 TableKit
+import UIKit.UITableView
+
+public extension TableDirector {
+
+ /**
+ method replaces current table director's section at index and reloads it
+
+ - parameter section: new section
+ - parameter index: current replaced section index
+ - parameter reload: is reloaded after replace
+
+ - returns: self
+ */
+ @discardableResult
+ func replace(section: TableSection, atIndex index: Int, reload: Bool = true) -> Self {
+ if index < sections.count {
+ remove(sectionAt: index)
+ }
+ insert(section: section, atIndex: index)
+ if reload {
+ self.reload(sectionAtIndex: index)
+ }
+ return self
+ }
+
+ /**
+ method reloads section at index with animation
+
+ - parameter index: current reloaded section index
+ - parameter animation: reloading animation. Default .none
+
+ - returns: self
+ */
+ @discardableResult
+ func reload(sectionAtIndex index: Int, with animation: UITableView.RowAnimation = .none) -> Self {
+ let action = { [tableView] in
+ guard let tableView = tableView else {
+ return
+ }
+
+ if index < tableView.numberOfSections {
+ tableView.reloadSections([index], with: animation)
+ } else {
+ tableView.reloadData()
+ }
+ }
+ if animation == .none {
+ UIView.performWithoutAnimation(action)
+ } else {
+ action()
+ }
+ return self
+ }
+
+ /**
+ method replaces current table director's state with sections
+
+ - parameter sections: new sections
+
+ - returns: self
+ */
+ @discardableResult
+ func replace(withSections sections: [TableSection]) -> Self {
+ clear().append(sections: sections).reload()
+ return self
+ }
+
+ /**
+ method replaces current table director's state with section
+
+ - parameter section: new section
+
+ - returns: self
+ */
+ @discardableResult
+ func replace(withSection section: TableSection) -> Self {
+ return replace(withSections: [section])
+ }
+
+ /**
+ method replaces current table director's state with rows
+
+ - parameter rows: new rows
+
+ - returns: self
+ */
+ @discardableResult
+ func replace(withRows rows: [Row]) -> Self {
+ return replace(withSection: TableSection(rows: rows))
+ }
+
+ /// Clear table view and reload it within empty section
+ func safeClear() {
+ clear().append(section: TableSection(onlyRows: [])).reload()
+ }
+
+ /// Inserts rows into table without complete reload.
+ ///
+ /// - Parameters:
+ /// - rows: Rows to insert.
+ /// - indexPath: Position of first row.
+ /// - animation: The type of animation when rows are inserted
+ /// - manualBeginEndUpdates: Don't call beginUpdates() & endUpdates() inside.
+ func insert(rows: [Row],
+ at indexPath: IndexPath,
+ with animation: UITableView.RowAnimation,
+ manualBeginEndUpdates: Bool = false) {
+
+ sections[indexPath.section].insert(rows: rows, at: indexPath.row)
+ let indexPaths: [IndexPath] = rows.indices.map {
+ IndexPath(row: indexPath.row + $0, section: indexPath.section)
+ }
+
+ if manualBeginEndUpdates {
+ tableView?.insertRows(at: indexPaths, with: animation)
+ } else {
+ tableView?.beginUpdates()
+ tableView?.insertRows(at: indexPaths, with: animation)
+ tableView?.endUpdates()
+ }
+ }
+
+ /// Removes rows from table without complete reload.
+ ///
+ /// - Parameters:
+ /// - rowsCount: Number of rows to remove.
+ /// - indexPath: Position of first row to remove.
+ /// - animation: The type of animation when rows are deleted
+ /// - manualBeginEndUpdates: Don't call beginUpdates() & endUpdates() inside.
+ func remove(rowsCount: Int,
+ startingAt indexPath: IndexPath,
+ with animation: UITableView.RowAnimation,
+ manualBeginEndUpdates: Bool = false) {
+
+ var indexPaths = [IndexPath]()
+ for index in indexPath.row ..< indexPath.row + rowsCount {
+ indexPaths.append(IndexPath(row: index, section: indexPath.section))
+ }
+
+ indexPaths.reversed().forEach {
+ sections[$0.section].remove(rowAt: $0.row)
+ }
+
+ if manualBeginEndUpdates {
+ tableView?.deleteRows(at: indexPaths, with: animation)
+ } else {
+ tableView?.beginUpdates()
+ tableView?.deleteRows(at: indexPaths, with: animation)
+ tableView?.endUpdates()
+ }
+ }
+
+ /// Method inserts section with animation.
+ ///
+ /// - Parameters:
+ /// - section: Section to insert
+ /// - index: Position to insert
+ /// - animation: The type of insert animation
+ /// - manualBeginEndUpdates: Don't call beginUpdates() & endUpdates() inside.
+ /// - Returns: self
+ @discardableResult
+ func insert(section: TableSection,
+ at index: Int,
+ with animation: UITableView.RowAnimation,
+ manualBeginEndUpdates: Bool = false) -> Self {
+
+ insert(section: section, atIndex: index)
+ if manualBeginEndUpdates {
+ tableView?.insertSections([index], with: animation)
+ } else {
+ tableView?.beginUpdates()
+ tableView?.insertSections([index], with: animation)
+ tableView?.endUpdates()
+ }
+
+ return self
+ }
+
+ /// Method removes section with animation.
+ ///
+ /// - Parameters:
+ /// - index: Position to remove
+ /// - animation: The type of remove animation
+ /// - manualBeginEndUpdates: Don't call beginUpdates() & endUpdates() inside.
+ /// - Returns: self
+ @discardableResult
+ func remove(at index: Int,
+ with animation: UITableView.RowAnimation,
+ manualBeginEndUpdates: Bool = false) -> Self {
+
+ delete(sectionAt: index)
+ if manualBeginEndUpdates {
+ tableView?.deleteSections([index], with: animation)
+ } else {
+ tableView?.beginUpdates()
+ tableView?.deleteSections([index], with: animation)
+ tableView?.endUpdates()
+ }
+
+ return self
+ }
+
+ /// Method replace section with animation.
+ ///
+ /// - Parameters:
+ /// - section: Section to replace
+ /// - index: Position to replace
+ /// - animation: The type of replace animation
+ /// - manualBeginEndUpdates: Don't call beginUpdates() & endUpdates() inside.
+ /// - Returns: self
+ @discardableResult
+ func replace(with section: TableSection,
+ at index: Int,
+ with animation: UITableView.RowAnimation,
+ manualBeginEndUpdates: Bool = false) -> Self {
+
+ remove(at: index, with: animation, manualBeginEndUpdates: manualBeginEndUpdates)
+ return insert(section: section, at: index, with: animation, manualBeginEndUpdates: manualBeginEndUpdates)
+ }
+}
diff --git a/TITableKitUtils/Sources/Extensions/TableSection/TableSection+Extensions.swift b/TITableKitUtils/Sources/Extensions/TableSection/TableSection+Extensions.swift
new file mode 100644
index 00000000..eda00808
--- /dev/null
+++ b/TITableKitUtils/Sources/Extensions/TableSection/TableSection+Extensions.swift
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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 TableKit
+
+public extension TableSection {
+
+ /// Initializes section with rows and zero height footer and header.
+ ///
+ /// - Parameter rows: Rows to insert into section.
+ convenience init(onlyRows rows: [Row]) {
+ self.init(rows: rows)
+
+ self.headerView = nil
+ self.footerView = nil
+
+ self.headerHeight = .leastNonzeroMagnitude
+ self.footerHeight = .leastNonzeroMagnitude
+ }
+}
diff --git a/TITableKitUtils/Sources/Separators/Extensions/Array/Array+SeparatorRowBox.swift b/TITableKitUtils/Sources/Separators/Extensions/Array/Array+SeparatorRowBox.swift
new file mode 100644
index 00000000..fa212ca2
--- /dev/null
+++ b/TITableKitUtils/Sources/Separators/Extensions/Array/Array+SeparatorRowBox.swift
@@ -0,0 +1,66 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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 TableKit
+import TIUIElements
+
+public extension Array where Element == SeparatorRowBox {
+
+ /// Create rows from SeparatorRowBox array
+ var rows: [Row] {
+ return map { $0.row }
+ }
+
+ /// Configure separators from SeparatorRowBox array
+ /// - parameter extreme: Configuration that will be used for extreme values, for first or last row
+ /// - parameter middle: Configuration for intermediate rows
+ func configureSeparators(extreme extremeSeparatorConfiguration: SeparatorConfiguration,
+ middle middleSeparatorConfiguration: SeparatorConfiguration) {
+
+ configureSeparators(first: extremeSeparatorConfiguration,
+ middle: middleSeparatorConfiguration,
+ last: extremeSeparatorConfiguration)
+ }
+
+ /// Configure separators from SeparatorRowBox array
+ /// - parameter first: Configuration of the top separator of the first row
+ /// - parameter middle: Configuration of the separators between the rows
+ /// - parameter last: Configuration of the bottom separator of the last row
+ func configureSeparators(first firstSeparatorConfiguration: SeparatorConfiguration,
+ middle middleSeparatorConfiguration: SeparatorConfiguration,
+ last lastSeparatorConfiguration: SeparatorConfiguration) {
+
+ if isEmpty {
+ return
+ }
+
+ switch count {
+ case 1:
+ first?.set(separatorType: .full(firstSeparatorConfiguration, lastSeparatorConfiguration))
+
+ default:
+ dropFirst().dropLast().forEach { $0.set(separatorType: .bottom(middleSeparatorConfiguration)) }
+ first?.set(separatorType: .full(firstSeparatorConfiguration, middleSeparatorConfiguration))
+ last?.set(separatorType: .bottom(lastSeparatorConfiguration))
+ }
+ }
+}
diff --git a/TITableKitUtils/Sources/Separators/Extensions/TableRow/TableRow+Separators.swift b/TITableKitUtils/Sources/Separators/Extensions/TableRow/TableRow+Separators.swift
new file mode 100644
index 00000000..05ae4742
--- /dev/null
+++ b/TITableKitUtils/Sources/Separators/Extensions/TableRow/TableRow+Separators.swift
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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 TableKit
+import TIUIElements
+
+private let configureSeparatorActionId = "TableRowConfigureSeparatorActionId"
+
+public extension TableRow where CellType: SeparatorConfigurable {
+
+ func with(separatorType: ViewSeparatorType) -> Self {
+ set(separatorType: separatorType)
+ return self
+ }
+
+ func set(separatorType: ViewSeparatorType) {
+ removeAction(forActionId: configureSeparatorActionId)
+
+ let action = TableRowAction(.configure) {
+ $0.cell?.configureSeparators(with: separatorType)
+ }
+
+ action.id = configureSeparatorActionId
+ on(action)
+ }
+}
+
+public extension TableRow where CellType: SeparatorConfigurable {
+
+ /// TableRow typed as SeparatorRowBox
+ var separatorRowBox: SeparatorRowBox {
+ return SeparatorRowBox(row: self)
+ }
+}
diff --git a/TITableKitUtils/Sources/Separators/SeparatorRowBox.swift b/TITableKitUtils/Sources/Separators/SeparatorRowBox.swift
new file mode 100644
index 00000000..6109c4da
--- /dev/null
+++ b/TITableKitUtils/Sources/Separators/SeparatorRowBox.swift
@@ -0,0 +1,41 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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 TableKit
+import TIUIElements
+import TISwiftUtils
+
+/// Class that used to configure separators when multiply cells presented in one section
+public final class SeparatorRowBox {
+ private let setSeparatorHandler: ParameterClosure
+
+ public func set(separatorType: ViewSeparatorType) {
+ setSeparatorHandler(separatorType)
+ }
+
+ public let row: Row
+
+ public init(row: TableRow) where T: SeparatorConfigurable {
+ self.row = row
+ setSeparatorHandler = row.set
+ }
+}
diff --git a/TITableKitUtils/TITableKitUtils.podspec b/TITableKitUtils/TITableKitUtils.podspec
new file mode 100644
index 00000000..3cacb356
--- /dev/null
+++ b/TITableKitUtils/TITableKitUtils.podspec
@@ -0,0 +1,18 @@
+Pod::Spec.new do |s|
+ s.name = 'TITableKitUtils'
+ s.version = '0.11.0'
+ s.summary = 'Set of helpers for TableKit classes.'
+ s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
+ s.license = { :type => 'MIT', :file => 'LICENSE' }
+ s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
+ s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
+
+ s.ios.deployment_target = '11.0'
+ s.swift_versions = ['5.3']
+
+ s.source_files = s.name + '/Sources/**/*'
+
+ s.dependency 'TIUIElements', s.version.to_s
+ s.dependency 'TISwiftUtils', s.version.to_s
+ s.dependency 'TableKit', '2.11.0'
+end
diff --git a/TIUIElements/Sources/Separators/BaseSeparatorCell.swift b/TIUIElements/Sources/Separators/BaseSeparatorCell.swift
new file mode 100644
index 00000000..003f7dd0
--- /dev/null
+++ b/TIUIElements/Sources/Separators/BaseSeparatorCell.swift
@@ -0,0 +1,147 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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
+
+open class BaseSeparatorCell: BaseInitializableCell, SeparatorConfigurable {
+ private lazy var topSeparatorView = createTopSeparator()
+ private lazy var bottomSeparatorView = UIView()
+
+ private var topViewLeftConstraint: NSLayoutConstraint?
+ private var topViewRightConstraint: NSLayoutConstraint?
+ private var topViewTopConstraint: NSLayoutConstraint?
+ private var topViewHeightConstraint: NSLayoutConstraint?
+
+ private var bottomViewLeftConstraint: NSLayoutConstraint?
+ private var bottomViewRightConstraint: NSLayoutConstraint?
+ private var bottomViewBottomConstraint: NSLayoutConstraint?
+ private var bottomViewHeightConstraint: NSLayoutConstraint?
+
+ open func createTopSeparator() -> UIView {
+ .init()
+ }
+
+ open func createBottomSeparator() -> UIView {
+ .init()
+ }
+
+ open func add(topSeparatorView: UIView) {
+ contentView.addSubview(topSeparatorView)
+ }
+
+ open func add(bottomSeparatorView: UIView) {
+ contentView.addSubview(bottomSeparatorView)
+ }
+
+ public func configureSeparators(with separatorType: ViewSeparatorType) {
+ topSeparatorView.isHidden = separatorType.topIsHidden
+ bottomSeparatorView.isHidden = separatorType.bottomIsHidden
+
+ switch separatorType {
+ case .none:
+ break
+
+ case let .bottom(configuration):
+ updateBottomSeparator(with: configuration)
+
+ case let .top(configuration):
+ updateTopSeparator(with: configuration)
+
+ case let .full(topConfiguration, bottomConfiguration):
+ updateTopSeparator(with: topConfiguration)
+ updateBottomSeparator(with: bottomConfiguration)
+ }
+ }
+
+ open override func prepareForReuse() {
+ super.prepareForReuse()
+ configureSeparators(with: .none)
+ }
+
+ // MARK: - InitializableView
+
+ open override func addViews() {
+ super.addViews()
+
+ add(topSeparatorView: topSeparatorView)
+ add(bottomSeparatorView: bottomSeparatorView)
+ }
+
+ open override func configureLayout() {
+ super.configureLayout()
+
+ if let separatorSuperview = topSeparatorView.superview {
+ topViewTopConstraint = topSeparatorView.topAnchor.constraint(equalTo: separatorSuperview.topAnchor)
+ topViewRightConstraint = separatorSuperview.rightAnchor.constraint(equalTo: topSeparatorView.rightAnchor)
+ topViewLeftConstraint = topSeparatorView.leftAnchor.constraint(equalTo: separatorSuperview.leftAnchor)
+ }
+
+ topViewHeightConstraint = topSeparatorView.heightAnchor.constraint(equalToConstant: 1)
+
+ if let separatorSuperview = topSeparatorView.superview {
+ bottomViewRightConstraint = separatorSuperview.rightAnchor.constraint(equalTo: bottomSeparatorView.rightAnchor)
+ bottomViewLeftConstraint = bottomSeparatorView.leftAnchor.constraint(equalTo: separatorSuperview.leftAnchor)
+ bottomViewBottomConstraint = bottomSeparatorView.bottomAnchor.constraint(equalTo: separatorSuperview.bottomAnchor)
+ }
+
+ bottomViewHeightConstraint = bottomSeparatorView.heightAnchor.constraint(equalToConstant: 1)
+
+ NSLayoutConstraint.activate([
+ topViewTopConstraint,
+ topViewRightConstraint,
+ topViewLeftConstraint,
+ topViewHeightConstraint,
+ bottomViewRightConstraint,
+ bottomViewLeftConstraint,
+ bottomViewBottomConstraint,
+ bottomViewHeightConstraint
+ ].compactMap { $0 })
+ }
+
+ open override func configureAppearance() {
+ super.configureAppearance()
+
+ [topSeparatorView, bottomSeparatorView].forEach {
+ $0.isHidden = true
+ $0.backgroundColor = .black
+ $0.translatesAutoresizingMaskIntoConstraints = false
+ }
+ }
+}
+
+private extension BaseSeparatorCell {
+ func updateTopSeparator(with configuration: SeparatorConfiguration) {
+ topSeparatorView.backgroundColor = configuration.color
+ topViewHeightConstraint?.constant = configuration.height
+ topViewTopConstraint?.constant = configuration.insets.top
+ topViewLeftConstraint?.constant = configuration.insets.left
+ topViewRightConstraint?.constant = -configuration.insets.right
+ }
+
+ func updateBottomSeparator(with configuration: SeparatorConfiguration) {
+ bottomSeparatorView.backgroundColor = configuration.color
+ bottomViewHeightConstraint?.constant = configuration.height
+ bottomViewBottomConstraint?.constant = -configuration.insets.bottom
+ bottomViewLeftConstraint?.constant = configuration.insets.left
+ bottomViewRightConstraint?.constant = -configuration.insets.right
+ }
+}
diff --git a/TIUIElements/Sources/Separators/SeparatorConfigurable.swift b/TIUIElements/Sources/Separators/SeparatorConfigurable.swift
new file mode 100644
index 00000000..6e58a390
--- /dev/null
+++ b/TIUIElements/Sources/Separators/SeparatorConfigurable.swift
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+public protocol SeparatorConfigurable {
+ func configureSeparators(with separatorType: ViewSeparatorType)
+}
diff --git a/TIUIElements/Sources/Separators/SeparatorConfiguration.swift b/TIUIElements/Sources/Separators/SeparatorConfiguration.swift
new file mode 100644
index 00000000..0a44231c
--- /dev/null
+++ b/TIUIElements/Sources/Separators/SeparatorConfiguration.swift
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import UIKit
+
+public struct SeparatorConfiguration {
+
+ public let color: UIColor
+ public let insets: UIEdgeInsets
+ public let height: CGFloat
+
+ public init(color: UIColor, insets: UIEdgeInsets = .zero, height: CGFloat = 1) {
+ self.color = color
+ self.insets = insets
+ self.height = height
+ }
+}
diff --git a/TIUIElements/Sources/Separators/ViewSeparatorType.swift b/TIUIElements/Sources/Separators/ViewSeparatorType.swift
new file mode 100644
index 00000000..9158ff2e
--- /dev/null
+++ b/TIUIElements/Sources/Separators/ViewSeparatorType.swift
@@ -0,0 +1,71 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+public enum ViewSeparatorType {
+
+ /// All separators for view is hidden
+ case none
+
+ /// Show only top separator
+ case top(SeparatorConfiguration)
+
+ /// Show only bottom separator
+ case bottom(SeparatorConfiguration)
+
+ /// First configuration for top, second for bottom
+ case full(SeparatorConfiguration, SeparatorConfiguration)
+}
+
+public extension ViewSeparatorType {
+
+ /// Determine if bottom separator is hidden.
+ var bottomIsHidden: Bool {
+ return bottomConfiguration == nil
+ }
+
+ /// Determine if top separator is hidden.
+ var topIsHidden: Bool {
+ return topConfiguration == nil
+ }
+
+ /// Returns top configuration if type is top or full.
+ var topConfiguration: SeparatorConfiguration? {
+ switch self {
+ case let .top(configuration), let .full(configuration, _):
+ return configuration
+
+ default:
+ return nil
+ }
+ }
+
+ /// Returns bottom configuration if type is bottom or full.
+ var bottomConfiguration: SeparatorConfiguration? {
+ switch self {
+ case let .bottom(configuration), let .full(_, configuration):
+ return configuration
+
+ default:
+ return nil
+ }
+ }
+}
diff --git a/TIUIKitCore/Sources/Views/BaseInitializableControl.swift b/TIUIElements/Sources/Views/BaseInitializableControl.swift
similarity index 95%
rename from TIUIKitCore/Sources/Views/BaseInitializableControl.swift
rename to TIUIElements/Sources/Views/BaseInitializableControl.swift
index c5cc67f0..7d852d5d 100644
--- a/TIUIKitCore/Sources/Views/BaseInitializableControl.swift
+++ b/TIUIElements/Sources/Views/BaseInitializableControl.swift
@@ -1,6 +1,7 @@
import UIKit
+import TIUIKitCore
-open class BaseInitializableControl: UIControl, InitializableView {
+open class BaseInitializableControl: UIControl, InitializableViewProtocol {
override public init(frame: CGRect) {
super.init(frame: frame)
diff --git a/TIUIKitCore/Sources/Views/BaseInitializableView.swift b/TIUIElements/Sources/Views/BaseInitializableView.swift
similarity index 95%
rename from TIUIKitCore/Sources/Views/BaseInitializableView.swift
rename to TIUIElements/Sources/Views/BaseInitializableView.swift
index 1fb7d960..d7192498 100644
--- a/TIUIKitCore/Sources/Views/BaseInitializableView.swift
+++ b/TIUIElements/Sources/Views/BaseInitializableView.swift
@@ -21,8 +21,9 @@
//
import UIKit
+import TIUIKitCore
-open class BaseInitializableView: UIView, InitializableView {
+open class BaseInitializableView: UIView, InitializableViewProtocol {
override public init(frame: CGRect) {
super.init(frame: frame)
diff --git a/TIUIElements/Sources/Views/Cells/BaseInitializableCell.swift b/TIUIElements/Sources/Views/Cells/BaseInitializableCell.swift
new file mode 100644
index 00000000..7f45b55f
--- /dev/null
+++ b/TIUIElements/Sources/Views/Cells/BaseInitializableCell.swift
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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 TIUIKitCore
+import UIKit
+
+open class BaseInitializableCell: UITableViewCell, InitializableViewProtocol {
+ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+ super.init(style: .default, reuseIdentifier: reuseIdentifier)
+
+ initializeView()
+ }
+
+ @available(*, unavailable)
+ required public init?(coder aDecoder: NSCoder) {
+ super.init(coder: aDecoder)
+ }
+
+ // MARK: - InitializableView
+
+ open func addViews() {
+ // empty for subclasses overriding
+ }
+
+ open func bindViews() {
+ // empty for subclasses overriding
+ }
+
+ open func configureLayout() {
+ // empty for subclasses overriding
+ }
+
+ open func configureAppearance() {
+ selectionStyle = .none
+ backgroundColor = .clear
+ }
+
+ open func localize() {
+ // empty for subclasses overriding
+ }
+}
diff --git a/TIUIElements/TIUIElements.podspec b/TIUIElements/TIUIElements.podspec
new file mode 100644
index 00000000..74097f9d
--- /dev/null
+++ b/TIUIElements/TIUIElements.podspec
@@ -0,0 +1,16 @@
+Pod::Spec.new do |s|
+ s.name = 'TIUIElements'
+ s.version = '0.11.0'
+ s.summary = 'Bunch of useful protocols and views.'
+ s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
+ s.license = { :type => 'MIT', :file => 'LICENSE' }
+ s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
+ s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
+
+ s.ios.deployment_target = '11.0'
+ s.swift_versions = ['5.3']
+
+ s.source_files = s.name + '/Sources/**/*'
+
+ s.dependency 'TIUIKitCore', s.version.to_s
+end
diff --git a/TIUIKitCore/README.md b/TIUIKitCore/README.md
index 9c46b9b3..96d028a7 100644
--- a/TIUIKitCore/README.md
+++ b/TIUIKitCore/README.md
@@ -12,7 +12,3 @@ Core UI elements: protocols, views and helpers.
# Views
- [BaseInitializableView](BaseInitializableView/BaseInitializableView.swift) - UIView conformance to InitializableView.
-
-# Installation via SPM
-
-You can install this framework as a target of LeadKit.
diff --git a/TIUIKitCore/Sources/Extensions/InitializableView/InitializableView+Extensions.swift b/TIUIKitCore/Sources/Extensions/InitializableView/InitializableView+Extensions.swift
index b5026ee6..2c10e7c9 100644
--- a/TIUIKitCore/Sources/Extensions/InitializableView/InitializableView+Extensions.swift
+++ b/TIUIKitCore/Sources/Extensions/InitializableView/InitializableView+Extensions.swift
@@ -20,7 +20,7 @@
// THE SOFTWARE.
//
-public extension InitializableView {
+public extension InitializableViewProtocol {
func initializeView() {
addViews()
diff --git a/TIUIKitCore/Sources/Protocols/ConfigurableView/ConfigurableView.swift b/TIUIKitCore/Sources/Protocols/ConfigurableView/ConfigurableView.swift
new file mode 100644
index 00000000..cd5fc1ab
--- /dev/null
+++ b/TIUIKitCore/Sources/Protocols/ConfigurableView/ConfigurableView.swift
@@ -0,0 +1,27 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+public protocol ConfigurableView {
+ associatedtype ViewModelType
+
+ func configure(with _: ViewModelType)
+}
diff --git a/TIUIKitCore/Sources/Protocols/InitializableView/InitializableView.swift b/TIUIKitCore/Sources/Protocols/InitializableViewProtocol/InitializableViewProtocol.swift
similarity index 97%
rename from TIUIKitCore/Sources/Protocols/InitializableView/InitializableView.swift
rename to TIUIKitCore/Sources/Protocols/InitializableViewProtocol/InitializableViewProtocol.swift
index bbf07d29..766256fb 100644
--- a/TIUIKitCore/Sources/Protocols/InitializableView/InitializableView.swift
+++ b/TIUIKitCore/Sources/Protocols/InitializableViewProtocol/InitializableViewProtocol.swift
@@ -21,7 +21,7 @@
//
/// Protocol with methods that should be called in constructor methods of view.
-public protocol InitializableView {
+public protocol InitializableViewProtocol {
/// Main method that should call other methods in particular order.
func initializeView()
diff --git a/TIUIKitCore/Sources/ViewText/BaseTextAttributes.swift b/TIUIKitCore/Sources/ViewText/BaseTextAttributes.swift
new file mode 100644
index 00000000..d9d5a26e
--- /dev/null
+++ b/TIUIKitCore/Sources/ViewText/BaseTextAttributes.swift
@@ -0,0 +1,57 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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.UIFont
+import UIKit.UIColor
+
+/// Base set of attributes to configure appearance of text.
+open class BaseTextAttributes {
+
+ /// Text font.
+ public let font: UIFont
+ /// Text color.
+ public let color: UIColor
+ /// Text alignment.
+ public let alignment: NSTextAlignment
+
+ /// Memberwise initializer.
+ ///
+ /// - Parameters:
+ /// - font: Text font.
+ /// - color: Text color.
+ /// - alignment: Text alignment.
+ public init(font: UIFont, color: UIColor, alignment: NSTextAlignment = .natural) {
+ self.font = font
+ self.color = color
+ self.alignment = alignment
+ }
+}
+
+public extension BaseTextAttributes {
+
+ /// Configures text appearance of given ViewTextConfigurable instance.
+ ///
+ /// - Parameter view: ViewTextConfigurable instance to configure with BaseTextAttributes.
+ func configureBaseApperance(of view: ViewTextConfigurable) {
+ view.configureBaseAppearance(with: self)
+ }
+}
diff --git a/TIUIKitCore/Sources/ViewText/ViewText.swift b/TIUIKitCore/Sources/ViewText/ViewText.swift
new file mode 100644
index 00000000..b84ea370
--- /dev/null
+++ b/TIUIKitCore/Sources/ViewText/ViewText.swift
@@ -0,0 +1,91 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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
+
+/// Enum that describes text with appearance options.
+///
+/// - string: Regular string with common and often-used text attributes.
+/// - attributedString: Attributed string.
+public enum ViewText {
+
+ case string(String, textAttributes: BaseTextAttributes)
+ case attributedString(NSAttributedString)
+}
+
+public extension ViewText {
+
+ /// Convenient initializer for .string case with default alignment parameter.
+ ///
+ /// - Parameters:
+ /// - string: Text to use.
+ /// - font: Font to use.
+ /// - color: Color to use.
+ /// - alignment: Alignment to use. Default is natural.
+ init(string: String, font: UIFont, color: UIColor, alignment: NSTextAlignment = .natural) {
+ self = .string(string, textAttributes: BaseTextAttributes(font: font,
+ color: color,
+ alignment: alignment))
+ }
+
+ /// Attributed string created using text attributes.
+ var attributedString: NSAttributedString {
+ switch self {
+ case let .string(title, textAttributes):
+
+ let paragraphStyle = NSMutableParagraphStyle()
+ paragraphStyle.alignment = textAttributes.alignment
+
+ let attributes: [NSAttributedString.Key: Any] = [
+ .font: textAttributes.font,
+ .foregroundColor: textAttributes.color,
+ .paragraphStyle: paragraphStyle
+ ]
+
+ return NSAttributedString(string: title, attributes: attributes)
+
+ case .attributedString(let attributedTitle):
+ return attributedTitle
+ }
+ }
+
+ /// Method that calculates size of view text using given max width and height arguments.
+ ///
+ /// - Parameters:
+ /// - maxWidth: The width constraint to apply when computing the string’s bounding rectangle.
+ /// - maxHeight: The width constraint to apply when computing the string’s bounding rectangle.
+ /// - Returns: Returns the size required to draw the text.
+ func size(maxWidth: CGFloat = CGFloat.greatestFiniteMagnitude,
+ maxHeight: CGFloat = CGFloat.greatestFiniteMagnitude) -> CGSize {
+
+ return attributedString.boundingRect(with: CGSize(width: maxWidth, height: maxHeight),
+ options: [.usesLineFragmentOrigin, .usesFontLeading],
+ context: nil).size
+ }
+
+ /// Configures given ViewTextConfigurable instance.
+ ///
+ /// - Parameter view: ViewTextConfigurable instance to configure with ViewText.
+ func configure(view: ViewTextConfigurable) {
+ view.configure(with: self)
+ }
+}
diff --git a/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/UIButton+ViewTextConfigurable.swift b/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/UIButton+ViewTextConfigurable.swift
new file mode 100644
index 00000000..de0e5e5f
--- /dev/null
+++ b/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/UIButton+ViewTextConfigurable.swift
@@ -0,0 +1,121 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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.UIButton
+
+extension UIButton: ViewTextConfigurable {
+
+ public var textFont: UIFont? {
+ get {
+ return titleLabel?.font
+ }
+ set {
+ titleLabel?.font = newValue
+ }
+ }
+
+ public var titleColor: UIColor? {
+ get {
+ return currentTitleColor
+ }
+ set {
+ setTitleColor(newValue, for: [])
+ }
+ }
+
+ public var textAlignment: NSTextAlignment {
+ get {
+ return contentHorizontalAlignment.textAlignment
+ }
+ set {
+ contentHorizontalAlignment = .init(textAlignment: newValue)
+ }
+ }
+
+ public var text: String? {
+ get {
+ return currentTitle
+ }
+ set {
+ setTitle(newValue, for: [])
+ }
+ }
+
+ public var attributedText: NSAttributedString? {
+ get {
+ return currentAttributedTitle
+ }
+ set {
+ setAttributedTitle(newValue, for: [])
+ }
+ }
+}
+
+private extension UIControl.ContentHorizontalAlignment {
+
+ init(textAlignment: NSTextAlignment) {
+ switch textAlignment {
+ case .left:
+ self = .leading
+
+ case .right:
+ self = .trailing
+
+ case .center:
+ self = .center
+
+ case .justified:
+ self = .fill
+
+ case .natural:
+ self = .leading
+
+ @unknown default:
+ self = .leading
+ }
+ }
+
+ var textAlignment: NSTextAlignment {
+ switch self {
+ case .left:
+ return .left
+
+ case .right:
+ return .right
+
+ case .center:
+ return .center
+
+ case .fill:
+ return .justified
+
+ case .leading:
+ return .natural
+
+ case .trailing:
+ return .right
+
+ @unknown default:
+ return .natural
+ }
+ }
+}
diff --git a/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/UILabel+ViewTextConfigurable.swift b/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/UILabel+ViewTextConfigurable.swift
new file mode 100644
index 00000000..8418ffa4
--- /dev/null
+++ b/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/UILabel+ViewTextConfigurable.swift
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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.UILabel
+
+extension UILabel: ViewTextConfigurable {
+
+ public var textFont: UIFont? {
+ get {
+ return font
+ }
+ set {
+ font = newValue
+ }
+ }
+
+ public var titleColor: UIColor? {
+ get {
+ return textColor
+ }
+ set {
+ textColor = newValue
+ }
+ }
+}
diff --git a/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/UITextField+ViewTextConfigurable.swift b/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/UITextField+ViewTextConfigurable.swift
new file mode 100644
index 00000000..eaa2ce79
--- /dev/null
+++ b/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/UITextField+ViewTextConfigurable.swift
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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.UITextField
+
+extension UITextField: ViewTextConfigurable {
+
+ public var textFont: UIFont? {
+ get {
+ return font
+ }
+ set {
+ font = newValue
+ }
+ }
+
+ public var titleColor: UIColor? {
+ get {
+ return textColor
+ }
+ set {
+ textColor = newValue
+ }
+ }
+}
diff --git a/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/ViewTextConfigurable.swift b/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/ViewTextConfigurable.swift
new file mode 100644
index 00000000..dfd7256c
--- /dev/null
+++ b/TIUIKitCore/Sources/ViewText/ViewTextConfigurable/ViewTextConfigurable.swift
@@ -0,0 +1,69 @@
+//
+// Copyright (c) 2020 Touch Instinct
+//
+// 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.UIFont
+import UIKit.UIColor
+
+/// Protocol that represents text object with appearance attributes.
+public protocol ViewTextConfigurable: AnyObject {
+
+ /// Font of text object.
+ var textFont: UIFont? { get set }
+
+ /// Text color of text object.
+ var titleColor: UIColor? { get set }
+
+ /// Text alignment of text object.
+ var textAlignment: NSTextAlignment { get set }
+
+ /// Text itself of text object.
+ var text: String? { get set }
+
+ /// Attributed text of text object.
+ var attributedText: NSAttributedString? { get set }
+}
+
+public extension ViewTextConfigurable {
+
+ /// Configures text and text appearance of view using ViewText object.
+ ///
+ /// - Parameter viewText: ViewText object with text and text appearance.
+ func configure(with viewText: ViewText) {
+ switch viewText {
+ case let .string(text, textAttributes):
+ self.text = text
+ self.configureBaseAppearance(with: textAttributes)
+
+ case .attributedString(let attributedString):
+ self.attributedText = attributedString
+ }
+ }
+
+ /// Configures text appearance of view.
+ ///
+ /// - Parameter baseTextAttributes: Set of attributes to configure appearance of text.
+ func configureBaseAppearance(with baseTextAttributes: BaseTextAttributes) {
+ textFont = baseTextAttributes.font
+ titleColor = baseTextAttributes.color
+ textAlignment = baseTextAttributes.alignment
+ }
+}
diff --git a/TIUIKitCore/TIUIKitCore.podspec b/TIUIKitCore/TIUIKitCore.podspec
new file mode 100644
index 00000000..bd49a66e
--- /dev/null
+++ b/TIUIKitCore/TIUIKitCore.podspec
@@ -0,0 +1,15 @@
+Pod::Spec.new do |s|
+ s.name = 'TIUIKitCore'
+ s.version = '0.11.0'
+ s.summary = 'Core UI elements: protocols, views and helpers.'
+ s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
+ s.license = { :type => 'MIT', :file => 'LICENSE' }
+ s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
+ s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
+
+ s.ios.deployment_target = '11.0'
+ s.swift_versions = ['5.3']
+
+ s.source_files = s.name + '/Sources/**/*'
+ s.framework = 'UIKit'
+end