Merge branch 'feature/skeletons_api' into feature/skeletons_docs
This commit is contained in:
commit
e942d08503
|
|
@ -1,3 +1,3 @@
|
|||
[submodule "build-scripts"]
|
||||
path = build-scripts
|
||||
url = https://github.com/TouchInstinct/BuildScripts.git
|
||||
url = https://gitlab.ti/touchinstinct/BuildScripts.git
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
# Changelog
|
||||
|
||||
### 1.37.0
|
||||
|
||||
- **Added**: API for converting view hierarchy to skeletons
|
||||
|
||||
### 1.36.0
|
||||
|
||||
- **Added**: API for converting view hierarchy to skeletons
|
||||
- **Removed**: `TILogger`module
|
||||
- **Updated**: moved `LoggingPresenter` to `TIDeveloperUtils` module.
|
||||
|
||||
### 1.35.1
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ Pod::Spec.new do |s|
|
|||
s.name = "LeadKit"
|
||||
s.version = "1.35.0"
|
||||
s.summary = "iOS framework with a bunch of tools for rapid development"
|
||||
s.homepage = "https://github.com/TouchInstinct/LeadKit"
|
||||
s.homepage = "https://gitlab.ti/touchinstinct/LeadKit"
|
||||
s.license = "Apache License, Version 2.0"
|
||||
s.author = "Touch Instinct"
|
||||
s.source = { :git => "https://github.com/TouchInstinct/LeadKit.git", :tag => s.version }
|
||||
s.source = { :git => "https://gitlab.ti/touchinstinct/LeadKit.git", :tag => s.version }
|
||||
s.platform = :ios, '10.0'
|
||||
s.swift_versions = ['5.1']
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ let package = Package(
|
|||
.library(name: "TIFoundationUtils", targets: ["TIFoundationUtils"]),
|
||||
.library(name: "TIKeychainUtils", targets: ["TIKeychainUtils"]),
|
||||
.library(name: "TITableKitUtils", targets: ["TITableKitUtils"]),
|
||||
.library(name: "TILogging", targets: ["TILogging"]),
|
||||
.library(name: "TIDeveloperUtils", targets: ["TIDeveloperUtils"]),
|
||||
|
||||
// MARK: - Networking
|
||||
|
|
@ -67,8 +66,7 @@ let package = Package(
|
|||
.target(name: "TIFoundationUtils", dependencies: ["TISwiftUtils"], path: "TIFoundationUtils", exclude: ["TIFoundationUtils.app"]),
|
||||
.target(name: "TIKeychainUtils", dependencies: ["TIFoundationUtils", "KeychainAccess"], path: "TIKeychainUtils/Sources"),
|
||||
.target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"),
|
||||
.target(name: "TILogging", dependencies: ["TIUIElements", "TISwiftUtils", "TIUIKitCore"], path: "TILogging/Sources"),
|
||||
.target(name: "TIDeveloperUtils", dependencies: [], path: "TIDeveloperUtils/Sources"),
|
||||
.target(name: "TIDeveloperUtils", dependencies: ["TISwiftUtils", "TIUIKitCore", "TIUIElements"], path: "TIDeveloperUtils/Sources"),
|
||||
|
||||
// MARK: - Networking
|
||||
.target(name: "TINetworking", dependencies: ["TIFoundationUtils", "Alamofire"], path: "TINetworking/Sources"),
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ ${SRCROOT}/TIModuleName/TIModuleName.app"
|
|||
./setup
|
||||
```
|
||||
|
||||
- If legacy [Source](https://github.com/TouchInstinct/LeadKit/tree/master/Sources) folder needed, [build dependencies for LeadKit.xcodeproj](https://github.com/TouchInstinct/LeadKit/blob/master/docs/snippets.md#build-dependencies-for-LeadKit.xcodeproj).
|
||||
- If legacy [Source](https://gitlab.ti/touchinstinct/LeadKit/tree/master/Sources) folder needed, [build dependencies for LeadKit.xcodeproj](https://gitlab.ti/touchinstinct/LeadKit/blob/master/docs/snippets.md#build-dependencies-for-LeadKit.xcodeproj).
|
||||
|
||||
- Make sure the commit message codestyle is followed. More about [Semantic Commit Messages](docs/semantic-commit-messages.md).
|
||||
|
||||
|
|
@ -105,14 +105,14 @@ ${SRCROOT}/TIModuleName/TIModuleName.app"
|
|||
|
||||
```swift
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/TouchInstinct/LeadKit.git", from: "x.y.z"),
|
||||
.package(url: "https://gitlab.ti/touchinstinct/LeadKit.git", from: "x.y.z"),
|
||||
],
|
||||
```
|
||||
|
||||
### Cocoapods
|
||||
|
||||
```ruby
|
||||
source 'https://github.com/TouchInstinct/Podspecs.git'
|
||||
source 'https://gitlab.ti/touchinstinct/Podspecs.git'
|
||||
|
||||
pod 'TISwiftUtils', 'x.y.z'
|
||||
pod 'TIFoundationUtils', 'x.y.z'
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIAppleMapUtils'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Set of helpers for map objects clustering and interacting using Apple MapKit.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.homepage = 'https://gitlab.ti/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.source = { :git => 'https://gitlab.ti/touchinstinct/LeadKit.git', :tag => s.version.to_s }
|
||||
|
||||
s.ios.deployment_target = '11.0'
|
||||
s.swift_versions = ['5.3']
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIAuth'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Login, registration, confirmation and other related actions'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIDeveloperUtils'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Universal web view API'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIEcommerce'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Cart, products, promocodes, bonuses and other related actions'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIFoundationUtils'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.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' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIGoogleMapUtils'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Set of helpers for map objects clustering and interacting using Google Maps SDK.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIKeychainUtils'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Set of helpers for Keychain classes.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2022 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 Foundation
|
||||
import os
|
||||
|
||||
public struct TILogger: LoggerRepresentable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
@available(iOS 12, *)
|
||||
public static let defaultLogger = TILogger(subsystem: .defaultSubsystem ?? "", category: .pointsOfInterest)
|
||||
|
||||
public let logInfo: OSLog
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
public init(subsystem: String, category: String) {
|
||||
self.logInfo = .init(subsystem: subsystem, category: category)
|
||||
}
|
||||
|
||||
@available(iOS 12, *)
|
||||
public init(subsystem: String, category: OSLog.Category) {
|
||||
self.logInfo = .init(subsystem: subsystem, category: category)
|
||||
}
|
||||
|
||||
// MARK: - LoggerRepresentable
|
||||
|
||||
public func log(_ message: StaticString, log: OSLog?, type: OSLogType, _ arguments: CVarArg...) {
|
||||
os_log(message, log: log ?? logInfo, type: type, arguments)
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
public func verbose(_ message: StaticString, _ arguments: CVarArg...) {
|
||||
self.log(message, log: logInfo, type: .default, arguments)
|
||||
}
|
||||
|
||||
public func info(_ message: StaticString, _ arguments: CVarArg...) {
|
||||
self.log(message, log: logInfo, type: .info, arguments)
|
||||
}
|
||||
|
||||
public func debug(_ message: StaticString, _ arguments: CVarArg...) {
|
||||
self.log(message, log: logInfo, type: .debug, arguments)
|
||||
}
|
||||
|
||||
public func error(_ message: StaticString, _ arguments: CVarArg...) {
|
||||
self.log(message, log: logInfo, type: .error, arguments)
|
||||
}
|
||||
|
||||
public func fault(_ message: StaticString, _ arguments: CVarArg...) {
|
||||
self.log(message, log: logInfo, type: .fault, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
static let defaultSubsystem = Bundle.main.bundleIdentifier
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TILogging'
|
||||
s.version = '1.36.0'
|
||||
s.summary = 'Logging API'
|
||||
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',
|
||||
'castlele' => 'nikita.semenov@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
|
||||
s.dependency 'TISwiftUtils', s.version.to_s
|
||||
s.dependency 'TIUIElements', s.version.to_s
|
||||
|
||||
end
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
import Foundation
|
||||
import UIKit.UIGeometry
|
||||
|
||||
open class BaseMapManager<Map,
|
||||
open class BaseMapManager<Map: AnyObject,
|
||||
PM: PlacemarkManager,
|
||||
CPM: PlacemarkManager,
|
||||
CUF: CameraUpdateFactory> where PM.Position: LocationCoordinate,
|
||||
|
|
@ -79,16 +79,20 @@ open class BaseMapManager<Map,
|
|||
}
|
||||
|
||||
open func set(items: [PM.DataModel]) {
|
||||
let placemarkTapHandler: PM.TapHandlerClosure = { [map, selectPlacemarkHandler, animationDuration, cameraUpdateOnMarkerTap] model, location in
|
||||
cameraUpdateOnMarkerTap?(location).update(map: map, animationDuration: animationDuration)
|
||||
let placemarkTapHandler: PM.TapHandlerClosure = { [weak map, selectPlacemarkHandler, animationDuration, cameraUpdateOnMarkerTap] model, location in
|
||||
if let map = map {
|
||||
cameraUpdateOnMarkerTap?(location).update(map: map, animationDuration: animationDuration)
|
||||
}
|
||||
|
||||
return selectPlacemarkHandler(model)
|
||||
}
|
||||
|
||||
let placemarkManagers = items.compactMap { placemarkManagerCreator($0, placemarkTapHandler) }
|
||||
|
||||
let clusterTapHandler: CPM.TapHandlerClosure = { [map, animationDuration, cameraUpdateOnClusterTap] managers, boundingBox in
|
||||
cameraUpdateOnClusterTap?(boundingBox).update(map: map, animationDuration: animationDuration)
|
||||
let clusterTapHandler: CPM.TapHandlerClosure = { [weak map, animationDuration, cameraUpdateOnClusterTap] managers, boundingBox in
|
||||
if let map = map {
|
||||
cameraUpdateOnClusterTap?(boundingBox).update(map: map, animationDuration: animationDuration)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIMapUtils'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Set of helpers for map objects clustering and interacting.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIMoyaNetworking'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Moya + Swagger network service.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TINetworking'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Swagger-frendly networking layer helpers.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TINetworkingCache'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Caching results of EndpointRequests.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIPagination'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Generic pagination component.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TISwiftUICore'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.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' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TISwiftUtils'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.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' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TITableKitUtils'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.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' }
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ Pod::Spec.new do |s|
|
|||
s.name = 'TITransitions'
|
||||
s.version = '1.34.1'
|
||||
s.summary = 'Set of custom transitions to present controller. '
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.homepage = 'https://gitlab.ti/touchinstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
s.author = { 'Loupehope' => 'vladislav.suhomlinov@touchin.ru' }
|
||||
s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
|
||||
s.source = { :git => 'https://gitlab.ti/touchinstinct/LeadKit.git', :tag => s.version.to_s }
|
||||
|
||||
s.ios.deployment_target = '11.0'
|
||||
s.swift_versions = ['5.0']
|
||||
|
|
|
|||
|
|
@ -20,8 +20,33 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TIUIKitCore
|
||||
import UIKit
|
||||
|
||||
// MARK: - UITextView + is multiline
|
||||
|
||||
extension UITextView {
|
||||
var isMultiline: Bool {
|
||||
isMultiline(text: text,
|
||||
attributedText: attributedText,
|
||||
font: font,
|
||||
textAlignment: textAlignment)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UILabel + is multiline
|
||||
|
||||
extension UILabel {
|
||||
var isMultiline: Bool {
|
||||
isMultiline(text: text,
|
||||
attributedText: attributedText,
|
||||
font: font,
|
||||
textAlignment: textAlignment)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIView + Skeleton helpers
|
||||
|
||||
extension UIView {
|
||||
public var skeletonableViews: [UIView] {
|
||||
if let skeletonableView = self as? Skeletonable {
|
||||
|
|
@ -56,29 +81,39 @@ extension UIView {
|
|||
return .generic(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UITextView {
|
||||
var isMultiline: Bool {
|
||||
guard let text = attributedText?.string ?? text, let font = font else {
|
||||
fileprivate func isMultiline(text: String?,
|
||||
attributedText: NSAttributedString?,
|
||||
font: UIFont?,
|
||||
textAlignment: NSTextAlignment) -> Bool {
|
||||
let _text: String
|
||||
let _font: UIFont
|
||||
|
||||
if let attributedText = attributedText, let maxFont = attributedText.getMaxFont() {
|
||||
_text = attributedText.string
|
||||
_font = maxFont
|
||||
|
||||
} else if let text = text, let font = font {
|
||||
_text = text
|
||||
_font = font
|
||||
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
let labelTextSize = (text as NSString).size(withAttributes: [.font: font])
|
||||
let textAttributes = BaseTextAttributes(font: _font, color: .black, alignment: textAlignment, isMultiline: true)
|
||||
let labelTextSize = textAttributes.size(of: _text, with: .zero)
|
||||
|
||||
return labelTextSize.width > bounds.width
|
||||
}
|
||||
}
|
||||
|
||||
extension UILabel {
|
||||
var isMultiline: Bool {
|
||||
// Unwrapping font to mute warning while casting UIFont! to Any
|
||||
guard let text = attributedText?.string ?? text, let font = font else {
|
||||
return false
|
||||
}
|
||||
// MARK: - NSAttributedString helper extension
|
||||
|
||||
let labelTextSize = (text as NSString).size(withAttributes: [.font: font])
|
||||
|
||||
return labelTextSize.width > bounds.width
|
||||
extension NSAttributedString {
|
||||
func getMaxFont() -> UIFont? {
|
||||
(0..<self.length)
|
||||
.compactMap { attribute(.font, at: $0, effectiveRange: nil) as? UIFont }
|
||||
.max { $0.pointSize < $1.pointSize }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
import UIKit
|
||||
|
||||
public protocol SkeletonsPresenter {
|
||||
var baseView: UIView? { get }
|
||||
var skeletonsConfiguration: SkeletonsConfiguration { get }
|
||||
var isSkeletonsHidden: Bool { get }
|
||||
var viewsToSkeletone: [UIView] { get }
|
||||
|
|
@ -41,88 +40,11 @@ extension SkeletonsPresenter {
|
|||
public var skeletonsConfiguration: SkeletonsConfiguration {
|
||||
SkeletonsConfiguration()
|
||||
}
|
||||
|
||||
public func showSkeletons() {
|
||||
guard let baseView = baseView else {
|
||||
return
|
||||
}
|
||||
|
||||
baseView.isUserInteractionEnabled = false
|
||||
|
||||
viewsToSkeletone
|
||||
.flatMap { view in
|
||||
view.isHidden = true
|
||||
|
||||
return getSkeletonLayer(forView: view)
|
||||
}
|
||||
.map { layer in
|
||||
layer.startAnimation()
|
||||
|
||||
return layer
|
||||
}
|
||||
.insert(onto: baseView)
|
||||
}
|
||||
|
||||
public func hideSkeletons() {
|
||||
guard let baseView = baseView else {
|
||||
return
|
||||
}
|
||||
|
||||
baseView.isUserInteractionEnabled = true
|
||||
|
||||
baseView.layer.sublayers?.forEach { layer in
|
||||
if let layer = layer as? SkeletonLayer {
|
||||
layer.remove(from: baseView)
|
||||
}
|
||||
}
|
||||
|
||||
baseView.skeletonableViews.forEach {
|
||||
$0.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
public func startAnimation() {
|
||||
baseView?.layer.skeletonLayers.forEach { layer in
|
||||
layer.startAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
public func stopAnimation() {
|
||||
baseView?.layer.skeletonLayers.forEach { layer in
|
||||
layer.stopAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func getSkeletonLayer(forView view: UIView) -> [SkeletonLayer] {
|
||||
let skeletonLayer = skeletonsConfiguration.createSkeletonLayer(for: baseView)
|
||||
var subviewSkeletonLayers = [SkeletonLayer]()
|
||||
|
||||
if view.isSkeletonsContainer {
|
||||
if skeletonsConfiguration.borderWidth != .zero {
|
||||
skeletonLayer.bind(to: .container(view))
|
||||
}
|
||||
|
||||
subviewSkeletonLayers = view.skeletonableViews
|
||||
.map(getSkeletonLayer(forView:))
|
||||
.flatMap { $0 }
|
||||
|
||||
} else {
|
||||
skeletonLayer.bind(to: view.viewType)
|
||||
}
|
||||
|
||||
return [skeletonLayer] + subviewSkeletonLayers
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIView + SkeletonsPresenter
|
||||
|
||||
extension SkeletonsPresenter where Self: UIView {
|
||||
public var baseView: UIView? {
|
||||
self
|
||||
}
|
||||
|
||||
public var isSkeletonsHidden: Bool {
|
||||
(layer.sublayers ?? []).first { $0 is SkeletonLayer } == nil
|
||||
}
|
||||
|
|
@ -130,30 +52,26 @@ extension SkeletonsPresenter where Self: UIView {
|
|||
public var viewsToSkeletone: [UIView] {
|
||||
skeletonableViews
|
||||
}
|
||||
|
||||
public func showSkeletons() {
|
||||
showSkeletons(viewsToSkeletone: viewsToSkeletone,
|
||||
skeletonsConfiguration)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIViewController + SkeletonsPresenter
|
||||
|
||||
extension SkeletonsPresenter where Self: UIViewController {
|
||||
public var baseView: UIView? {
|
||||
view
|
||||
}
|
||||
|
||||
public var isSkeletonsHidden: Bool {
|
||||
(view.layer.sublayers ?? []).first { $0 is SkeletonLayer } == nil
|
||||
}
|
||||
|
||||
public var viewsToSkeletone: [UIView] {
|
||||
baseView?.skeletonableViews ?? view.skeletonableViews
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helper extension
|
||||
|
||||
extension Array where Element: CALayer {
|
||||
public func insert(onto view: UIView, at index: UInt32 = .max) {
|
||||
self.forEach { subLayer in
|
||||
view.layer.insertSublayer(subLayer, at: index)
|
||||
}
|
||||
view.skeletonableViews
|
||||
}
|
||||
|
||||
public func showSkeletons() {
|
||||
showSkeletons(viewsToSkeletone: viewsToSkeletone,
|
||||
skeletonsConfiguration)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
//
|
||||
// Copyright (c) 2023 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
|
||||
|
||||
extension UIView {
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
/// Shows skeletons on the view
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - viewsToSkeletone: views that will be converted to skeletones. If nil was passed subviews will be converted to skeletons
|
||||
/// - config: configuration of the skeletons' layers
|
||||
public func showSkeletons(viewsToSkeletone: [UIView]?,
|
||||
_ config: SkeletonsConfiguration) {
|
||||
|
||||
let viewsToSkeletone = viewsToSkeletone ?? skeletonableViews
|
||||
isUserInteractionEnabled = false
|
||||
|
||||
subviews.forEach { $0.isHidden = true }
|
||||
|
||||
viewsToSkeletone
|
||||
.flatMap { view in
|
||||
getSkeletonLayer(forView: view, withConfiguration: config)
|
||||
}
|
||||
.map { layer in
|
||||
layer.startAnimation()
|
||||
|
||||
return layer
|
||||
}
|
||||
.insert(onto: self)
|
||||
}
|
||||
|
||||
public func hideSkeletons() {
|
||||
isUserInteractionEnabled = true
|
||||
|
||||
layer.sublayers?.forEach { layer in
|
||||
if let layer = layer as? SkeletonLayer {
|
||||
layer.remove(from: self)
|
||||
}
|
||||
}
|
||||
|
||||
subviews.forEach { $0.isHidden = false}
|
||||
}
|
||||
|
||||
public func startAnimation() {
|
||||
layer.skeletonLayers.forEach { layer in
|
||||
layer.startAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
public func stopAnimation() {
|
||||
layer.skeletonLayers.forEach { layer in
|
||||
layer.stopAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func getSkeletonLayer(forView view: UIView,
|
||||
withConfiguration conf: SkeletonsConfiguration) -> [SkeletonLayer] {
|
||||
|
||||
let skeletonLayer = conf.createSkeletonLayer(for: self)
|
||||
var subviewSkeletonLayers = [SkeletonLayer]()
|
||||
|
||||
if view.isSkeletonsContainer {
|
||||
if conf.borderWidth != .zero {
|
||||
skeletonLayer.bind(to: .container(view))
|
||||
}
|
||||
|
||||
subviewSkeletonLayers = view.skeletonableViews
|
||||
.map { getSkeletonLayer(forView: $0, withConfiguration: conf) }
|
||||
.flatMap { $0 }
|
||||
|
||||
} else {
|
||||
skeletonLayer.bind(to: view.viewType)
|
||||
}
|
||||
|
||||
return [skeletonLayer] + subviewSkeletonLayers
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helper extension
|
||||
|
||||
extension Array where Element: CALayer {
|
||||
public func insert(onto view: UIView, at index: UInt32 = .max) {
|
||||
self.forEach { subLayer in
|
||||
view.layer.insertSublayer(subLayer, at: index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2022 Touch Instinct
|
||||
// Copyright (c) 2023 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
|
||||
|
|
@ -20,8 +20,30 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import os
|
||||
import UIKit
|
||||
|
||||
public protocol LoggerRepresentable {
|
||||
func log(_ message: StaticString, log: OSLog?, type: OSLogType, _ arguments: CVarArg...)
|
||||
extension UIViewController {
|
||||
|
||||
/// Shows skeletons
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - viewsToSkeletone: views that will be converted to skeletones. If nil was passed subviews of the view will be converted to skeletons
|
||||
/// - config: configuration of the skeletons' layers
|
||||
public func showSkeletons(viewsToSkeletone: [UIView]?,
|
||||
_ config: SkeletonsConfiguration) {
|
||||
|
||||
view.showSkeletons(viewsToSkeletone: viewsToSkeletone, config)
|
||||
}
|
||||
|
||||
public func hideSkeletons() {
|
||||
view.hideSkeletons()
|
||||
}
|
||||
|
||||
public func startAnimation() {
|
||||
view.startAnimation()
|
||||
}
|
||||
|
||||
public func stopAnimation() {
|
||||
view.stopAnimation()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIUIElements'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.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' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIUIKitCore'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.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' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIWebView'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Universal web view API'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIYandexMapUtils'
|
||||
s.version = '1.36.0'
|
||||
s.version = '1.37.0'
|
||||
s.summary = 'Set of helpers for map objects clustering and interacting using Yandex Maps SDK.'
|
||||
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 = '10.0'
|
||||
s.ios.deployment_target = '12.0'
|
||||
s.swift_versions = ['5.3']
|
||||
|
||||
s.source_files = s.name + '/Sources/**/*'
|
||||
|
|
@ -17,5 +17,5 @@ Pod::Spec.new do |s|
|
|||
s.pod_target_xcconfig = { 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
|
||||
|
||||
s.dependency 'TIMapUtils', s.version.to_s
|
||||
s.dependency 'YandexMapsMobile', '4.0.0-lite'
|
||||
s.dependency 'YandexMapsMobile', '4.3.1-lite'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ TIKeychainUtils
|
|||
TIUIKitCore
|
||||
TISwiftUICore
|
||||
TIUIElements
|
||||
TILogging
|
||||
TIAuth
|
||||
TITableKitUtils
|
||||
TINetworking
|
||||
|
|
@ -17,4 +16,4 @@ TIGoogleMapUtils
|
|||
TIYandexMapUtils
|
||||
TIEcommerce
|
||||
TIWebView
|
||||
TIDeveloperUtils
|
||||
TIDeveloperUtils
|
||||
|
|
|
|||
|
|
@ -14,5 +14,5 @@
|
|||
#
|
||||
|
||||
for module_name in $(cat ${SRCROOT}/project-scripts/ordered_modules_list.txt); do
|
||||
bundle exec pod repo push git@github.com:TouchInstinct/Podspecs ${SRCROOT}/${module_name}/${module_name}.podspec "$@" --allow-warnings
|
||||
bundle exec pod repo push git@gitlab.ti:touchinstinct/Podspecs ${SRCROOT}/${module_name}/${module_name}.podspec "$@" --allow-warnings
|
||||
done
|
||||
|
|
|
|||
Loading…
Reference in New Issue