Merge branch 'feature/skeletons_api' into feature/skeletons_docs

This commit is contained in:
Nikita Semenov 2023-03-07 14:42:07 +03:00
commit e942d08503
45 changed files with 246 additions and 251 deletions

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "build-scripts"]
path = build-scripts
url = https://github.com/TouchInstinct/BuildScripts.git
url = https://gitlab.ti/touchinstinct/BuildScripts.git

View File

@ -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

View File

@ -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']

View File

@ -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"),

View File

@ -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'

View File

@ -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']

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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']

View File

@ -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 }
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}
}

View File

@ -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()
}
}

View File

@ -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' }

View File

@ -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' }

View File

@ -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' }

View File

@ -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

View File

@ -5,7 +5,6 @@ TIKeychainUtils
TIUIKitCore
TISwiftUICore
TIUIElements
TILogging
TIAuth
TITableKitUtils
TINetworking
@ -17,4 +16,4 @@ TIGoogleMapUtils
TIYandexMapUtils
TIEcommerce
TIWebView
TIDeveloperUtils
TIDeveloperUtils

View File

@ -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