diff --git a/CHANGELOG.md b/CHANGELOG.md index a245bf89..efa04a5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +### 1.54.0 + +- **Added**: `maxWidth` parameter to `BaseViewSkeletonsConfiguration`. +- **Added**: custom `SkeletonConfigurations` for nested `SkeletonPresenters`. +- **Update**: Many fixes and improvenments to `TextSkeletonsConfiguration`. + ### 1.53.3 - **Update**: `Skeletonable` can now control custom geometry change notification. diff --git a/TIAppleMapUtils/TIAppleMapUtils.podspec b/TIAppleMapUtils/TIAppleMapUtils.podspec index c4ab11b6..ef091860 100644 --- a/TIAppleMapUtils/TIAppleMapUtils.podspec +++ b/TIAppleMapUtils/TIAppleMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIAppleMapUtils' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Set of helpers for map objects clustering and interacting using Apple MapKit.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIApplication/TIApplication.podspec b/TIApplication/TIApplication.podspec index 2815d18f..a2f31525 100644 --- a/TIApplication/TIApplication.podspec +++ b/TIApplication/TIApplication.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIApplication' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Application architecture.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIAuth/TIAuth.podspec b/TIAuth/TIAuth.podspec index a31bcfef..e5dbfb76 100644 --- a/TIAuth/TIAuth.podspec +++ b/TIAuth/TIAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIAuth' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Login, registration, confirmation and other related actions' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIBottomSheet/TIBottomSheet.podspec b/TIBottomSheet/TIBottomSheet.podspec index 78ac61d2..befe01e1 100644 --- a/TIBottomSheet/TIBottomSheet.podspec +++ b/TIBottomSheet/TIBottomSheet.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIBottomSheet' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Base models for creating bottom sheet view controllers' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TICoreGraphicsUtils/TICoreGraphicsUtils.podspec b/TICoreGraphicsUtils/TICoreGraphicsUtils.podspec index fcee874b..3e2b9950 100644 --- a/TICoreGraphicsUtils/TICoreGraphicsUtils.podspec +++ b/TICoreGraphicsUtils/TICoreGraphicsUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TICoreGraphicsUtils' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'CoreGraphics drawing helpers' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIDeeplink/TIDeeplink.podspec b/TIDeeplink/TIDeeplink.podspec index b4b7c10a..0c2a4fc4 100644 --- a/TIDeeplink/TIDeeplink.podspec +++ b/TIDeeplink/TIDeeplink.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIDeeplink' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Deeplink service API' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIDeveloperUtils/TIDeveloperUtils.podspec b/TIDeveloperUtils/TIDeveloperUtils.podspec index 595d380f..704552d2 100644 --- a/TIDeveloperUtils/TIDeveloperUtils.podspec +++ b/TIDeveloperUtils/TIDeveloperUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIDeveloperUtils' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Universal web view API' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIEcommerce/TIEcommerce.podspec b/TIEcommerce/TIEcommerce.podspec index a5829e54..f8bbd893 100644 --- a/TIEcommerce/TIEcommerce.podspec +++ b/TIEcommerce/TIEcommerce.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIEcommerce' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Cart, products, promocodes, bonuses and other related actions' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIFoundationUtils/TIFoundationUtils.podspec b/TIFoundationUtils/TIFoundationUtils.podspec index b6394b95..9fe349c7 100644 --- a/TIFoundationUtils/TIFoundationUtils.podspec +++ b/TIFoundationUtils/TIFoundationUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIFoundationUtils' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Set of helpers for Foundation framework classes.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIGoogleMapUtils/TIGoogleMapUtils.podspec b/TIGoogleMapUtils/TIGoogleMapUtils.podspec index c19a21ad..610299c9 100644 --- a/TIGoogleMapUtils/TIGoogleMapUtils.podspec +++ b/TIGoogleMapUtils/TIGoogleMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIGoogleMapUtils' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Set of helpers for map objects clustering and interacting using Google Maps SDK.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIKeychainUtils/TIKeychainUtils.podspec b/TIKeychainUtils/TIKeychainUtils.podspec index 8484828f..43cab733 100644 --- a/TIKeychainUtils/TIKeychainUtils.podspec +++ b/TIKeychainUtils/TIKeychainUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIKeychainUtils' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Set of helpers for Keychain classes.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TILogging/TILogging.podspec b/TILogging/TILogging.podspec index 36306ba8..f1d3c81d 100644 --- a/TILogging/TILogging.podspec +++ b/TILogging/TILogging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TILogging' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Logging for TI libraries.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIMapUtils/TIMapUtils.podspec b/TIMapUtils/TIMapUtils.podspec index d5206212..a8ae9dc7 100644 --- a/TIMapUtils/TIMapUtils.podspec +++ b/TIMapUtils/TIMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIMapUtils' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Set of helpers for map objects clustering and interacting.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIMoyaNetworking/TIMoyaNetworking.podspec b/TIMoyaNetworking/TIMoyaNetworking.podspec index 37163d08..269cd14f 100644 --- a/TIMoyaNetworking/TIMoyaNetworking.podspec +++ b/TIMoyaNetworking/TIMoyaNetworking.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIMoyaNetworking' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Moya + Swagger network service.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TINetworking/TINetworking.podspec b/TINetworking/TINetworking.podspec index 6da4bca1..812191a3 100644 --- a/TINetworking/TINetworking.podspec +++ b/TINetworking/TINetworking.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TINetworking' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Swagger-frendly networking layer helpers.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TINetworkingCache/TINetworkingCache.podspec b/TINetworkingCache/TINetworkingCache.podspec index da034303..b8ef2d10 100644 --- a/TINetworkingCache/TINetworkingCache.podspec +++ b/TINetworkingCache/TINetworkingCache.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TINetworkingCache' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Caching results of EndpointRequests.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIPagination/TIPagination.podspec b/TIPagination/TIPagination.podspec index fcded26d..36ee1cec 100644 --- a/TIPagination/TIPagination.podspec +++ b/TIPagination/TIPagination.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIPagination' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Generic pagination component.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TISwiftUICore/TISwiftUICore.podspec b/TISwiftUICore/TISwiftUICore.podspec index d7857c53..5e224585 100644 --- a/TISwiftUICore/TISwiftUICore.podspec +++ b/TISwiftUICore/TISwiftUICore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TISwiftUICore' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Core UI elements: protocols, views and helpers.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TISwiftUtils/TISwiftUtils.podspec b/TISwiftUtils/TISwiftUtils.podspec index e12f194e..c3e7fc40 100644 --- a/TISwiftUtils/TISwiftUtils.podspec +++ b/TISwiftUtils/TISwiftUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TISwiftUtils' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Bunch of useful helpers for Swift development.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TITableKitUtils/TITableKitUtils.podspec b/TITableKitUtils/TITableKitUtils.podspec index 4801e01b..1626ddea 100644 --- a/TITableKitUtils/TITableKitUtils.podspec +++ b/TITableKitUtils/TITableKitUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TITableKitUtils' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Set of helpers for TableKit classes.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TITextProcessing/TITextProcessing.podspec b/TITextProcessing/TITextProcessing.podspec index dd218cff..11d0cbb1 100644 --- a/TITextProcessing/TITextProcessing.podspec +++ b/TITextProcessing/TITextProcessing.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TITextProcessing' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'A text processing service helping to get a text mask and a placeholder from incoming regex.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIUIElements/Sources/Views/Skeletons/Configuration/BaseViewSkeletonsConfiguration.swift b/TIUIElements/Sources/Views/Skeletons/Configuration/BaseViewSkeletonsConfiguration.swift index 82c65412..fc1c94f6 100644 --- a/TIUIElements/Sources/Views/Skeletons/Configuration/BaseViewSkeletonsConfiguration.swift +++ b/TIUIElements/Sources/Views/Skeletons/Configuration/BaseViewSkeletonsConfiguration.swift @@ -32,28 +32,46 @@ open class BaseViewSkeletonsConfiguration { } public var padding: UIEdgeInsets + public var maxWidth: CGFloat public var shape: Shape - public init(padding: UIEdgeInsets = .edges(5), shape: Shape = .rectangle(cornerRadius: .zero)) { + public init(padding: UIEdgeInsets = .edges(5), + maxWidth: CGFloat = .infinity, + shape: Shape = .rectangle(cornerRadius: .zero)) { + self.shape = shape + self.maxWidth = maxWidth self.padding = padding } - open func drawPath(rect: CGRect) -> CGPath { + open func createPath(for rect: CGRect) -> CGPath { + let adjustedRect = rect.reduceSize(byPadding: padding) + .with(maxWidth: maxWidth) + switch shape { case let .custom(path): return path case let .rectangle(cornerRadius: cornerRadius): - let path = UIBezierPath(roundedRect: rect.reduceSize(byPadding: padding), cornerRadius: cornerRadius) - return path.cgPath + return UIBezierPath(roundedRect: adjustedRect, + cornerRadius: cornerRadius).cgPath case .circle: - return CGPath(ellipseIn: rect.reduceSize(byPadding: padding), transform: nil) + return CGPath(ellipseIn: adjustedRect, + transform: nil) } } open func applyPadding(viewFrame: CGRect) -> CGRect { viewFrame.with(padding: padding) } + + open func copyWith(padding: UIEdgeInsets? = nil, + maxWidth: CGFloat? = nil, + shape: Shape? = nil) -> BaseViewSkeletonsConfiguration { + + BaseViewSkeletonsConfiguration(padding: padding ?? self.padding, + maxWidth: maxWidth ?? self.maxWidth, + shape: shape ?? self.shape) + } } diff --git a/TIUIElements/Sources/Views/Skeletons/Configuration/ContainerViewSkeletonsConfiguration.swift b/TIUIElements/Sources/Views/Skeletons/Configuration/ContainerViewSkeletonsConfiguration.swift index 98fc81ea..d44adeef 100644 --- a/TIUIElements/Sources/Views/Skeletons/Configuration/ContainerViewSkeletonsConfiguration.swift +++ b/TIUIElements/Sources/Views/Skeletons/Configuration/ContainerViewSkeletonsConfiguration.swift @@ -28,10 +28,22 @@ open class ContainerViewSkeletonsConfiguration: BaseViewSkeletonsConfiguration { public init(borderWidth: CGFloat = .zero, padding: UIEdgeInsets = .zero, + maxWidth: CGFloat = .infinity, shape: Shape = .rectangle(cornerRadius: .zero)) { self.borderWidth = borderWidth super.init(padding: padding, shape: shape) } + + open func copyWith(borderWidth: CGFloat? = nil, + padding: UIEdgeInsets? = nil, + maxWidth: CGFloat? = nil, + shape: Shape? = nil) -> ContainerViewSkeletonsConfiguration { + + ContainerViewSkeletonsConfiguration(borderWidth: borderWidth ?? self.borderWidth, + padding: padding ?? self.padding, + maxWidth: maxWidth ?? self.maxWidth, + shape: shape ?? self.shape) + } } diff --git a/TIUIElements/Sources/Views/Skeletons/Configuration/TextSkeletonsConfiguration.swift b/TIUIElements/Sources/Views/Skeletons/Configuration/TextSkeletonsConfiguration.swift index 4819e742..29f039f8 100644 --- a/TIUIElements/Sources/Views/Skeletons/Configuration/TextSkeletonsConfiguration.swift +++ b/TIUIElements/Sources/Views/Skeletons/Configuration/TextSkeletonsConfiguration.swift @@ -26,35 +26,68 @@ import UIKit open class TextSkeletonsConfiguration: BaseViewSkeletonsConfiguration { - private enum Constants { - static var defaultNumberOfLines: Int { + public enum Defaults { + public static var numberOfLines: Int { + 1 + } + + public static var multilineNumberOfLines: Int { 3 } + + public static var linesWidthFraction: [CGFloat] { + [1, 0.65, 0.78] + } + + public static var defaultFont: UIFont { + .systemFont(ofSize: 15) + } } - private var isMultiline = false - private var labelNumberOfLines: Int = .zero - private var labelHeight: CGFloat = .zero - private var font: UIFont? + public var numberOfLines: Int + public var linesWidthFraction: [CGFloat] + public var lineHeight: CGFloat? + public var lineSpacing: CGFloat? - public var numberOfLines: Int? - public var lineHeight: Closure? - public var lineSpacing: Closure? - - public init(numberOfLines: Int? = nil, - lineHeight: Closure? = nil, - lineSpacing: Closure? = nil, + public init(numberOfLines: Int = Defaults.numberOfLines, + linesWidthFraction: [CGFloat] = Defaults.linesWidthFraction, + lineHeight: CGFloat? = nil, + lineSpacing: CGFloat? = nil, padding: UIEdgeInsets = .edges(5), + maxWidth: CGFloat = .infinity, shape: Shape = .rectangle(cornerRadius: .zero)) { self.numberOfLines = numberOfLines + self.linesWidthFraction = linesWidthFraction self.lineHeight = lineHeight self.lineSpacing = lineSpacing super.init(padding: padding, shape: shape) } - open override func drawPath(rect: CGRect) -> CGPath { + open func createConfiguration(for label: UILabel) -> TextSkeletonsConfiguration { + let labelFont = getFont(from: label) + + return copyWith(numberOfLines: label.numberOfLines, + lineHeight: calculateLineHeight(for: labelFont), + lineSpacing: calculateLineSpacing(for: labelFont), + padding: padding, + maxWidth: maxWidth, + shape: shape) + } + + open func createConfiguration(for textView: UITextView) -> TextSkeletonsConfiguration { + let labelFont = getFont(from: textView) + + return copyWith(numberOfLines: textView.textContainer.maximumNumberOfLines, + lineHeight: calculateLineHeight(for: labelFont), + lineSpacing: calculateLineSpacing(for: labelFont), + padding: padding, + maxWidth: maxWidth, + shape: shape) + } + + open override func createPath(for rect: CGRect) -> CGPath { /* SkeletonLayer |-------------------------| @@ -65,10 +98,10 @@ open class TextSkeletonsConfiguration: BaseViewSkeletonsConfiguration { ||-----------------------|| - third line CGRect(0, (lineHeight + spacing) * 2, rect.width, lineHeight) |-------------------------| */ + let adjustedRect = rect.reduceSize(byPadding: padding).with(maxWidth: maxWidth) let path = UIBezierPath() - let numberOfLines = getNumberOfLines() - let spacing = getLineSpacing() - let lineHeight = getLineHeight() + let spacing = lineSpacing ?? calculateLineSpacing(for: Defaults.defaultFont) + let lineHeight = self.lineHeight ?? calculateLineHeight(for: Defaults.defaultFont) var cornerRadius = CGFloat.zero if case let .rectangle(cornerRadius: radius) = shape { @@ -76,17 +109,27 @@ open class TextSkeletonsConfiguration: BaseViewSkeletonsConfiguration { } for lineNumber in 0.. CGPath { - if case let .custom(path) = shape { - return path + open func getFont(from textView: UITextView) -> UIFont { + guard let attributedText = textView.attributedText else { + return textView.font ?? Defaults.defaultFont } - isMultiline = label.isMultiline - font = label.font - labelNumberOfLines = label.numberOfLines - labelHeight = label.bounds.height - - return drawPath(rect: label.bounds.reduceSize(byPadding: padding)) + return getBiggestFont(from: attributedText) } - open func configureTextViewPath(textView: UITextView) -> CGPath { - if case let .custom(path) = shape { - return path + open func getFont(from label: UILabel) -> UIFont { + guard let attributedText = label.attributedText else { + return label.font } - isMultiline = textView.isMultiline - font = textView.font - labelNumberOfLines = textView.textContainer.maximumNumberOfLines - labelHeight = textView.bounds.height - - return drawPath(rect: textView.bounds.reduceSize(byPadding: padding)) + return getBiggestFont(from: attributedText) } - // MARK: - Private methods + open func getBiggestFont(from attributedString: NSAttributedString) -> UIFont { + let text = attributedString.string - private func getLineHeight() -> CGFloat { - if let lineHeight = lineHeight?(font) { - return lineHeight + var biggestFont: UIFont = .systemFont(ofSize: 1) + + attributedString.enumerateAttributes(in: NSRange(text.startIndex..., in: text)) { attributes, _, _ in + guard let fontValue = attributes[.font] as? UIFont else { + return + } + + if fontValue.lineHeight > biggestFont.lineHeight { + biggestFont = fontValue + } } + return biggestFont + } + + open func calculateLineHeight(for font: UIFont) -> CGFloat { // By default height of the line is equal to 75% of font's size - return (font?.pointSize ?? 1) * 0.75 + font.pointSize * 0.75 } - private func getLineSpacing() -> CGFloat { - if let lineSpacing = lineSpacing?(font) { - return lineSpacing - } - - return font?.xHeight ?? .zero + open func calculateLineSpacing(for font: UIFont) -> CGFloat { + font.xHeight } - private func getNumberOfLines() -> Int { - guard isMultiline else { - return 1 - } + open func copyWith(numberOfLines: Int? = nil, + linesWidthFraction: [CGFloat]? = nil, + lineHeight: CGFloat? = nil, + lineSpacing: CGFloat? = nil, + padding: UIEdgeInsets? = nil, + maxWidth: CGFloat? = nil, + shape: Shape? = nil) -> TextSkeletonsConfiguration { - if let numberOfLines = numberOfLines { - return numberOfLines - } - - return labelNumberOfLines == .zero - ? Constants.defaultNumberOfLines - : labelNumberOfLines + TextSkeletonsConfiguration(numberOfLines: numberOfLines ?? self.numberOfLines, + linesWidthFraction: linesWidthFraction ?? self.linesWidthFraction, + lineHeight: lineHeight ?? self.lineHeight, + lineSpacing: lineSpacing ?? self.lineSpacing, + padding: padding ?? self.padding, + maxWidth: maxWidth ?? self.maxWidth, + shape: shape ?? self.shape) } } diff --git a/TIUIElements/Sources/Views/Skeletons/Helpers/CGRect+Padding.swift b/TIUIElements/Sources/Views/Skeletons/Helpers/CGRect+Padding.swift index 98702362..16aee400 100644 --- a/TIUIElements/Sources/Views/Skeletons/Helpers/CGRect+Padding.swift +++ b/TIUIElements/Sources/Views/Skeletons/Helpers/CGRect+Padding.swift @@ -37,4 +37,13 @@ extension CGRect { return CGRect(origin: origin, size: reducedSize) } + + func with(maxWidth: CGFloat) -> CGRect { + guard maxWidth.isFinite else { + return self + } + + return CGRect(origin: origin, size: CGSize(width: min(width, maxWidth), + height: height)) + } } diff --git a/TIUIElements/Sources/Views/Skeletons/SkeletonLayer.swift b/TIUIElements/Sources/Views/Skeletons/SkeletonLayer.swift index da2db1a2..8ab93d53 100644 --- a/TIUIElements/Sources/Views/Skeletons/SkeletonLayer.swift +++ b/TIUIElements/Sources/Views/Skeletons/SkeletonLayer.swift @@ -188,31 +188,35 @@ open class SkeletonLayer: CAShapeLayer { switch viewType { case let .textView(textView): - path = configuration.labelConfiguration.configureTextViewPath(textView: textView) + let textViewConfig = configuration.labelConfiguration.createConfiguration(for: textView) + + path = textViewConfig.createPath(for: textView.bounds) let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size) - frame = configuration.labelConfiguration.applyPadding(viewFrame: viewFrame) + frame = textViewConfig.applyPadding(viewFrame: viewFrame) case let .label(label): - path = configuration.labelConfiguration.configureLabelPath(label: label) + let labelConfig = configuration.labelConfiguration.createConfiguration(for: label) + + path = labelConfig.createPath(for: label.bounds) let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size) - frame = configuration.labelConfiguration.applyPadding(viewFrame: viewFrame) + frame = labelConfig.applyPadding(viewFrame: viewFrame) case .imageView(_): - path = configuration.imageViewConfiguration.drawPath(rect: viewType.view.bounds) + path = configuration.imageViewConfiguration.createPath(for: viewType.view.bounds) let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size) frame = configuration.imageViewConfiguration.applyPadding(viewFrame: viewFrame) case .parentView(_): - path = configuration.containerViewConfiguration.drawPath(rect: viewType.view.bounds) + path = configuration.containerViewConfiguration.createPath(for: viewType.view.bounds) let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size) frame = configuration.containerViewConfiguration.applyPadding(viewFrame: viewFrame) case .leafView(_): - path = configuration.viewConfiguration.drawPath(rect: viewType.view.bounds) + path = configuration.viewConfiguration.createPath(for: viewType.view.bounds) let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size) frame = configuration.viewConfiguration.applyPadding(viewFrame: viewFrame) diff --git a/TIUIElements/Sources/Views/Skeletons/UIView+PresentingSkeletons.swift b/TIUIElements/Sources/Views/Skeletons/UIView+PresentingSkeletons.swift index 3ed92d51..0b7bb0c7 100644 --- a/TIUIElements/Sources/Views/Skeletons/UIView+PresentingSkeletons.swift +++ b/TIUIElements/Sources/Views/Skeletons/UIView+PresentingSkeletons.swift @@ -77,22 +77,29 @@ public extension UIView { withConfiguration conf: SkeletonsConfiguration, forceNoContainers: Bool = false) -> [SkeletonLayer] { - let skeletonLayer = conf.createSkeletonLayer(for: self) - var subviewSkeletonLayers = [SkeletonLayer]() + let config = (view as? SkeletonsPresenter)?.skeletonsConfiguration ?? conf if view.isSkeletonsContainer { if !conf.isContainersHidden, !forceNoContainers { + let skeletonLayer = config.createSkeletonLayer(for: self) skeletonLayer.bind(to: .parentView(view)) + + return [skeletonLayer] + getSkeletonLayer(forView: view, + withConfiguration: config, + forceNoContainers: true) + } else { + return view.skeletonableViews + .map { getSkeletonLayer(forView: $0, + withConfiguration: config, + forceNoContainers: true) } + .flatMap { $0 } } - - subviewSkeletonLayers = view.skeletonableViews - .map { getSkeletonLayer(forView: $0, withConfiguration: conf, forceNoContainers: true) } - .flatMap { $0 } } else { + let skeletonLayer = config.createSkeletonLayer(for: self) skeletonLayer.bind(to: view.viewType) - } - return [skeletonLayer] + subviewSkeletonLayers + return [skeletonLayer] + } } private func configureBaseLayer(withConfiguration conf: SkeletonsConfiguration) { diff --git a/TIUIElements/TIUIElements.podspec b/TIUIElements/TIUIElements.podspec index 68cc4ed9..3f4d7893 100644 --- a/TIUIElements/TIUIElements.podspec +++ b/TIUIElements/TIUIElements.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIUIElements' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Bunch of useful protocols and views.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIUIKitCore/TIUIKitCore.podspec b/TIUIKitCore/TIUIKitCore.podspec index 0f1255f9..968df282 100644 --- a/TIUIKitCore/TIUIKitCore.podspec +++ b/TIUIKitCore/TIUIKitCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIUIKitCore' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Core UI elements: protocols, views and helpers.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIWebView/TIWebView.podspec b/TIWebView/TIWebView.podspec index 59b94610..ba1981b7 100644 --- a/TIWebView/TIWebView.podspec +++ b/TIWebView/TIWebView.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIWebView' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Universal web view API' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIYandexMapUtils/TIYandexMapUtils.podspec b/TIYandexMapUtils/TIYandexMapUtils.podspec index 40821e40..018adb0c 100644 --- a/TIYandexMapUtils/TIYandexMapUtils.podspec +++ b/TIYandexMapUtils/TIYandexMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIYandexMapUtils' - s.version = '1.53.3' + s.version = '1.54.0' s.summary = 'Set of helpers for map objects clustering and interacting using Yandex Maps SDK.' s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' }