Files
divkit/client/ios/DivKitExtensions/Shimmers/ShimmerStyle+Serialization.swift
pkurchatov e2b330d645 Swift 6 support in DivKitExtensionsTests
commit_hash:f3785279b800fa5cb88b1d6dbda2e87a80ee9f3d
2025-12-23 18:17:36 +03:00

147 lines
3.7 KiB
Swift

#if os(iOS)
import DivKit
import Foundation
import LayoutKit
import VGSL
public struct ColorAndLocation: Equatable, Sendable {
var color: Color
var location: CGFloat
public init(color: Color, location: CGFloat) {
self.color = color
self.location = location
}
}
extension ColorAndLocation: Hashable {}
extension [ColorAndLocation] {
var locations: [CGFloat] {
map(\.location)
}
var colors: [Color] {
map(\.color)
}
var fromValues: [NSNumber] {
guard let max = locations.max() else { return [] }
return locations.map { NSNumber(value: ($0 - max).native) }
}
var toValues: [NSNumber] {
guard let min = locations.min() else { return [] }
let addToAll = 1 - min
return locations.map { NSNumber(value: ($0 + addToAll).native) }
}
}
extension DivBase {
func resolveExtensionParams(for extensionId: String) -> [String: Any]? {
extensions?.first(where: { $0.id == extensionId })?.params
}
}
extension Dictionary where Key == String {
func getOptionalColorArray(
_ key: Key,
expressionResolver: ExpressionResolver
) throws -> [Color]? {
try getOptionalArray(
key,
transform: { expressionResolver.resolveColor($0) }
)
}
func getOptionalFloatArray(
_ key: Key,
expressionResolver: ExpressionResolver
) throws -> [CGFloat]? {
let result: [Double]? = try getOptionalArray(
key,
transform: { (obj: Any) -> Double? in
if let expression = obj as? String {
return expressionResolver.resolveNumeric(expression)
}
return obj as? Double
}
)
return result?.map { CGFloat($0) }
}
func getOptionalColorsAndLocations(
colorsKey: Key,
locationsKey: Key,
expressionResolver: ExpressionResolver
) throws -> [ColorAndLocation]? {
let colors: [Color]? = try getOptionalColorArray(
colorsKey,
expressionResolver: expressionResolver
)
let locations: [CGFloat]? = try getOptionalFloatArray(
locationsKey,
expressionResolver: expressionResolver
)
guard let colors, let locations else {
return nil
}
guard colors.count == locations.count else {
throw ShimmerSerializationError.invalidColorsAndLocationsCount
}
return zip(colors, locations).map(ColorAndLocation.init)
}
func getOptionalCornerRadius(
_ key: Key,
expressionResolver: ExpressionResolver
) throws -> CornerRadii? {
try? getOptionalField(key) { (obj: Any) in
if let corners = obj as? [String: Any] {
let topLeft: Int? = try? getOptionalIntFromDict(
dict: corners, "top-left",
resolver: expressionResolver
)
let topRight: Int? = try? getOptionalIntFromDict(
dict: corners, "top-right",
resolver: expressionResolver
)
let bottomLeft: Int? = try? getOptionalIntFromDict(
dict: corners, "bottom-left",
resolver: expressionResolver
)
let bottomRight: Int? = try? getOptionalIntFromDict(
dict: corners, "bottom-right",
resolver: expressionResolver
)
return CornerRadii(
topLeft: CGFloat(topLeft ?? 0),
topRight: CGFloat(topRight ?? 0),
bottomLeft: CGFloat(bottomLeft ?? 0),
bottomRight: CGFloat(bottomRight ?? 0)
)
}
return nil
}
}
private func getOptionalIntFromDict(
dict: [String: Any],
_ key: Key,
resolver: ExpressionResolver
) throws -> Int? {
if let value = dict[key] as? Int {
return value
} else if let expression: String = try dict.getOptionalField(key) {
return resolver.resolveNumeric(expression)
}
return nil
}
}
private enum ShimmerSerializationError: Error {
case invalidColorsAndLocationsCount
}
#endif