unioil-loyalty-rn-app/ios/Pods/lottie-ios/Sources/Private/Utility/Extensions/AnimationKeypathExtension.s...

267 lines
6.7 KiB
Swift

//
// KeypathSearchableExtension.swift
// lottie-swift
//
// Created by Brandon Withrow on 2/4/19.
//
import Foundation
import QuartzCore
extension KeypathSearchable {
func animatorNodes(for keyPath: AnimationKeypath) -> [AnimatorNode]? {
// Make sure there is a current key path.
guard let currentKey = keyPath.currentKey else { return nil }
// Now try popping the keypath for wildcard / child search
guard let nextKeypath = keyPath.popKey(keypathName) else {
// We may be on the final keypath. Check for match.
if
let node = self as? AnimatorNode,
currentKey.equalsKeypath(keypathName)
{
// This is the final keypath and matches self. Return.s
return [node]
}
/// Nope. Stop Search
return nil
}
var results: [AnimatorNode] = []
if
let node = self as? AnimatorNode,
nextKeypath.currentKey == nil
{
// Keypath matched self and was the final keypath.
results.append(node)
}
for childNode in childKeypaths {
// Check if the child has any nodes matching the next keypath.
if let foundNodes = childNode.animatorNodes(for: nextKeypath) {
results.append(contentsOf: foundNodes)
}
// In this case the current key is fuzzy, and both child and self match the next keyname. Keep digging!
if
currentKey.keyPathType == .fuzzyWildcard,
let nextKeypath = keyPath.nextKeypath,
nextKeypath.equalsKeypath(childNode.keypathName),
let foundNodes = childNode.animatorNodes(for: keyPath)
{
results.append(contentsOf: foundNodes)
}
}
guard results.count > 0 else {
return nil
}
return results
}
func nodeProperties(for keyPath: AnimationKeypath) -> [AnyNodeProperty]? {
guard let nextKeypath = keyPath.popKey(keypathName) else {
/// Nope. Stop Search
return nil
}
/// Keypath matches in some way. Continue the search.
var results: [AnyNodeProperty] = []
/// Check if we have a property keypath yet
if
let propertyKey = nextKeypath.propertyKey,
let property = keypathProperties[propertyKey]
{
/// We found a property!
results.append(property)
}
if nextKeypath.nextKeypath != nil {
/// Now check child keypaths.
for child in childKeypaths {
if let childProperties = child.nodeProperties(for: nextKeypath) {
results.append(contentsOf: childProperties)
}
}
}
guard results.count > 0 else {
return nil
}
return results
}
func layer(for keyPath: AnimationKeypath) -> CALayer? {
if keyPath.nextKeypath == nil, let layerKey = keyPath.currentKey, layerKey.equalsKeypath(keypathName) {
/// We found our layer!
return keypathLayer
}
guard let nextKeypath = keyPath.popKey(keypathName) else {
/// Nope. Stop Search
return nil
}
/// Now check child keypaths.
for child in childKeypaths {
if let layer = child.layer(for: nextKeypath) {
return layer
}
}
return nil
}
func logKeypaths(for keyPath: AnimationKeypath?, logger: LottieLogger) {
let newKeypath: AnimationKeypath
if let previousKeypath = keyPath {
newKeypath = previousKeypath.appendingKey(keypathName)
} else {
newKeypath = AnimationKeypath(keys: [keypathName])
}
logger.info(newKeypath.fullPath)
for key in keypathProperties.keys {
logger.info(newKeypath.appendingKey(key).fullPath)
}
for child in childKeypaths {
child.logKeypaths(for: newKeypath, logger: logger)
}
}
}
extension AnimationKeypath {
var currentKey: String? {
keys.first
}
var nextKeypath: String? {
guard keys.count > 1 else {
return nil
}
return keys[1]
}
var propertyKey: String? {
if nextKeypath == nil {
/// There are no more keypaths. This is a property key.
return currentKey
}
if keys.count == 2, currentKey?.keyPathType == .fuzzyWildcard {
/// The next keypath is the last and the current is a fuzzy key.
return nextKeypath
}
return nil
}
var fullPath: String {
keys.joined(separator: ".")
}
// Pops the top keypath from the stack if the keyname matches.
func popKey(_ keyname: String) -> AnimationKeypath? {
guard
let currentKey = currentKey,
currentKey.equalsKeypath(keyname),
keys.count > 1 else
{
// Current key either doesnt match or we are on the last key.
return nil
}
// Pop the keypath from the stack and return the new stack.
let newKeys: [String]
if currentKey.keyPathType == .fuzzyWildcard {
/// Dont remove if current key is a fuzzy wildcard, and if the next keypath doesnt equal keypathname
if
let nextKeypath = nextKeypath,
nextKeypath.equalsKeypath(keyname)
{
/// Remove next two keypaths. This keypath breaks the wildcard.
var oldKeys = keys
oldKeys.remove(at: 0)
oldKeys.remove(at: 0)
newKeys = oldKeys
} else {
newKeys = keys
}
} else {
var oldKeys = keys
oldKeys.remove(at: 0)
newKeys = oldKeys
}
return AnimationKeypath(keys: newKeys)
}
func appendingKey(_ key: String) -> AnimationKeypath {
var newKeys = keys
newKeys.append(key)
return AnimationKeypath(keys: newKeys)
}
}
extension String {
var keyPathType: KeyType {
switch self {
case "*":
return .wildcard
case "**":
return .fuzzyWildcard
default:
return .specific
}
}
func equalsKeypath(_ keyname: String) -> Bool {
if keyPathType == .wildcard || keyPathType == .fuzzyWildcard {
return true
}
if self == keyname {
return true
}
if let index = firstIndex(of: "*") {
// Wildcard search.
let prefix = String(self.prefix(upTo: index))
let suffix = String(self.suffix(from: self.index(after: index)))
if prefix.count > 0 {
// Match prefix.
if keyname.count < prefix.count {
return false
}
let testPrefix = String(keyname.prefix(upTo: keyname.index(keyname.startIndex, offsetBy: prefix.count)))
if testPrefix != prefix {
// Prefix doesnt match
return false
}
}
if suffix.count > 0 {
// Match suffix.
if keyname.count < suffix.count {
// Suffix doesnt match
return false
}
let index = keyname.index(keyname.endIndex, offsetBy: -suffix.count)
let testSuffix = String(keyname.suffix(from: index))
if testSuffix != suffix {
return false
}
}
return true
}
return false
}
}
// MARK: - KeyType
enum KeyType {
case specific
case wildcard
case fuzzyWildcard
}