├── Podfile ├── Podfile.lock ├── Pods ├── Manifest.lock ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── shubham.xcuserdatad │ │ └── xcschemes │ │ ├── Pods-UserOnboarding.xcscheme │ │ ├── lottie-ios.xcscheme │ │ └── xcschememanagement.plist ├── Target Support Files │ ├── Pods-UserOnboarding │ │ ├── Pods-UserOnboarding-Info.plist │ │ ├── Pods-UserOnboarding-acknowledgements.markdown │ │ ├── Pods-UserOnboarding-acknowledgements.plist │ │ ├── Pods-UserOnboarding-dummy.m │ │ ├── Pods-UserOnboarding-frameworks-Debug-input-files.xcfilelist │ │ ├── Pods-UserOnboarding-frameworks-Debug-output-files.xcfilelist │ │ ├── Pods-UserOnboarding-frameworks-Release-input-files.xcfilelist │ │ ├── Pods-UserOnboarding-frameworks-Release-output-files.xcfilelist │ │ ├── Pods-UserOnboarding-frameworks.sh │ │ ├── Pods-UserOnboarding-umbrella.h │ │ ├── Pods-UserOnboarding.debug.xcconfig │ │ ├── Pods-UserOnboarding.modulemap │ │ └── Pods-UserOnboarding.release.xcconfig │ └── lottie-ios │ │ ├── lottie-ios-Info.plist │ │ ├── lottie-ios-dummy.m │ │ ├── lottie-ios-prefix.pch │ │ ├── lottie-ios-umbrella.h │ │ ├── lottie-ios.modulemap │ │ └── lottie-ios.xcconfig └── lottie-ios │ ├── LICENSE │ ├── README.md │ └── lottie-swift │ └── src │ ├── Private │ ├── LayerContainers │ │ ├── AnimationContainer.swift │ │ ├── CompLayers │ │ │ ├── CompositionLayer.swift │ │ │ ├── ImageCompositionLayer.swift │ │ │ ├── MaskContainerLayer.swift │ │ │ ├── NullCompositionLayer.swift │ │ │ ├── PreCompositionLayer.swift │ │ │ ├── ShapeCompositionLayer.swift │ │ │ ├── SolidCompositionLayer.swift │ │ │ └── TextCompositionLayer.swift │ │ └── Utility │ │ │ ├── CompositionLayersInitializer.swift │ │ │ ├── InvertedMatteLayer.swift │ │ │ ├── LayerImageProvider.swift │ │ │ ├── LayerTextProvider.swift │ │ │ └── LayerTransformNode.swift │ ├── Model │ │ ├── Animation.swift │ │ ├── Assets │ │ │ ├── Asset.swift │ │ │ ├── AssetLibrary.swift │ │ │ ├── ImageAsset.swift │ │ │ └── PrecompAsset.swift │ │ ├── Extensions │ │ │ └── KeyedDecodingContainerExtensions.swift │ │ ├── Keyframes │ │ │ ├── Keyframe.swift │ │ │ └── KeyframeGroup.swift │ │ ├── Layers │ │ │ ├── ImageLayerModel.swift │ │ │ ├── LayerModel.swift │ │ │ ├── PreCompLayerModel.swift │ │ │ ├── ShapeLayerModel.swift │ │ │ ├── SolidLayerModel.swift │ │ │ └── TextLayerModel.swift │ │ ├── Objects │ │ │ ├── DashPattern.swift │ │ │ ├── Marker.swift │ │ │ ├── Mask.swift │ │ │ └── Transform.swift │ │ ├── ShapeItems │ │ │ ├── Ellipse.swift │ │ │ ├── FillI.swift │ │ │ ├── GradientFill.swift │ │ │ ├── GradientStroke.swift │ │ │ ├── Group.swift │ │ │ ├── Merge.swift │ │ │ ├── Rectangle.swift │ │ │ ├── Repeater.swift │ │ │ ├── Shape.swift │ │ │ ├── ShapeItem.swift │ │ │ ├── ShapeTransform.swift │ │ │ ├── Star.swift │ │ │ ├── Stroke.swift │ │ │ └── Trim.swift │ │ └── Text │ │ │ ├── Font.swift │ │ │ ├── Glyph.swift │ │ │ ├── TextAnimator.swift │ │ │ └── TextDocument.swift │ ├── NodeRenderSystem │ │ ├── Extensions │ │ │ └── ItemsExtension.swift │ │ ├── NodeProperties │ │ │ ├── NodeProperty.swift │ │ │ ├── Protocols │ │ │ │ ├── AnyNodeProperty.swift │ │ │ │ ├── AnyValueContainer.swift │ │ │ │ ├── KeypathSearchable.swift │ │ │ │ └── NodePropertyMap.swift │ │ │ ├── ValueContainer.swift │ │ │ └── ValueProviders │ │ │ │ ├── GroupInterpolator.swift │ │ │ │ ├── KeyframeInterpolator.swift │ │ │ │ └── SingleValueProvider.swift │ │ ├── Nodes │ │ │ ├── ModifierNodes │ │ │ │ └── TrimPathNode.swift │ │ │ ├── OutputNodes │ │ │ │ ├── GroupOutputNode.swift │ │ │ │ ├── PassThroughOutputNode.swift │ │ │ │ ├── PathOutputNode.swift │ │ │ │ └── Renderables │ │ │ │ │ ├── FillRenderer.swift │ │ │ │ │ ├── GradientFillRenderer.swift │ │ │ │ │ ├── GradientStrokeRenderer.swift │ │ │ │ │ └── StrokeRenderer.swift │ │ │ ├── PathNodes │ │ │ │ ├── EllipseNode.swift │ │ │ │ ├── PolygonNode.swift │ │ │ │ ├── RectNode.swift │ │ │ │ ├── ShapeNode.swift │ │ │ │ └── StarNode.swift │ │ │ ├── RenderContainers │ │ │ │ └── GroupNode.swift │ │ │ ├── RenderNodes │ │ │ │ ├── FillNode.swift │ │ │ │ ├── GradientFillNode.swift │ │ │ │ ├── GradientStrokeNode.swift │ │ │ │ └── StrokeNode.swift │ │ │ └── Text │ │ │ │ └── TextAnimatorNode.swift │ │ ├── Protocols │ │ │ ├── AnimatorNode.swift │ │ │ ├── PathNode.swift │ │ │ └── RenderNode.swift │ │ └── RenderLayers │ │ │ ├── ShapeContainerLayer.swift │ │ │ └── ShapeRenderLayer.swift │ └── Utility │ │ ├── Debugging │ │ ├── AnimatorNodeDebugging.swift │ │ └── LayerDebugging.swift │ │ ├── Extensions │ │ ├── AnimationKeypathExtension.swift │ │ ├── CGFloatExtensions.swift │ │ ├── MathKit.swift │ │ └── StringExtensions.swift │ │ ├── Helpers │ │ └── AnimationContext.swift │ │ ├── Interpolatable │ │ ├── Interpolatable.swift │ │ ├── InterpolatableExtensions.swift │ │ └── KeyframeExtensions.swift │ │ └── Primitives │ │ ├── BezierPath.swift │ │ ├── ColorExtension.swift │ │ ├── CompoundBezierPath.swift │ │ ├── CurveVertex.swift │ │ ├── PathElement.swift │ │ └── VectorsExtensions.swift │ └── Public │ ├── Animation │ ├── AnimationPublic.swift │ ├── AnimationView.swift │ └── AnimationViewInitializers.swift │ ├── AnimationCache │ ├── AnimationCacheProvider.swift │ └── LRUAnimationCache.swift │ ├── DynamicProperties │ ├── AnimationKeypath.swift │ ├── AnyValueProvider.swift │ └── ValueProviders │ │ ├── ColorValueProvider.swift │ │ ├── FloatValueProvider.swift │ │ ├── GradientValueProvider.swift │ │ ├── PointValueProvider.swift │ │ └── SizeValueProvider.swift │ ├── ImageProvider │ └── AnimationImageProvider.swift │ ├── Primitives │ ├── AnimationTime.swift │ ├── Color.swift │ └── Vectors.swift │ ├── TextProvider │ └── AnimationTextProvider.swift │ └── iOS │ ├── AnimatedButton.swift │ ├── AnimatedControl.swift │ ├── AnimatedSwitch.swift │ ├── AnimationSubview.swift │ ├── BundleImageProvider.swift │ ├── Compatibility │ ├── CompatibleAnimationKeypath.swift │ └── CompatibleAnimationView.swift │ ├── FilepathImageProvider.swift │ ├── LottieView.swift │ └── UIColorExtension.swift ├── README.md ├── UserOnboarding.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── shubham.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── UserOnboarding.xcworkspace ├── contents.xcworkspacedata ├── xcshareddata │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── shubham.xcuserdatad │ └── xcdebugger │ └── Breakpoints_v2.xcbkptlist └── UserOnboarding ├── AppDelegate.swift ├── Assets.xcassets ├── AppIcon.appiconset │ └── Contents.json └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── CollectionViewCell.swift ├── Info.plist ├── OnboardingCollectionViewCell.swift ├── OnboardingCollectionViewCell.xib ├── SceneDelegate.swift └── ViewController.swift /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'UserOnboarding' do 5 | # Comment the next line if you don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for UserOnboarding 9 | pod 'lottie-ios' 10 | 11 | 12 | end 13 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - lottie-ios (3.1.8) 3 | 4 | DEPENDENCIES: 5 | - lottie-ios 6 | 7 | SPEC REPOS: 8 | trunk: 9 | - lottie-ios 10 | 11 | SPEC CHECKSUMS: 12 | lottie-ios: 48fac6be217c76937e36e340e2d09cf7b10b7f5f 13 | 14 | PODFILE CHECKSUM: efe27b7096ba59cdb6862ddf85368f650bc9fa85 15 | 16 | COCOAPODS: 1.8.4 17 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - lottie-ios (3.1.8) 3 | 4 | DEPENDENCIES: 5 | - lottie-ios 6 | 7 | SPEC REPOS: 8 | trunk: 9 | - lottie-ios 10 | 11 | SPEC CHECKSUMS: 12 | lottie-ios: 48fac6be217c76937e36e340e2d09cf7b10b7f5f 13 | 14 | PODFILE CHECKSUM: efe27b7096ba59cdb6862ddf85368f650bc9fa85 15 | 16 | COCOAPODS: 1.8.4 17 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/shubham.xcuserdatad/xcschemes/Pods-UserOnboarding.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/shubham.xcuserdatad/xcschemes/lottie-ios.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/shubham.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Pods-UserOnboarding.xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 1 13 | 14 | lottie-ios.xcscheme 15 | 16 | isShown 17 | 18 | orderHint 19 | 0 20 | 21 | 22 | SuppressBuildableAutocreation 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_UserOnboarding : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_UserOnboarding 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lottie.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lottie.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_UserOnboardingVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_UserOnboardingVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "CoreGraphics" -framework "Lottie" -framework "QuartzCore" -framework "UIKit" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_UserOnboarding { 2 | umbrella header "Pods-UserOnboarding-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserOnboarding/Pods-UserOnboarding.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "CoreGraphics" -framework "Lottie" -framework "QuartzCore" -framework "UIKit" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/lottie-ios/lottie-ios-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 3.1.8 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/lottie-ios/lottie-ios-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_lottie_ios : NSObject 3 | @end 4 | @implementation PodsDummy_lottie_ios 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/lottie-ios/lottie-ios-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/lottie-ios/lottie-ios-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double LottieVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char LottieVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/lottie-ios/lottie-ios.modulemap: -------------------------------------------------------------------------------- 1 | framework module Lottie { 2 | umbrella header "lottie-ios-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/lottie-ios/lottie-ios.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = $(inherited) -framework "CoreGraphics" -framework "QuartzCore" -framework "UIKit" 4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/lottie-ios 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/LayerContainers/CompLayers/ImageCompositionLayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageCompositionLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/25/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | import QuartzCore 11 | 12 | final class ImageCompositionLayer: CompositionLayer { 13 | 14 | var image: CGImage? = nil { 15 | didSet { 16 | if let image = image { 17 | contentsLayer.contents = image 18 | } else { 19 | contentsLayer.contents = nil 20 | } 21 | } 22 | } 23 | 24 | let imageReferenceID: String 25 | 26 | init(imageLayer: ImageLayerModel, size: CGSize) { 27 | self.imageReferenceID = imageLayer.referenceID 28 | super.init(layer: imageLayer, size: size) 29 | contentsLayer.masksToBounds = true 30 | contentsLayer.contentsGravity = CALayerContentsGravity.resize 31 | } 32 | 33 | override init(layer: Any) { 34 | /// Used for creating shadow model layers. Read More here: https://developer.apple.com/documentation/quartzcore/calayer/1410842-init 35 | guard let layer = layer as? ImageCompositionLayer else { 36 | fatalError("init(layer:) Wrong Layer Class") 37 | } 38 | self.imageReferenceID = layer.imageReferenceID 39 | self.image = nil 40 | super.init(layer: layer) 41 | } 42 | 43 | required init?(coder aDecoder: NSCoder) { 44 | fatalError("init(coder:) has not been implemented") 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/LayerContainers/CompLayers/NullCompositionLayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NullCompositionLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/25/19. 6 | // 7 | 8 | import Foundation 9 | 10 | final class NullCompositionLayer: CompositionLayer { 11 | 12 | init(layer: LayerModel) { 13 | super.init(layer: layer, size: .zero) 14 | } 15 | 16 | required init?(coder aDecoder: NSCoder) { 17 | fatalError("init(coder:) has not been implemented") 18 | } 19 | 20 | override init(layer: Any) { 21 | /// Used for creating shadow model layers. Read More here: https://developer.apple.com/documentation/quartzcore/calayer/1410842-init 22 | guard let layer = layer as? NullCompositionLayer else { 23 | fatalError("init(layer:) Wrong Layer Class") 24 | } 25 | super.init(layer: layer) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/LayerContainers/CompLayers/PreCompositionLayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreCompositionLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/25/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | final class PreCompositionLayer: CompositionLayer { 12 | 13 | let frameRate: CGFloat 14 | let remappingNode: NodeProperty? 15 | fileprivate var animationLayers: [CompositionLayer] 16 | 17 | init(precomp: PreCompLayerModel, 18 | asset: PrecompAsset, 19 | layerImageProvider: LayerImageProvider, 20 | textProvider: AnimationTextProvider, 21 | assetLibrary: AssetLibrary?, 22 | frameRate: CGFloat) { 23 | self.animationLayers = [] 24 | if let keyframes = precomp.timeRemapping?.keyframes { 25 | self.remappingNode = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframes)) 26 | } else { 27 | self.remappingNode = nil 28 | } 29 | self.frameRate = frameRate 30 | super.init(layer: precomp, size: CGSize(width: precomp.width, height: precomp.height)) 31 | contentsLayer.masksToBounds = true 32 | contentsLayer.bounds = CGRect(origin: .zero, size: CGSize(width: precomp.width, height: precomp.height)) 33 | 34 | let layers = asset.layers.initializeCompositionLayers(assetLibrary: assetLibrary, layerImageProvider: layerImageProvider, textProvider: textProvider, frameRate: frameRate) 35 | 36 | var imageLayers = [ImageCompositionLayer]() 37 | 38 | var mattedLayer: CompositionLayer? = nil 39 | 40 | for layer in layers.reversed() { 41 | layer.bounds = bounds 42 | animationLayers.append(layer) 43 | if let imageLayer = layer as? ImageCompositionLayer { 44 | imageLayers.append(imageLayer) 45 | } 46 | if let matte = mattedLayer { 47 | /// The previous layer requires this layer to be its matte 48 | matte.matteLayer = layer 49 | mattedLayer = nil 50 | continue 51 | } 52 | if let matte = layer.matteType, 53 | (matte == .add || matte == .invert) { 54 | /// We have a layer that requires a matte. 55 | mattedLayer = layer 56 | } 57 | contentsLayer.addSublayer(layer) 58 | } 59 | 60 | self.childKeypaths.append(contentsOf: layers) 61 | 62 | layerImageProvider.addImageLayers(imageLayers) 63 | } 64 | 65 | override init(layer: Any) { 66 | /// Used for creating shadow model layers. Read More here: https://developer.apple.com/documentation/quartzcore/calayer/1410842-init 67 | guard let layer = layer as? PreCompositionLayer else { 68 | fatalError("init(layer:) Wrong Layer Class") 69 | } 70 | self.frameRate = layer.frameRate 71 | self.remappingNode = nil 72 | self.animationLayers = [] 73 | 74 | super.init(layer: layer) 75 | } 76 | 77 | required init?(coder aDecoder: NSCoder) { 78 | fatalError("init(coder:) has not been implemented") 79 | } 80 | 81 | override func displayContentsWithFrame(frame: CGFloat, forceUpdates: Bool) { 82 | let localFrame: CGFloat 83 | if let remappingNode = remappingNode { 84 | remappingNode.update(frame: frame) 85 | localFrame = remappingNode.value.cgFloatValue * frameRate 86 | } else { 87 | localFrame = (frame - startFrame) / timeStretch 88 | } 89 | animationLayers.forEach( { $0.displayWithFrame(frame: localFrame, forceUpdates: forceUpdates) }) 90 | } 91 | 92 | override var keypathProperties: [String : AnyNodeProperty] { 93 | guard let remappingNode = remappingNode else { 94 | return super.keypathProperties 95 | } 96 | return ["Time Remap" : remappingNode] 97 | } 98 | 99 | override func updateRenderScale() { 100 | super.updateRenderScale() 101 | animationLayers.forEach( { $0.renderScale = renderScale } ) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/LayerContainers/CompLayers/ShapeCompositionLayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShapeLayerContainer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/22/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /** 12 | A CompositionLayer responsible for initializing and rendering shapes 13 | */ 14 | final class ShapeCompositionLayer: CompositionLayer { 15 | 16 | let rootNode: AnimatorNode? 17 | let renderContainer: ShapeContainerLayer? 18 | 19 | init(shapeLayer: ShapeLayerModel) { 20 | let results = shapeLayer.items.initializeNodeTree() 21 | let renderContainer = ShapeContainerLayer() 22 | self.renderContainer = renderContainer 23 | self.rootNode = results.rootNode 24 | super.init(layer: shapeLayer, size: .zero) 25 | contentsLayer.addSublayer(renderContainer) 26 | for container in results.renderContainers { 27 | renderContainer.insertRenderLayer(container) 28 | } 29 | rootNode?.updateTree(0, forceUpdates: true) 30 | self.childKeypaths.append(contentsOf: results.childrenNodes) 31 | } 32 | 33 | override init(layer: Any) { 34 | guard let layer = layer as? ShapeCompositionLayer else { 35 | fatalError("init(layer:) wrong class.") 36 | } 37 | self.rootNode = nil 38 | self.renderContainer = nil 39 | super.init(layer: layer) 40 | } 41 | 42 | override func displayContentsWithFrame(frame: CGFloat, forceUpdates: Bool) { 43 | rootNode?.updateTree(frame, forceUpdates: forceUpdates) 44 | renderContainer?.markRenderUpdates(forFrame: frame) 45 | } 46 | 47 | required init?(coder aDecoder: NSCoder) { 48 | fatalError("init(coder:) has not been implemented") 49 | } 50 | 51 | override func updateRenderScale() { 52 | super.updateRenderScale() 53 | renderContainer?.renderScale = renderScale 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/LayerContainers/CompLayers/SolidCompositionLayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolidCompositionLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/25/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | final class SolidCompositionLayer: CompositionLayer { 12 | 13 | let colorProperty: NodeProperty? 14 | let solidShape: CAShapeLayer = CAShapeLayer() 15 | 16 | init(solid: SolidLayerModel) { 17 | let components = solid.colorHex.hexColorComponents() 18 | self.colorProperty = NodeProperty(provider: SingleValueProvider(Color(r: Double(components.red), g: Double(components.green), b: Double(components.blue), a: 1))) 19 | 20 | super.init(layer: solid, size: .zero) 21 | solidShape.path = CGPath(rect: CGRect(x: 0, y: 0, width: solid.width, height: solid.height), transform: nil) 22 | contentsLayer.addSublayer(solidShape) 23 | } 24 | 25 | override init(layer: Any) { 26 | /// Used for creating shadow model layers. Read More here: https://developer.apple.com/documentation/quartzcore/calayer/1410842-init 27 | guard let layer = layer as? SolidCompositionLayer else { 28 | fatalError("init(layer:) Wrong Layer Class") 29 | } 30 | self.colorProperty = layer.colorProperty 31 | super.init(layer: layer) 32 | } 33 | 34 | required init?(coder aDecoder: NSCoder) { 35 | fatalError("init(coder:) has not been implemented") 36 | } 37 | 38 | override func displayContentsWithFrame(frame: CGFloat, forceUpdates: Bool) { 39 | guard let colorProperty = colorProperty else { return } 40 | colorProperty.update(frame: frame) 41 | solidShape.fillColor = colorProperty.value.cgColorValue 42 | } 43 | 44 | override var keypathProperties: [String : AnyNodeProperty] { 45 | guard let colorProperty = colorProperty else { return super.keypathProperties } 46 | return ["Color" : colorProperty] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/LayerContainers/Utility/CompositionLayersInitializer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CompositionLayersInitializer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/25/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | extension Array where Element == LayerModel { 12 | 13 | func initializeCompositionLayers(assetLibrary: AssetLibrary?, 14 | layerImageProvider: LayerImageProvider, 15 | textProvider: AnimationTextProvider, 16 | frameRate: CGFloat) -> [CompositionLayer] { 17 | var compositionLayers = [CompositionLayer]() 18 | var layerMap = [Int : CompositionLayer]() 19 | 20 | /// Organize the assets into a dictionary of [ID : ImageAsset] 21 | var childLayers = [LayerModel]() 22 | 23 | for layer in self { 24 | if layer.hidden == true { 25 | let genericLayer = NullCompositionLayer(layer: layer) 26 | compositionLayers.append(genericLayer) 27 | layerMap[layer.index] = genericLayer 28 | } else if let shapeLayer = layer as? ShapeLayerModel { 29 | let shapeContainer = ShapeCompositionLayer(shapeLayer: shapeLayer) 30 | compositionLayers.append(shapeContainer) 31 | layerMap[layer.index] = shapeContainer 32 | } else if let solidLayer = layer as? SolidLayerModel { 33 | let solidContainer = SolidCompositionLayer(solid: solidLayer) 34 | compositionLayers.append(solidContainer) 35 | layerMap[layer.index] = solidContainer 36 | } else if let precompLayer = layer as? PreCompLayerModel, 37 | let assetLibrary = assetLibrary, 38 | let precompAsset = assetLibrary.precompAssets[precompLayer.referenceID] { 39 | let precompContainer = PreCompositionLayer(precomp: precompLayer, 40 | asset: precompAsset, 41 | layerImageProvider: layerImageProvider, 42 | textProvider: textProvider, 43 | assetLibrary: assetLibrary, 44 | frameRate: frameRate) 45 | compositionLayers.append(precompContainer) 46 | layerMap[layer.index] = precompContainer 47 | } else if let imageLayer = layer as? ImageLayerModel, 48 | let assetLibrary = assetLibrary, 49 | let imageAsset = assetLibrary.imageAssets[imageLayer.referenceID] { 50 | let imageContainer = ImageCompositionLayer(imageLayer: imageLayer, size: CGSize(width: imageAsset.width, height: imageAsset.height)) 51 | compositionLayers.append(imageContainer) 52 | layerMap[layer.index] = imageContainer 53 | } else if let textLayer = layer as? TextLayerModel { 54 | let textContainer = TextCompositionLayer(textLayer: textLayer, textProvider: textProvider) 55 | compositionLayers.append(textContainer) 56 | layerMap[layer.index] = textContainer 57 | } else { 58 | let genericLayer = NullCompositionLayer(layer: layer) 59 | compositionLayers.append(genericLayer) 60 | layerMap[layer.index] = genericLayer 61 | } 62 | if layer.parent != nil { 63 | childLayers.append(layer) 64 | } 65 | } 66 | 67 | /// Now link children with their parents 68 | for layerModel in childLayers { 69 | if let parentID = layerModel.parent { 70 | let childLayer = layerMap[layerModel.index] 71 | let parentLayer = layerMap[parentID] 72 | childLayer?.transformNode.parentNode = parentLayer?.transformNode 73 | } 74 | } 75 | 76 | return compositionLayers 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/LayerContainers/Utility/InvertedMatteLayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InvertedMatteLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/28/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | /** 12 | A layer that inverses the alpha output of its input layer. 13 | 14 | WARNING: This is experimental and probably not very performant. 15 | */ 16 | final class InvertedMatteLayer: CALayer, CompositionLayerDelegate { 17 | 18 | let inputMatte: CompositionLayer? 19 | let wrapperLayer = CALayer() 20 | 21 | init(inputMatte: CompositionLayer) { 22 | self.inputMatte = inputMatte 23 | super.init() 24 | inputMatte.layerDelegate = self 25 | self.anchorPoint = .zero 26 | self.bounds = inputMatte.bounds 27 | self.setNeedsDisplay() 28 | } 29 | 30 | override init(layer: Any) { 31 | guard let layer = layer as? InvertedMatteLayer else { 32 | fatalError("init(layer:) wrong class.") 33 | } 34 | self.inputMatte = nil 35 | super.init(layer: layer) 36 | } 37 | 38 | func frameUpdated(frame: CGFloat) { 39 | self.setNeedsDisplay() 40 | self.displayIfNeeded() 41 | } 42 | 43 | required init?(coder aDecoder: NSCoder) { 44 | fatalError("init(coder:) has not been implemented") 45 | } 46 | 47 | override func draw(in ctx: CGContext) { 48 | guard let inputMatte = inputMatte else { return } 49 | guard let fillColor = CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [0, 0, 0, 1]) 50 | else { return } 51 | ctx.setFillColor(fillColor) 52 | ctx.fill(bounds) 53 | ctx.setBlendMode(.destinationOut) 54 | inputMatte.render(in: ctx) 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/LayerContainers/Utility/LayerImageProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayerImageProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/25/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Connects a LottieImageProvider to a group of image layers 11 | final class LayerImageProvider { 12 | 13 | var imageProvider: AnimationImageProvider { 14 | didSet { 15 | reloadImages() 16 | } 17 | } 18 | 19 | fileprivate(set) var imageLayers: [ImageCompositionLayer] 20 | let imageAssets: [String : ImageAsset] 21 | 22 | init(imageProvider: AnimationImageProvider, assets: [String : ImageAsset]?) { 23 | self.imageProvider = imageProvider 24 | self.imageLayers = [ImageCompositionLayer]() 25 | if let assets = assets { 26 | self.imageAssets = assets 27 | } else { 28 | self.imageAssets = [:] 29 | } 30 | reloadImages() 31 | } 32 | 33 | func addImageLayers(_ layers: [ImageCompositionLayer]) { 34 | for layer in layers { 35 | if imageAssets[layer.imageReferenceID] != nil { 36 | /// Found a linking asset in our asset library. Add layer 37 | imageLayers.append(layer) 38 | } 39 | } 40 | } 41 | 42 | func reloadImages() { 43 | for imageLayer in imageLayers { 44 | if let asset = imageAssets[imageLayer.imageReferenceID] { 45 | imageLayer.image = imageProvider.imageForAsset(asset: asset) 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/LayerContainers/Utility/LayerTextProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayerTextProvider.swift 3 | // lottie-ios-iOS 4 | // 5 | // Created by Alexandr Goncharov on 07/06/2019. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Connects a LottieTextProvider to a group of text layers 11 | final class LayerTextProvider { 12 | 13 | var textProvider: AnimationTextProvider { 14 | didSet { 15 | reloadTexts() 16 | } 17 | } 18 | 19 | fileprivate(set) var textLayers: [TextCompositionLayer] 20 | 21 | init(textProvider: AnimationTextProvider) { 22 | self.textProvider = textProvider 23 | self.textLayers = [] 24 | reloadTexts() 25 | } 26 | 27 | func addTextLayers(_ layers: [TextCompositionLayer]) { 28 | textLayers += layers 29 | } 30 | 31 | func reloadTexts() { 32 | textLayers.forEach { 33 | $0.textProvider = textProvider 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Animation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Animation.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/7/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public enum CoordinateSpace: Int, Codable { 11 | case type2d 12 | case type3d 13 | } 14 | 15 | /** 16 | The `Animation` model is the top level model object in Lottie. 17 | 18 | An `Animation` holds all of the animation data backing a Lottie Animation. 19 | Codable, see JSON schema [here](https://github.com/airbnb/lottie-web/tree/master/docs/json). 20 | */ 21 | public final class Animation: Codable { 22 | 23 | /// The version of the JSON Schema. 24 | let version: String 25 | 26 | /// The coordinate space of the composition. 27 | let type: CoordinateSpace 28 | 29 | /// The start time of the composition in frameTime. 30 | public let startFrame: AnimationFrameTime 31 | 32 | /// The end time of the composition in frameTime. 33 | public let endFrame: AnimationFrameTime 34 | 35 | /// The frame rate of the composition. 36 | public let framerate: Double 37 | 38 | /// The height of the composition in points. 39 | let width: Int 40 | 41 | /// The width of the composition in points. 42 | let height: Int 43 | 44 | /// The list of animation layers 45 | let layers: [LayerModel] 46 | 47 | /// The list of glyphs used for text rendering 48 | let glyphs: [Glyph]? 49 | 50 | /// The list of fonts used for text rendering 51 | let fonts: FontList? 52 | 53 | /// Asset Library 54 | let assetLibrary: AssetLibrary? 55 | 56 | /// Markers 57 | let markers: [Marker]? 58 | let markerMap: [String : Marker]? 59 | 60 | /// Return all marker names, in order, or an empty list if none are specified 61 | public var markerNames: [String] { 62 | guard let markers = markers else { return [] } 63 | return markers.map { $0.name } 64 | } 65 | 66 | enum CodingKeys : String, CodingKey { 67 | case version = "v" 68 | case type = "ddd" 69 | case startFrame = "ip" 70 | case endFrame = "op" 71 | case framerate = "fr" 72 | case width = "w" 73 | case height = "h" 74 | case layers = "layers" 75 | case glyphs = "chars" 76 | case fonts = "fonts" 77 | case assetLibrary = "assets" 78 | case markers = "markers" 79 | } 80 | 81 | required public init(from decoder: Decoder) throws { 82 | let container = try decoder.container(keyedBy: Animation.CodingKeys.self) 83 | self.version = try container.decode(String.self, forKey: .version) 84 | self.type = try container.decodeIfPresent(CoordinateSpace.self, forKey: .type) ?? .type2d 85 | self.startFrame = try container.decode(AnimationFrameTime.self, forKey: .startFrame) 86 | self.endFrame = try container.decode(AnimationFrameTime.self, forKey: .endFrame) 87 | self.framerate = try container.decode(Double.self, forKey: .framerate) 88 | self.width = try container.decode(Int.self, forKey: .width) 89 | self.height = try container.decode(Int.self, forKey: .height) 90 | self.layers = try container.decode([LayerModel].self, ofFamily: LayerType.self, forKey: .layers) 91 | self.glyphs = try container.decodeIfPresent([Glyph].self, forKey: .glyphs) 92 | self.fonts = try container.decodeIfPresent(FontList.self, forKey: .fonts) 93 | self.assetLibrary = try container.decodeIfPresent(AssetLibrary.self, forKey: .assetLibrary) 94 | self.markers = try container.decodeIfPresent([Marker].self, forKey: .markers) 95 | 96 | if let markers = markers { 97 | var markerMap: [String : Marker] = [:] 98 | for marker in markers { 99 | markerMap[marker.name] = marker 100 | } 101 | self.markerMap = markerMap 102 | } else { 103 | self.markerMap = nil 104 | } 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Assets/Asset.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Asset.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/9/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public class Asset: Codable { 11 | 12 | /// The ID of the asset 13 | let id: String 14 | 15 | private enum CodingKeys : String, CodingKey { 16 | case id = "id" 17 | } 18 | 19 | required public init(from decoder: Decoder) throws { 20 | let container = try decoder.container(keyedBy: Asset.CodingKeys.self) 21 | if let id = try? container.decode(String.self, forKey: .id) { 22 | self.id = id 23 | } else { 24 | self.id = String(try container.decode(Int.self, forKey: .id)) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Assets/AssetLibrary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AssetLibrary.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/9/19. 6 | // 7 | 8 | import Foundation 9 | 10 | final class AssetLibrary: Codable { 11 | 12 | /// The Assets 13 | let assets: [String : Asset] 14 | 15 | let imageAssets: [String : ImageAsset] 16 | let precompAssets: [String : PrecompAsset] 17 | 18 | required init(from decoder: Decoder) throws { 19 | var container = try decoder.unkeyedContainer() 20 | var containerForKeys = container 21 | 22 | var decodedAssets = [String : Asset]() 23 | 24 | var imageAssets = [String : ImageAsset]() 25 | var precompAssets = [String : PrecompAsset]() 26 | 27 | while !container.isAtEnd { 28 | let keyContainer = try containerForKeys.nestedContainer(keyedBy: PrecompAsset.CodingKeys.self) 29 | if keyContainer.contains(.layers) { 30 | let precompAsset = try container.decode(PrecompAsset.self) 31 | decodedAssets[precompAsset.id] = precompAsset 32 | precompAssets[precompAsset.id] = precompAsset 33 | } else { 34 | let imageAsset = try container.decode(ImageAsset.self) 35 | decodedAssets[imageAsset.id] = imageAsset 36 | imageAssets[imageAsset.id] = imageAsset 37 | } 38 | } 39 | self.assets = decodedAssets 40 | self.precompAssets = precompAssets 41 | self.imageAssets = imageAssets 42 | } 43 | 44 | func encode(to encoder: Encoder) throws { 45 | var container = encoder.unkeyedContainer() 46 | try container.encode(contentsOf: Array(assets.values)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Assets/ImageAsset.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageAsset.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/9/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public final class ImageAsset: Asset { 11 | 12 | /// Image name 13 | public let name: String 14 | 15 | /// Image Directory 16 | public let directory: String 17 | 18 | /// Image Size 19 | public let width: Double 20 | 21 | public let height: Double 22 | 23 | enum CodingKeys : String, CodingKey { 24 | case name = "p" 25 | case directory = "u" 26 | case width = "w" 27 | case height = "h" 28 | } 29 | 30 | required init(from decoder: Decoder) throws { 31 | let container = try decoder.container(keyedBy: ImageAsset.CodingKeys.self) 32 | self.name = try container.decode(String.self, forKey: .name) 33 | self.directory = try container.decode(String.self, forKey: .directory) 34 | self.width = try container.decode(Double.self, forKey: .width) 35 | self.height = try container.decode(Double.self, forKey: .height) 36 | try super.init(from: decoder) 37 | } 38 | 39 | override public func encode(to encoder: Encoder) throws { 40 | try super.encode(to: encoder) 41 | var container = encoder.container(keyedBy: CodingKeys.self) 42 | try container.encode(name, forKey: .name) 43 | try container.encode(directory, forKey: .directory) 44 | try container.encode(width, forKey: .width) 45 | try container.encode(height, forKey: .height) 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Assets/PrecompAsset.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrecompAsset.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/9/19. 6 | // 7 | 8 | import Foundation 9 | 10 | final class PrecompAsset: Asset { 11 | 12 | /// Layers of the precomp 13 | let layers: [LayerModel] 14 | 15 | enum CodingKeys : String, CodingKey { 16 | case layers = "layers" 17 | } 18 | 19 | required init(from decoder: Decoder) throws { 20 | let container = try decoder.container(keyedBy: PrecompAsset.CodingKeys.self) 21 | self.layers = try container.decode([LayerModel].self, ofFamily: LayerType.self, forKey: .layers) 22 | try super.init(from: decoder) 23 | } 24 | 25 | override func encode(to encoder: Encoder) throws { 26 | try super.encode(to: encoder) 27 | var container = encoder.container(keyedBy: CodingKeys.self) 28 | try container.encode(layers, forKey: .layers) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift: -------------------------------------------------------------------------------- 1 | // From: https://medium.com/@kewindannerfjordremeczki/swift-4-0-decodable-heterogeneous-collections-ecc0e6b468cf 2 | 3 | import Foundation 4 | 5 | /// To support a new class family, create an enum that conforms to this protocol and contains the different types. 6 | protocol ClassFamily: Decodable { 7 | /// The discriminator key. 8 | static var discriminator: Discriminator { get } 9 | 10 | /// Returns the class type of the object corresponding to the value. 11 | func getType() -> AnyObject.Type 12 | } 13 | 14 | /// Discriminator key enum used to retrieve discriminator fields in JSON payloads. 15 | enum Discriminator: String, CodingKey { 16 | case type = "ty" 17 | } 18 | 19 | extension KeyedDecodingContainer { 20 | 21 | /// Decode a heterogeneous list of objects for a given family. 22 | /// - Parameters: 23 | /// - heterogeneousType: The decodable type of the list. 24 | /// - family: The ClassFamily enum for the type family. 25 | /// - key: The CodingKey to look up the list in the current container. 26 | /// - Returns: The resulting list of heterogeneousType elements. 27 | func decode(_ heterogeneousType: [T].Type, ofFamily family: U.Type, forKey key: K) throws -> [T] { 28 | var container = try self.nestedUnkeyedContainer(forKey: key) 29 | var list = [T]() 30 | var tmpContainer = container 31 | while !container.isAtEnd { 32 | let typeContainer = try container.nestedContainer(keyedBy: Discriminator.self) 33 | let family: U = try typeContainer.decode(U.self, forKey: U.discriminator) 34 | if let type = family.getType() as? T.Type { 35 | list.append(try tmpContainer.decode(type)) 36 | } 37 | } 38 | return list 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Keyframes/Keyframe.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Keyframe.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/7/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /** 12 | Keyframe represents a point in time and is the container for datatypes. 13 | Note: This is a parent class and should not be used directly. 14 | */ 15 | final class Keyframe { 16 | 17 | /// The value of the keyframe 18 | let value: T 19 | /// The time in frames of the keyframe. 20 | let time: CGFloat 21 | /// A hold keyframe freezes interpolation until the next keyframe that is not a hold. 22 | let isHold: Bool 23 | /// The in tangent for the time interpolation curve. 24 | let inTangent: Vector2D? 25 | /// The out tangent for the time interpolation curve. 26 | let outTangent: Vector2D? 27 | 28 | /// The spacial in tangent of the vector. 29 | let spatialInTangent: Vector3D? 30 | /// The spacial out tangent of the vector. 31 | let spatialOutTangent: Vector3D? 32 | 33 | /// Initialize a value-only keyframe with no time data. 34 | init(_ value: T, 35 | spatialInTangent: Vector3D? = nil, 36 | spatialOutTangent: Vector3D? = nil) { 37 | self.value = value 38 | self.time = 0 39 | self.isHold = true 40 | self.inTangent = nil 41 | self.outTangent = nil 42 | self.spatialInTangent = spatialInTangent 43 | self.spatialOutTangent = spatialOutTangent 44 | } 45 | 46 | /// Initialize a keyframe 47 | init(value: T, 48 | time: Double, 49 | isHold: Bool, 50 | inTangent: Vector2D?, 51 | outTangent: Vector2D?, 52 | spatialInTangent: Vector3D? = nil, 53 | spatialOutTangent: Vector3D? = nil) { 54 | self.value = value 55 | self.time = CGFloat(time) 56 | self.isHold = isHold 57 | self.outTangent = outTangent 58 | self.inTangent = inTangent 59 | self.spatialInTangent = spatialInTangent 60 | self.spatialOutTangent = spatialOutTangent 61 | } 62 | 63 | } 64 | 65 | /** 66 | A generic class used to parse and remap keyframe json. 67 | 68 | Keyframe json has a couple of different variations and formats depending on the 69 | type of keyframea and also the version of the JSON. By parsing the raw data 70 | we can reconfigure it into a constant format. 71 | */ 72 | final class KeyframeData: Codable { 73 | 74 | /// The start value of the keyframe 75 | let startValue: T? 76 | /// The End value of the keyframe. Note: Newer versions animation json do not have this field. 77 | let endValue: T? 78 | /// The time in frames of the keyframe. 79 | let time: Double? 80 | /// A hold keyframe freezes interpolation until the next keyframe that is not a hold. 81 | let hold: Int? 82 | 83 | /// The in tangent for the time interpolation curve. 84 | let inTangent: Vector2D? 85 | /// The out tangent for the time interpolation curve. 86 | let outTangent: Vector2D? 87 | 88 | /// The spacial in tangent of the vector. 89 | let spatialInTangent: Vector3D? 90 | /// The spacial out tangent of the vector. 91 | let spatialOutTangent:Vector3D? 92 | 93 | init(startValue: T?, 94 | endValue: T?, 95 | time: Double?, 96 | hold: Int?, 97 | inTangent: Vector2D?, 98 | outTangent: Vector2D?, 99 | spatialInTangent: Vector3D?, 100 | spatialOutTangent: Vector3D?) { 101 | self.startValue = startValue 102 | self.endValue = endValue 103 | self.time = time 104 | self.hold = hold 105 | self.inTangent = inTangent 106 | self.outTangent = outTangent 107 | self.spatialInTangent = spatialInTangent 108 | self.spatialOutTangent = spatialOutTangent 109 | } 110 | 111 | enum CodingKeys : String, CodingKey { 112 | case startValue = "s" 113 | case endValue = "e" 114 | case time = "t" 115 | case hold = "h" 116 | case inTangent = "i" 117 | case outTangent = "o" 118 | case spatialInTangent = "ti" 119 | case spatialOutTangent = "to" 120 | } 121 | 122 | var isHold: Bool { 123 | if let hold = hold { 124 | return hold > 0 125 | } 126 | return false 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Layers/ImageLayerModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// A layer that holds an image. 11 | final class ImageLayerModel: LayerModel { 12 | 13 | /// The reference ID of the image. 14 | let referenceID: String 15 | 16 | private enum CodingKeys : String, CodingKey { 17 | case referenceID = "refId" 18 | } 19 | 20 | required init(from decoder: Decoder) throws { 21 | let container = try decoder.container(keyedBy: ImageLayerModel.CodingKeys.self) 22 | self.referenceID = try container.decode(String.self, forKey: .referenceID) 23 | try super.init(from: decoder) 24 | } 25 | 26 | override func encode(to encoder: Encoder) throws { 27 | try super.encode(to: encoder) 28 | var container = encoder.container(keyedBy: CodingKeys.self) 29 | try container.encode(referenceID, forKey: .referenceID) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Layers/PreCompLayerModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreCompLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// A layer that holds another animation composition. 11 | final class PreCompLayerModel: LayerModel { 12 | 13 | /// The reference ID of the precomp. 14 | let referenceID: String 15 | 16 | /// A value that remaps time over time. 17 | let timeRemapping: KeyframeGroup? 18 | 19 | /// Precomp Width 20 | let width: Double 21 | 22 | /// Precomp Height 23 | let height: Double 24 | 25 | private enum CodingKeys : String, CodingKey { 26 | case referenceID = "refId" 27 | case timeRemapping = "tm" 28 | case width = "w" 29 | case height = "h" 30 | } 31 | 32 | required init(from decoder: Decoder) throws { 33 | let container = try decoder.container(keyedBy: PreCompLayerModel.CodingKeys.self) 34 | self.referenceID = try container.decode(String.self, forKey: .referenceID) 35 | self.timeRemapping = try container.decodeIfPresent(KeyframeGroup.self, forKey: .timeRemapping) 36 | self.width = try container.decode(Double.self, forKey: .width) 37 | self.height = try container.decode(Double.self, forKey: .height) 38 | try super.init(from: decoder) 39 | } 40 | 41 | override func encode(to encoder: Encoder) throws { 42 | try super.encode(to: encoder) 43 | var container = encoder.container(keyedBy: CodingKeys.self) 44 | try container.encode(referenceID, forKey: .referenceID) 45 | try container.encode(timeRemapping, forKey: .timeRemapping) 46 | try container.encode(width, forKey: .width) 47 | try container.encode(height, forKey: .height) 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Layers/ShapeLayerModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShapeLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// A layer that holds vector shape objects. 11 | final class ShapeLayerModel: LayerModel { 12 | 13 | /// A list of shape items. 14 | let items: [ShapeItem] 15 | 16 | private enum CodingKeys : String, CodingKey { 17 | case items = "shapes" 18 | } 19 | 20 | required init(from decoder: Decoder) throws { 21 | let container = try decoder.container(keyedBy: ShapeLayerModel.CodingKeys.self) 22 | self.items = try container.decode([ShapeItem].self, ofFamily: ShapeType.self, forKey: .items) 23 | try super.init(from: decoder) 24 | } 25 | 26 | override func encode(to encoder: Encoder) throws { 27 | try super.encode(to: encoder) 28 | var container = encoder.container(keyedBy: CodingKeys.self) 29 | try container.encode(self.items, forKey: .items) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Layers/SolidLayerModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolidLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// A layer that holds a solid color. 11 | final class SolidLayerModel: LayerModel { 12 | 13 | /// The color of the solid in Hex // Change to value provider. 14 | let colorHex: String 15 | 16 | /// The Width of the color layer 17 | let width: Double 18 | 19 | /// The height of the color layer 20 | let height: Double 21 | 22 | private enum CodingKeys : String, CodingKey { 23 | case colorHex = "sc" 24 | case width = "sw" 25 | case height = "sh" 26 | } 27 | 28 | required init(from decoder: Decoder) throws { 29 | let container = try decoder.container(keyedBy: SolidLayerModel.CodingKeys.self) 30 | self.colorHex = try container.decode(String.self, forKey: .colorHex) 31 | self.width = try container.decode(Double.self, forKey: .width) 32 | self.height = try container.decode(Double.self, forKey: .height) 33 | try super.init(from: decoder) 34 | } 35 | 36 | override func encode(to encoder: Encoder) throws { 37 | try super.encode(to: encoder) 38 | var container = encoder.container(keyedBy: CodingKeys.self) 39 | try container.encode(colorHex, forKey: .colorHex) 40 | try container.encode(width, forKey: .width) 41 | try container.encode(height, forKey: .height) 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Layers/TextLayerModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// A layer that holds text. 11 | final class TextLayerModel: LayerModel { 12 | 13 | /// The text for the layer 14 | let text: KeyframeGroup 15 | 16 | /// Text animators 17 | let animators: [TextAnimator] 18 | 19 | private enum CodingKeys : String, CodingKey { 20 | case textGroup = "t" 21 | } 22 | 23 | private enum TextCodingKeys : String, CodingKey { 24 | case text = "d" 25 | case animators = "a" 26 | } 27 | 28 | required init(from decoder: Decoder) throws { 29 | let container = try decoder.container(keyedBy: TextLayerModel.CodingKeys.self) 30 | let textContainer = try container.nestedContainer(keyedBy: TextCodingKeys.self, forKey: .textGroup) 31 | self.text = try textContainer.decode(KeyframeGroup.self, forKey: .text) 32 | self.animators = try textContainer.decode([TextAnimator].self, forKey: .animators) 33 | try super.init(from: decoder) 34 | } 35 | 36 | override func encode(to encoder: Encoder) throws { 37 | try super.encode(to: encoder) 38 | var container = encoder.container(keyedBy: CodingKeys.self) 39 | var textContainer = container.nestedContainer(keyedBy: TextCodingKeys.self, forKey: .textGroup) 40 | try textContainer.encode(text, forKey: .text) 41 | try textContainer.encode(animators, forKey: .animators) 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Objects/DashPattern.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DashPattern.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/22/19. 6 | // 7 | 8 | import Foundation 9 | 10 | enum DashElementType: String, Codable { 11 | case offset = "o" 12 | case dash = "d" 13 | case gap = "g" 14 | } 15 | 16 | final class DashElement: Codable { 17 | let type: DashElementType 18 | let value: KeyframeGroup 19 | 20 | enum CodingKeys : String, CodingKey { 21 | case type = "n" 22 | case value = "v" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Objects/Marker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Marker.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/9/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// A time marker 11 | final class Marker: Codable { 12 | 13 | /// The Marker Name 14 | let name: String 15 | 16 | /// The Frame time of the marker 17 | let frameTime: AnimationFrameTime 18 | 19 | enum CodingKeys : String, CodingKey { 20 | case name = "cm" 21 | case frameTime = "tm" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Objects/Mask.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Mask.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | enum MaskMode: String, Codable { 11 | case add = "a" 12 | case subtract = "s" 13 | case intersect = "i" 14 | case lighten = "l" 15 | case darken = "d" 16 | case difference = "f" 17 | case none = "n" 18 | } 19 | 20 | final class Mask: Codable { 21 | 22 | let mode: MaskMode 23 | 24 | let opacity: KeyframeGroup 25 | 26 | let shape: KeyframeGroup 27 | 28 | let inverted: Bool 29 | 30 | let expansion: KeyframeGroup 31 | 32 | enum CodingKeys : String, CodingKey { 33 | case mode = "mode" 34 | case opacity = "o" 35 | case inverted = "inv" 36 | case shape = "pt" 37 | case expansion = "x" 38 | } 39 | 40 | required init(from decoder: Decoder) throws { 41 | let container = try decoder.container(keyedBy: Mask.CodingKeys.self) 42 | self.mode = try container.decodeIfPresent(MaskMode.self, forKey: .mode) ?? .add 43 | self.opacity = try container.decodeIfPresent(KeyframeGroup.self, forKey: .opacity) ?? KeyframeGroup(Vector1D(100)) 44 | self.shape = try container.decode(KeyframeGroup.self, forKey: .shape) 45 | self.inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false 46 | self.expansion = try container.decodeIfPresent(KeyframeGroup.self, forKey: .expansion) ?? KeyframeGroup(Vector1D(0)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Objects/Transform.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Transform.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/7/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// The animatable transform for a layer. Controls position, rotation, scale, and opacity. 11 | final class Transform: Codable { 12 | 13 | /// The anchor point of the transform. 14 | let anchorPoint: KeyframeGroup 15 | 16 | /// The position of the transform. This is nil if the position data was split. 17 | let position: KeyframeGroup? 18 | 19 | /// The positionX of the transform. This is nil if the position property is set. 20 | let positionX: KeyframeGroup? 21 | 22 | /// The positionY of the transform. This is nil if the position property is set. 23 | let positionY: KeyframeGroup? 24 | 25 | /// The scale of the transform 26 | let scale: KeyframeGroup 27 | 28 | /// The rotation of the transform. Note: This is single dimensional rotation. 29 | let rotation: KeyframeGroup 30 | 31 | /// The opacity of the transform. 32 | let opacity: KeyframeGroup 33 | 34 | /// Should always be nil. 35 | let rotationZ: KeyframeGroup? 36 | 37 | enum CodingKeys : String, CodingKey { 38 | case anchorPoint = "a" 39 | case position = "p" 40 | case positionX = "px" 41 | case positionY = "py" 42 | case scale = "s" 43 | case rotation = "r" 44 | case rotationZ = "rz" 45 | case opacity = "o" 46 | } 47 | 48 | enum PositionCodingKeys : String, CodingKey { 49 | case split = "s" 50 | case positionX = "x" 51 | case positionY = "y" 52 | } 53 | 54 | 55 | required init(from decoder: Decoder) throws { 56 | /** 57 | This manual override of decode is required because we want to throw an error 58 | in the case that there is not position data. 59 | */ 60 | let container = try decoder.container(keyedBy: Transform.CodingKeys.self) 61 | 62 | // AnchorPoint 63 | self.anchorPoint = try container.decodeIfPresent(KeyframeGroup.self, forKey: .anchorPoint) ?? KeyframeGroup(Vector3D(x: Double(0), y: 0, z: 0)) 64 | 65 | // Position 66 | if container.contains(.positionX), container.contains(.positionY) { 67 | // Position dimensions are split into two keyframe groups 68 | self.positionX = try container.decode(KeyframeGroup.self, forKey: .positionX) 69 | self.positionY = try container.decode(KeyframeGroup.self, forKey: .positionY) 70 | self.position = nil 71 | } else if let positionKeyframes = try? container.decode(KeyframeGroup.self, forKey: .position) { 72 | // Position dimensions are a single keyframe group. 73 | self.position = positionKeyframes 74 | self.positionX = nil 75 | self.positionY = nil 76 | } else if let positionContainer = try? container.nestedContainer(keyedBy: PositionCodingKeys.self, forKey: .position), 77 | let positionX = try? positionContainer.decode(KeyframeGroup.self, forKey: .positionX), 78 | let positionY = try? positionContainer.decode(KeyframeGroup.self, forKey: .positionY) { 79 | /// Position keyframes are split and nested. 80 | self.positionX = positionX 81 | self.positionY = positionY 82 | self.position = nil 83 | } else { 84 | /// Default value. 85 | self.position = KeyframeGroup(Vector3D(x: Double(0), y: 0, z: 0)) 86 | self.positionX = nil 87 | self.positionY = nil 88 | } 89 | 90 | 91 | // Scale 92 | self.scale = try container.decodeIfPresent(KeyframeGroup.self, forKey: .scale) ?? KeyframeGroup(Vector3D(x: Double(100), y: 100, z: 100)) 93 | 94 | // Rotation 95 | if let rotationZ = try container.decodeIfPresent(KeyframeGroup.self, forKey: .rotationZ) { 96 | self.rotation = rotationZ 97 | } else { 98 | self.rotation = try container.decodeIfPresent(KeyframeGroup.self, forKey: .rotation) ?? KeyframeGroup(Vector1D(0)) 99 | } 100 | self.rotationZ = nil 101 | 102 | // Opacity 103 | self.opacity = try container.decodeIfPresent(KeyframeGroup.self, forKey: .opacity) ?? KeyframeGroup(Vector1D(100)) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/Ellipse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EllipseItem.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | enum PathDirection: Int, Codable { 11 | case clockwise = 1 12 | case userSetClockwise = 2 13 | case counterClockwise = 3 14 | } 15 | 16 | /// An item that define an ellipse shape 17 | final class Ellipse: ShapeItem { 18 | 19 | /// The direction of the ellipse. 20 | let direction: PathDirection 21 | 22 | /// The position of the ellipse 23 | let position: KeyframeGroup 24 | 25 | /// The size of the ellipse 26 | let size: KeyframeGroup 27 | 28 | private enum CodingKeys : String, CodingKey { 29 | case direction = "d" 30 | case position = "p" 31 | case size = "s" 32 | } 33 | 34 | required init(from decoder: Decoder) throws { 35 | let container = try decoder.container(keyedBy: Ellipse.CodingKeys.self) 36 | self.direction = try container.decodeIfPresent(PathDirection.self, forKey: .direction) ?? .clockwise 37 | self.position = try container.decode(KeyframeGroup.self, forKey: .position) 38 | self.size = try container.decode(KeyframeGroup.self, forKey: .size) 39 | try super.init(from: decoder) 40 | } 41 | 42 | override func encode(to encoder: Encoder) throws { 43 | try super.encode(to: encoder) 44 | var container = encoder.container(keyedBy: CodingKeys.self) 45 | try container.encode(direction, forKey: .direction) 46 | try container.encode(position, forKey: .position) 47 | try container.encode(size, forKey: .size) 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/FillI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FillShape.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | enum FillRule: Int, Codable { 11 | case none 12 | case nonZeroWinding 13 | case evenOdd 14 | } 15 | 16 | /// An item that defines a fill render 17 | final class Fill: ShapeItem { 18 | 19 | /// The opacity of the fill 20 | let opacity: KeyframeGroup 21 | 22 | /// The color keyframes for the fill 23 | let color: KeyframeGroup 24 | 25 | let fillRule: FillRule 26 | 27 | private enum CodingKeys : String, CodingKey { 28 | case opacity = "o" 29 | case color = "c" 30 | case fillRule = "r" 31 | } 32 | 33 | required init(from decoder: Decoder) throws { 34 | let container = try decoder.container(keyedBy: Fill.CodingKeys.self) 35 | self.opacity = try container.decode(KeyframeGroup.self, forKey: .opacity) 36 | self.color = try container.decode(KeyframeGroup.self, forKey: .color) 37 | self.fillRule = try container.decodeIfPresent(FillRule.self, forKey: .fillRule) ?? .nonZeroWinding 38 | try super.init(from: decoder) 39 | } 40 | 41 | override func encode(to encoder: Encoder) throws { 42 | try super.encode(to: encoder) 43 | var container = encoder.container(keyedBy: CodingKeys.self) 44 | try container.encode(opacity, forKey: .opacity) 45 | try container.encode(color, forKey: .color) 46 | try container.encode(fillRule, forKey: .fillRule) 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/GradientFill.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GradientFill.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | enum GradientType: Int, Codable { 11 | case none 12 | case linear 13 | case radial 14 | } 15 | 16 | /// An item that define a gradient fill 17 | final class GradientFill: ShapeItem { 18 | 19 | /// The opacity of the fill 20 | let opacity: KeyframeGroup 21 | 22 | /// The start of the gradient 23 | let startPoint: KeyframeGroup 24 | 25 | /// The end of the gradient 26 | let endPoint: KeyframeGroup 27 | 28 | /// The type of gradient 29 | let gradientType: GradientType 30 | 31 | /// Gradient Highlight Length. Only if type is Radial 32 | let highlightLength: KeyframeGroup? 33 | 34 | /// Highlight Angle. Only if type is Radial 35 | let highlightAngle: KeyframeGroup? 36 | 37 | /// The number of color points in the gradient 38 | let numberOfColors: Int 39 | 40 | /// The Colors of the gradient. 41 | let colors: KeyframeGroup<[Double]> 42 | 43 | private enum CodingKeys : String, CodingKey { 44 | case opacity = "o" 45 | case startPoint = "s" 46 | case endPoint = "e" 47 | case gradientType = "t" 48 | case highlightLength = "h" 49 | case highlightAngle = "a" 50 | case colors = "g" 51 | } 52 | 53 | private enum GradientDataKeys : String, CodingKey { 54 | case numberOfColors = "p" 55 | case colors = "k" 56 | } 57 | 58 | required init(from decoder: Decoder) throws { 59 | let container = try decoder.container(keyedBy: GradientFill.CodingKeys.self) 60 | self.opacity = try container.decode(KeyframeGroup.self, forKey: .opacity) 61 | self.startPoint = try container.decode(KeyframeGroup.self, forKey: .startPoint) 62 | self.endPoint = try container.decode(KeyframeGroup.self, forKey: .endPoint) 63 | self.gradientType = try container.decode(GradientType.self, forKey: .gradientType) 64 | self.highlightLength = try container.decodeIfPresent(KeyframeGroup.self, forKey: .highlightLength) 65 | self.highlightAngle = try container.decodeIfPresent(KeyframeGroup.self, forKey: .highlightAngle) 66 | let colorsContainer = try container.nestedContainer(keyedBy: GradientDataKeys.self, forKey: .colors) 67 | self.colors = try colorsContainer.decode(KeyframeGroup<[Double]>.self, forKey: .colors) 68 | self.numberOfColors = try colorsContainer.decode(Int.self, forKey: .numberOfColors) 69 | try super.init(from: decoder) 70 | } 71 | 72 | override func encode(to encoder: Encoder) throws { 73 | try super.encode(to: encoder) 74 | var container = encoder.container(keyedBy: CodingKeys.self) 75 | try container.encode(opacity, forKey: .opacity) 76 | try container.encode(startPoint, forKey: .startPoint) 77 | try container.encode(endPoint, forKey: .endPoint) 78 | try container.encode(gradientType, forKey: .gradientType) 79 | try container.encodeIfPresent(highlightLength, forKey: .highlightLength) 80 | try container.encodeIfPresent(highlightAngle, forKey: .highlightAngle) 81 | var colorsContainer = container.nestedContainer(keyedBy: GradientDataKeys.self, forKey: .colors) 82 | try colorsContainer.encode(numberOfColors, forKey: .numberOfColors) 83 | try colorsContainer.encode(colors, forKey: .colors) 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/Group.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GroupItem.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// An item that define an ellipse shape 11 | final class Group: ShapeItem { 12 | 13 | /// A list of shape items. 14 | let items: [ShapeItem] 15 | 16 | private enum CodingKeys : String, CodingKey { 17 | case items = "it" 18 | } 19 | 20 | required init(from decoder: Decoder) throws { 21 | let container = try decoder.container(keyedBy: Group.CodingKeys.self) 22 | self.items = try container.decode([ShapeItem].self, ofFamily: ShapeType.self, forKey: .items) 23 | try super.init(from: decoder) 24 | } 25 | 26 | override func encode(to encoder: Encoder) throws { 27 | try super.encode(to: encoder) 28 | var container = encoder.container(keyedBy: CodingKeys.self) 29 | try container.encode(items, forKey: .items) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/Merge.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Merge.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | enum MergeMode: Int, Codable { 11 | case none 12 | case merge 13 | case add 14 | case subtract 15 | case intersect 16 | case exclude 17 | } 18 | 19 | /// An item that define an ellipse shape 20 | final class Merge: ShapeItem { 21 | 22 | /// The mode of the merge path 23 | let mode: MergeMode 24 | 25 | private enum CodingKeys : String, CodingKey { 26 | case mode = "mm" 27 | } 28 | 29 | required init(from decoder: Decoder) throws { 30 | let container = try decoder.container(keyedBy: Merge.CodingKeys.self) 31 | self.mode = try container.decode(MergeMode.self, forKey: .mode) 32 | try super.init(from: decoder) 33 | } 34 | 35 | override func encode(to encoder: Encoder) throws { 36 | try super.encode(to: encoder) 37 | var container = encoder.container(keyedBy: CodingKeys.self) 38 | try container.encode(mode, forKey: .mode) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/Rectangle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Rectangle.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// An item that define an ellipse shape 11 | final class Rectangle: ShapeItem { 12 | 13 | /// The direction of the rect. 14 | let direction: PathDirection 15 | 16 | /// The position 17 | let position: KeyframeGroup 18 | 19 | /// The size 20 | let size: KeyframeGroup 21 | 22 | /// The Corner radius of the rectangle 23 | let cornerRadius: KeyframeGroup 24 | 25 | private enum CodingKeys : String, CodingKey { 26 | case direction = "d" 27 | case position = "p" 28 | case size = "s" 29 | case cornerRadius = "r" 30 | } 31 | 32 | required init(from decoder: Decoder) throws { 33 | let container = try decoder.container(keyedBy: Rectangle.CodingKeys.self) 34 | self.direction = try container.decodeIfPresent(PathDirection.self, forKey: .direction) ?? .clockwise 35 | self.position = try container.decode(KeyframeGroup.self, forKey: .position) 36 | self.size = try container.decode(KeyframeGroup.self, forKey: .size) 37 | self.cornerRadius = try container.decode(KeyframeGroup.self, forKey: .cornerRadius) 38 | try super.init(from: decoder) 39 | } 40 | 41 | override func encode(to encoder: Encoder) throws { 42 | try super.encode(to: encoder) 43 | var container = encoder.container(keyedBy: CodingKeys.self) 44 | try container.encode(direction, forKey: .direction) 45 | try container.encode(position, forKey: .position) 46 | try container.encode(size, forKey: .size) 47 | try container.encode(cornerRadius, forKey: .cornerRadius) 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/Repeater.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Repeater.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// An item that define an ellipse shape 11 | final class Repeater: ShapeItem { 12 | 13 | /// The number of copies to repeat 14 | let copies: KeyframeGroup 15 | 16 | /// The offset of each copy 17 | let offset: KeyframeGroup 18 | 19 | /// Start Opacity 20 | let startOpacity: KeyframeGroup 21 | 22 | /// End opacity 23 | let endOpacity: KeyframeGroup 24 | 25 | /// The rotation 26 | let rotation: KeyframeGroup 27 | 28 | /// Anchor Point 29 | let anchorPoint: KeyframeGroup 30 | 31 | /// Position 32 | let position: KeyframeGroup 33 | 34 | /// Scale 35 | let scale: KeyframeGroup 36 | 37 | private enum CodingKeys : String, CodingKey { 38 | case copies = "c" 39 | case offset = "o" 40 | case transform = "tr" 41 | } 42 | 43 | private enum TransformKeys : String, CodingKey { 44 | case rotation = "r" 45 | case startOpacity = "so" 46 | case endOpacity = "eo" 47 | case anchorPoint = "a" 48 | case position = "p" 49 | case scale = "s" 50 | } 51 | 52 | required init(from decoder: Decoder) throws { 53 | let container = try decoder.container(keyedBy: Repeater.CodingKeys.self) 54 | self.copies = try container.decodeIfPresent(KeyframeGroup.self, forKey: .copies) ?? KeyframeGroup(Vector1D(0)) 55 | self.offset = try container.decodeIfPresent(KeyframeGroup.self, forKey: .offset) ?? KeyframeGroup(Vector1D(0)) 56 | let transformContainer = try container.nestedContainer(keyedBy: TransformKeys.self, forKey: .transform) 57 | self.startOpacity = try transformContainer.decodeIfPresent(KeyframeGroup.self, forKey: .startOpacity) ?? KeyframeGroup(Vector1D(100)) 58 | self.endOpacity = try transformContainer.decodeIfPresent(KeyframeGroup.self, forKey: .endOpacity) ?? KeyframeGroup(Vector1D(100)) 59 | self.rotation = try transformContainer.decodeIfPresent(KeyframeGroup.self, forKey: .rotation) ?? KeyframeGroup(Vector1D(0)) 60 | self.position = try transformContainer.decodeIfPresent(KeyframeGroup.self, forKey: .position) ?? KeyframeGroup(Vector3D(x: Double(0), y: 0, z: 0)) 61 | self.anchorPoint = try transformContainer.decodeIfPresent(KeyframeGroup.self, forKey: .anchorPoint) ?? KeyframeGroup(Vector3D(x: Double(0), y: 0, z: 0)) 62 | self.scale = try transformContainer.decodeIfPresent(KeyframeGroup.self, forKey: .scale) ?? KeyframeGroup(Vector3D(x: Double(100), y: 100, z: 100)) 63 | try super.init(from: decoder) 64 | } 65 | 66 | override func encode(to encoder: Encoder) throws { 67 | try super.encode(to: encoder) 68 | var container = encoder.container(keyedBy: CodingKeys.self) 69 | try container.encode(copies, forKey: .copies) 70 | try container.encode(offset, forKey: .offset) 71 | var transformContainer = container.nestedContainer(keyedBy: TransformKeys.self, forKey: .transform) 72 | try transformContainer.encode(startOpacity, forKey: .startOpacity) 73 | try transformContainer.encode(endOpacity, forKey: .endOpacity) 74 | try transformContainer.encode(rotation, forKey: .rotation) 75 | try transformContainer.encode(position, forKey: .position) 76 | try transformContainer.encode(anchorPoint, forKey: .anchorPoint) 77 | try transformContainer.encode(scale, forKey: .scale) 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/Shape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VectorShape.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// An item that define an ellipse shape 11 | final class Shape: ShapeItem { 12 | 13 | /// The Path 14 | let path: KeyframeGroup 15 | 16 | let direction: PathDirection? 17 | 18 | private enum CodingKeys : String, CodingKey { 19 | case path = "ks" 20 | case direction = "d" 21 | } 22 | 23 | required init(from decoder: Decoder) throws { 24 | let container = try decoder.container(keyedBy: Shape.CodingKeys.self) 25 | self.path = try container.decode(KeyframeGroup.self, forKey: .path) 26 | self.direction = try container.decodeIfPresent(PathDirection.self, forKey: .direction) 27 | try super.init(from: decoder) 28 | } 29 | 30 | override func encode(to encoder: Encoder) throws { 31 | try super.encode(to: encoder) 32 | var container = encoder.container(keyedBy: CodingKeys.self) 33 | try container.encode(path, forKey: .path) 34 | try container.encodeIfPresent(direction, forKey: .direction) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/ShapeItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShapeItem.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Used for mapping a heterogeneous list to classes for parsing. 11 | extension ShapeType: ClassFamily { 12 | 13 | static var discriminator: Discriminator = .type 14 | 15 | func getType() -> AnyObject.Type { 16 | switch self { 17 | case .ellipse: 18 | return Ellipse.self 19 | case .fill: 20 | return Fill.self 21 | case .gradientFill: 22 | return GradientFill.self 23 | case .group: 24 | return Group.self 25 | case .gradientStroke: 26 | return GradientStroke.self 27 | case .merge: 28 | return Merge.self 29 | case .rectangle: 30 | return Rectangle.self 31 | case .repeater: 32 | return Repeater.self 33 | case .shape: 34 | return Shape.self 35 | case .star: 36 | return Star.self 37 | case .stroke: 38 | return Stroke.self 39 | case .trim: 40 | return Trim.self 41 | case .transform: 42 | return ShapeTransform.self 43 | default: 44 | return ShapeItem.self 45 | } 46 | } 47 | } 48 | 49 | enum ShapeType: String, Codable { 50 | case ellipse = "el" 51 | case fill = "fl" 52 | case gradientFill = "gf" 53 | case group = "gr" 54 | case gradientStroke = "gs" 55 | case merge = "mm" 56 | case rectangle = "rc" 57 | case repeater = "rp" 58 | case round = "rd" 59 | case shape = "sh" 60 | case star = "sr" 61 | case stroke = "st" 62 | case trim = "tm" 63 | case transform = "tr" 64 | case unknown 65 | 66 | public init(from decoder: Decoder) throws { 67 | self = try ShapeType(rawValue: decoder.singleValueContainer().decode(RawValue.self)) ?? .unknown 68 | } 69 | } 70 | 71 | /// An item belonging to a Shape Layer 72 | class ShapeItem: Codable { 73 | 74 | /// The name of the shape 75 | let name: String 76 | 77 | /// The type of shape 78 | let type: ShapeType 79 | 80 | let hidden: Bool 81 | 82 | private enum CodingKeys : String, CodingKey { 83 | case name = "nm" 84 | case type = "ty" 85 | case hidden = "hd" 86 | } 87 | 88 | required init(from decoder: Decoder) throws { 89 | let container = try decoder.container(keyedBy: ShapeItem.CodingKeys.self) 90 | self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? "Layer" 91 | self.type = try container.decode(ShapeType.self, forKey: .type) 92 | self.hidden = try container.decodeIfPresent(Bool.self, forKey: .hidden) ?? false 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/ShapeTransform.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransformItem.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// An item that define an ellipse shape 11 | final class ShapeTransform: ShapeItem { 12 | 13 | /// Anchor Point 14 | let anchor: KeyframeGroup 15 | 16 | /// Position 17 | let position: KeyframeGroup 18 | 19 | /// Scale 20 | let scale: KeyframeGroup 21 | 22 | /// Rotation 23 | let rotation: KeyframeGroup 24 | 25 | /// opacity 26 | let opacity: KeyframeGroup 27 | 28 | /// Skew 29 | let skew: KeyframeGroup 30 | 31 | /// Skew Axis 32 | let skewAxis: KeyframeGroup 33 | 34 | private enum CodingKeys : String, CodingKey { 35 | case anchor = "a" 36 | case position = "p" 37 | case scale = "s" 38 | case rotation = "r" 39 | case opacity = "o" 40 | case skew = "sk" 41 | case skewAxis = "sa" 42 | } 43 | 44 | required init(from decoder: Decoder) throws { 45 | let container = try decoder.container(keyedBy: ShapeTransform.CodingKeys.self) 46 | self.anchor = try container.decodeIfPresent(KeyframeGroup.self, forKey: .anchor) ?? KeyframeGroup(Vector3D(x: Double(0), y: 0, z: 0)) 47 | self.position = try container.decodeIfPresent(KeyframeGroup.self, forKey: .position) ?? KeyframeGroup(Vector3D(x: Double(0), y: 0, z: 0)) 48 | self.scale = try container.decodeIfPresent(KeyframeGroup.self, forKey: .scale) ?? KeyframeGroup(Vector3D(x: Double(100), y: 100, z: 100)) 49 | self.rotation = try container.decodeIfPresent(KeyframeGroup.self, forKey: .rotation) ?? KeyframeGroup(Vector1D(0)) 50 | self.opacity = try container.decodeIfPresent(KeyframeGroup.self, forKey: .opacity) ?? KeyframeGroup(Vector1D(100)) 51 | self.skew = try container.decodeIfPresent(KeyframeGroup.self, forKey: .skew) ?? KeyframeGroup(Vector1D(0)) 52 | self.skewAxis = try container.decodeIfPresent(KeyframeGroup.self, forKey: .skewAxis) ?? KeyframeGroup(Vector1D(0)) 53 | try super.init(from: decoder) 54 | } 55 | 56 | override func encode(to encoder: Encoder) throws { 57 | try super.encode(to: encoder) 58 | var container = encoder.container(keyedBy: CodingKeys.self) 59 | try container.encode(anchor, forKey: .anchor) 60 | try container.encode(position, forKey: .position) 61 | try container.encode(scale, forKey: .scale) 62 | try container.encode(rotation, forKey: .rotation) 63 | try container.encode(opacity, forKey: .opacity) 64 | try container.encode(skew, forKey: .skew) 65 | try container.encode(skewAxis, forKey: .skewAxis) 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/Star.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Star.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | enum StarType: Int, Codable { 11 | case none 12 | case star 13 | case polygon 14 | } 15 | 16 | /// An item that define an ellipse shape 17 | final class Star: ShapeItem { 18 | 19 | /// The direction of the star. 20 | let direction: PathDirection 21 | 22 | /// The position of the star 23 | let position: KeyframeGroup 24 | 25 | /// The outer radius of the star 26 | let outerRadius: KeyframeGroup 27 | 28 | /// The outer roundness of the star 29 | let outerRoundness: KeyframeGroup 30 | 31 | /// The outer radius of the star 32 | let innerRadius: KeyframeGroup? 33 | 34 | /// The outer roundness of the star 35 | let innerRoundness: KeyframeGroup? 36 | 37 | /// The rotation of the star 38 | let rotation: KeyframeGroup 39 | 40 | /// The number of points on the star 41 | let points: KeyframeGroup 42 | 43 | /// The type of star 44 | let starType: StarType 45 | 46 | private enum CodingKeys : String, CodingKey { 47 | case direction = "d" 48 | case position = "p" 49 | case outerRadius = "or" 50 | case outerRoundness = "os" 51 | case innerRadius = "ir" 52 | case innerRoundness = "is" 53 | case rotation = "r" 54 | case points = "pt" 55 | case starType = "sy" 56 | } 57 | 58 | required init(from decoder: Decoder) throws { 59 | let container = try decoder.container(keyedBy: Star.CodingKeys.self) 60 | self.direction = try container.decodeIfPresent(PathDirection.self, forKey: .direction) ?? .clockwise 61 | self.position = try container.decode(KeyframeGroup.self, forKey: .position) 62 | self.outerRadius = try container.decode(KeyframeGroup.self, forKey: .outerRadius) 63 | self.outerRoundness = try container.decode(KeyframeGroup.self, forKey: .outerRoundness) 64 | self.innerRadius = try container.decodeIfPresent(KeyframeGroup.self, forKey: .innerRadius) 65 | self.innerRoundness = try container.decodeIfPresent(KeyframeGroup.self, forKey: .innerRoundness) 66 | self.rotation = try container.decode(KeyframeGroup.self, forKey: .rotation) 67 | self.points = try container.decode(KeyframeGroup.self, forKey: .points) 68 | self.starType = try container.decode(StarType.self, forKey: .starType) 69 | try super.init(from: decoder) 70 | } 71 | 72 | override func encode(to encoder: Encoder) throws { 73 | try super.encode(to: encoder) 74 | var container = encoder.container(keyedBy: CodingKeys.self) 75 | try container.encode(direction, forKey: .direction) 76 | try container.encode(position, forKey: .position) 77 | try container.encode(outerRadius, forKey: .outerRadius) 78 | try container.encode(outerRoundness, forKey: .outerRoundness) 79 | try container.encode(innerRadius, forKey: .innerRadius) 80 | try container.encode(innerRoundness, forKey: .innerRoundness) 81 | try container.encode(rotation, forKey: .rotation) 82 | try container.encode(points, forKey: .points) 83 | try container.encode(starType, forKey: .starType) 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/Stroke.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Stroke.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// An item that define an ellipse shape 11 | final class Stroke: ShapeItem { 12 | 13 | /// The opacity of the stroke 14 | let opacity: KeyframeGroup 15 | 16 | /// The Color of the stroke 17 | let color: KeyframeGroup 18 | 19 | /// The width of the stroke 20 | let width: KeyframeGroup 21 | 22 | /// Line Cap 23 | let lineCap: LineCap 24 | 25 | /// Line Join 26 | let lineJoin: LineJoin 27 | 28 | /// Miter Limit 29 | let miterLimit: Double 30 | 31 | /// The dash pattern of the stroke 32 | let dashPattern: [DashElement]? 33 | 34 | private enum CodingKeys : String, CodingKey { 35 | case opacity = "o" 36 | case color = "c" 37 | case width = "w" 38 | case lineCap = "lc" 39 | case lineJoin = "lj" 40 | case miterLimit = "ml" 41 | case dashPattern = "d" 42 | } 43 | 44 | required init(from decoder: Decoder) throws { 45 | let container = try decoder.container(keyedBy: Stroke.CodingKeys.self) 46 | self.opacity = try container.decode(KeyframeGroup.self, forKey: .opacity) 47 | self.color = try container.decode(KeyframeGroup.self, forKey: .color) 48 | self.width = try container.decode(KeyframeGroup.self, forKey: .width) 49 | self.lineCap = try container.decodeIfPresent(LineCap.self, forKey: .lineCap) ?? .round 50 | self.lineJoin = try container.decodeIfPresent(LineJoin.self, forKey: .lineJoin) ?? .round 51 | self.miterLimit = try container.decodeIfPresent(Double.self, forKey: .miterLimit) ?? 4 52 | self.dashPattern = try container.decodeIfPresent([DashElement].self, forKey: .dashPattern) 53 | try super.init(from: decoder) 54 | } 55 | 56 | override func encode(to encoder: Encoder) throws { 57 | try super.encode(to: encoder) 58 | var container = encoder.container(keyedBy: CodingKeys.self) 59 | try container.encode(opacity, forKey: .opacity) 60 | try container.encode(color, forKey: .color) 61 | try container.encode(width, forKey: .width) 62 | try container.encode(lineCap, forKey: .lineCap) 63 | try container.encode(lineJoin, forKey: .lineJoin) 64 | try container.encode(miterLimit, forKey: .miterLimit) 65 | try container.encodeIfPresent(dashPattern, forKey: .dashPattern) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/ShapeItems/Trim.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Trim.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/8/19. 6 | // 7 | 8 | import Foundation 9 | 10 | enum TrimType: Int, Codable { 11 | case simultaneously = 1 12 | case individually = 2 13 | } 14 | /// An item that define an ellipse shape 15 | final class Trim: ShapeItem { 16 | 17 | /// The start of the trim 18 | let start: KeyframeGroup 19 | 20 | /// The end of the trim 21 | let end: KeyframeGroup 22 | 23 | /// The offset of the trim 24 | let offset: KeyframeGroup 25 | 26 | let trimType: TrimType 27 | 28 | private enum CodingKeys : String, CodingKey { 29 | case start = "s" 30 | case end = "e" 31 | case offset = "o" 32 | case trimType = "m" 33 | } 34 | 35 | required init(from decoder: Decoder) throws { 36 | let container = try decoder.container(keyedBy: Trim.CodingKeys.self) 37 | self.start = try container.decode(KeyframeGroup.self, forKey: .start) 38 | self.end = try container.decode(KeyframeGroup.self, forKey: .end) 39 | self.offset = try container.decode(KeyframeGroup.self, forKey: .offset) 40 | self.trimType = try container.decode(TrimType.self, forKey: .trimType) 41 | try super.init(from: decoder) 42 | } 43 | 44 | override func encode(to encoder: Encoder) throws { 45 | try super.encode(to: encoder) 46 | var container = encoder.container(keyedBy: CodingKeys.self) 47 | try container.encode(start, forKey: .start) 48 | try container.encode(end, forKey: .end) 49 | try container.encode(offset, forKey: .offset) 50 | try container.encode(trimType, forKey: .trimType) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Text/Font.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Font.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/9/19. 6 | // 7 | 8 | import Foundation 9 | 10 | final class Font: Codable { 11 | 12 | let name: String 13 | let familyName: String 14 | let style: String 15 | let ascent: Double 16 | 17 | private enum CodingKeys: String, CodingKey { 18 | case name = "fName" 19 | case familyName = "fFamily" 20 | case style = "fStyle" 21 | case ascent = "ascent" 22 | } 23 | 24 | } 25 | 26 | /// A list of fonts 27 | final class FontList: Codable { 28 | 29 | let fonts: [Font] 30 | 31 | enum CodingKeys : String, CodingKey { 32 | case fonts = "list" 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Text/Glyph.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Glyph.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/9/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// A model that holds a vector character 11 | final class Glyph: Codable { 12 | 13 | /// The character 14 | let character: String 15 | 16 | /// The font size of the character 17 | let fontSize: Double 18 | 19 | /// The font family of the character 20 | let fontFamily: String 21 | 22 | /// The Style of the character 23 | let fontStyle: String 24 | 25 | /// The Width of the character 26 | let width: Double 27 | 28 | /// The Shape Data of the Character 29 | let shapes: [ShapeItem] 30 | 31 | private enum CodingKeys: String, CodingKey { 32 | case character = "ch" 33 | case fontSize = "size" 34 | case fontFamily = "fFamily" 35 | case fontStyle = "style" 36 | case width = "w" 37 | case shapeWrapper = "data" 38 | } 39 | 40 | private enum ShapeKey: String, CodingKey { 41 | case shapes = "shapes" 42 | } 43 | 44 | required init(from decoder: Decoder) throws { 45 | let container = try decoder.container(keyedBy: Glyph.CodingKeys.self) 46 | self.character = try container.decode(String.self, forKey: .character) 47 | self.fontSize = try container.decode(Double.self, forKey: .fontSize) 48 | self.fontFamily = try container.decode(String.self, forKey: .fontFamily) 49 | self.fontStyle = try container.decode(String.self, forKey: .fontStyle) 50 | self.width = try container.decode(Double.self, forKey: .width) 51 | if container.contains(.shapeWrapper), 52 | let shapeContainer = try? container.nestedContainer(keyedBy: ShapeKey.self, forKey: .shapeWrapper), 53 | shapeContainer.contains(.shapes) { 54 | self.shapes = try shapeContainer.decode([ShapeItem].self, ofFamily: ShapeType.self, forKey: .shapes) 55 | } else { 56 | self.shapes = [] 57 | } 58 | } 59 | 60 | func encode(to encoder: Encoder) throws { 61 | var container = encoder.container(keyedBy: CodingKeys.self) 62 | 63 | try container.encode(character, forKey: .character) 64 | try container.encode(fontSize, forKey: .fontSize) 65 | try container.encode(fontFamily, forKey: .fontFamily) 66 | try container.encode(fontStyle, forKey: .fontStyle) 67 | try container.encode(width, forKey: .width) 68 | 69 | var shapeContainer = container.nestedContainer(keyedBy: ShapeKey.self, forKey: .shapeWrapper) 70 | try shapeContainer.encode(shapes, forKey: .shapes) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Text/TextAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextAnimator.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/9/19. 6 | // 7 | 8 | import Foundation 9 | 10 | final class TextAnimator: Codable { 11 | 12 | let name: String 13 | 14 | /// Anchor 15 | let anchor: KeyframeGroup? 16 | 17 | /// Position 18 | let position: KeyframeGroup? 19 | 20 | /// Scale 21 | let scale: KeyframeGroup? 22 | 23 | /// Skew 24 | let skew: KeyframeGroup? 25 | 26 | /// Skew Axis 27 | let skewAxis: KeyframeGroup? 28 | 29 | /// Rotation 30 | let rotation: KeyframeGroup? 31 | 32 | /// Opacity 33 | let opacity: KeyframeGroup? 34 | 35 | /// Stroke Color 36 | let strokeColor: KeyframeGroup? 37 | 38 | /// Fill Color 39 | let fillColor: KeyframeGroup? 40 | 41 | /// Stroke Width 42 | let strokeWidth: KeyframeGroup? 43 | 44 | /// Tracking 45 | let tracking: KeyframeGroup? 46 | 47 | private enum CodingKeys: String, CodingKey { 48 | // case textSelector = "s" TODO 49 | case textAnimator = "a" 50 | case name = "nm" 51 | } 52 | 53 | private enum TextSelectorKeys: String, CodingKey { 54 | case start = "s" 55 | case end = "e" 56 | case offset = "o" 57 | } 58 | 59 | private enum TextAnimatorKeys: String, CodingKey { 60 | case fillColor = "fc" 61 | case strokeColor = "sc" 62 | case strokeWidth = "sw" 63 | case tracking = "t" 64 | case anchor = "a" 65 | case position = "p" 66 | case scale = "s" 67 | case skew = "sk" 68 | case skewAxis = "sa" 69 | case rotation = "r" 70 | case opacity = "o" 71 | } 72 | 73 | required init(from decoder: Decoder) throws { 74 | let container = try decoder.container(keyedBy: TextAnimator.CodingKeys.self) 75 | self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" 76 | let animatorContainer = try container.nestedContainer(keyedBy: TextAnimatorKeys.self, forKey: .textAnimator) 77 | self.fillColor = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .fillColor) 78 | self.strokeColor = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .strokeColor) 79 | self.strokeWidth = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .strokeWidth) 80 | self.tracking = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .tracking) 81 | self.anchor = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .anchor) 82 | self.position = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .position) 83 | self.scale = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .scale) 84 | self.skew = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .skew) 85 | self.skewAxis = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .skewAxis) 86 | self.rotation = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .rotation) 87 | self.opacity = try animatorContainer.decodeIfPresent(KeyframeGroup.self, forKey: .opacity) 88 | 89 | } 90 | 91 | func encode(to encoder: Encoder) throws { 92 | var container = encoder.container(keyedBy: CodingKeys.self) 93 | var animatorContainer = container.nestedContainer(keyedBy: TextAnimatorKeys.self, forKey: .textAnimator) 94 | try animatorContainer.encodeIfPresent(fillColor, forKey: .fillColor) 95 | try animatorContainer.encodeIfPresent(strokeColor, forKey: .strokeColor) 96 | try animatorContainer.encodeIfPresent(strokeWidth, forKey: .strokeWidth) 97 | try animatorContainer.encodeIfPresent(tracking, forKey: .tracking) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Model/Text/TextDocument.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextDocument.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/9/19. 6 | // 7 | 8 | import Foundation 9 | 10 | enum TextJustification: Int, Codable { 11 | case left 12 | case right 13 | case center 14 | } 15 | 16 | final class TextDocument: Codable { 17 | 18 | /// The Text 19 | let text: String 20 | 21 | /// The Font size 22 | let fontSize: Double 23 | 24 | /// The Font Family 25 | let fontFamily: String 26 | 27 | /// Justification 28 | let justification: TextJustification 29 | 30 | /// Tracking 31 | let tracking: Int 32 | 33 | /// Line Height 34 | let lineHeight: Double 35 | 36 | /// Baseline 37 | let baseline: Double? 38 | 39 | /// Fill Color data 40 | let fillColorData: Color 41 | 42 | /// Scroke Color data 43 | let strokeColorData: Color? 44 | 45 | /// Stroke Width 46 | let strokeWidth: Double? 47 | 48 | /// Stroke Over Fill 49 | let strokeOverFill: Bool? 50 | 51 | let textFramePosition: Vector3D? 52 | 53 | let textFrameSize: Vector3D? 54 | 55 | private enum CodingKeys : String, CodingKey { 56 | case text = "t" 57 | case fontSize = "s" 58 | case fontFamily = "f" 59 | case justification = "j" 60 | case tracking = "tr" 61 | case lineHeight = "lh" 62 | case baseline = "ls" 63 | case fillColorData = "fc" 64 | case strokeColorData = "sc" 65 | case strokeWidth = "sw" 66 | case strokeOverFill = "of" 67 | case textFramePosition = "ps" 68 | case textFrameSize = "sz" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Extensions/ItemsExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ItemsExtension.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/18/19. 6 | // 7 | 8 | import Foundation 9 | 10 | final class NodeTree { 11 | var rootNode: AnimatorNode? = nil 12 | var transform: ShapeTransform? = nil 13 | var renderContainers: [ShapeContainerLayer] = [] 14 | var paths: [PathOutputNode] = [] 15 | var childrenNodes: [AnimatorNode] = [] 16 | } 17 | 18 | extension Array where Element == ShapeItem { 19 | func initializeNodeTree() -> NodeTree { 20 | 21 | let nodeTree = NodeTree() 22 | 23 | for item in self { 24 | guard item.hidden == false, item.type != .unknown else { continue } 25 | if let fill = item as? Fill { 26 | let node = FillNode(parentNode: nodeTree.rootNode, fill: fill) 27 | nodeTree.rootNode = node 28 | nodeTree.childrenNodes.append(node) 29 | } else if let stroke = item as? Stroke { 30 | let node = StrokeNode(parentNode: nodeTree.rootNode, stroke: stroke) 31 | nodeTree.rootNode = node 32 | nodeTree.childrenNodes.append(node) 33 | } else if let gradientFill = item as? GradientFill { 34 | let node = GradientFillNode(parentNode: nodeTree.rootNode, gradientFill: gradientFill) 35 | nodeTree.rootNode = node 36 | nodeTree.childrenNodes.append(node) 37 | } else if let gradientStroke = item as? GradientStroke { 38 | let node = GradientStrokeNode(parentNode: nodeTree.rootNode, gradientStroke: gradientStroke) 39 | nodeTree.rootNode = node 40 | nodeTree.childrenNodes.append(node) 41 | } else if let ellipse = item as? Ellipse { 42 | let node = EllipseNode(parentNode: nodeTree.rootNode, ellipse: ellipse) 43 | nodeTree.rootNode = node 44 | nodeTree.childrenNodes.append(node) 45 | } else if let rect = item as? Rectangle { 46 | let node = RectangleNode(parentNode: nodeTree.rootNode, rectangle: rect) 47 | nodeTree.rootNode = node 48 | nodeTree.childrenNodes.append(node) 49 | } else if let star = item as? Star { 50 | switch star.starType { 51 | case .none: 52 | continue 53 | case .polygon: 54 | let node = PolygonNode(parentNode: nodeTree.rootNode, star: star) 55 | nodeTree.rootNode = node 56 | nodeTree.childrenNodes.append(node) 57 | case .star: 58 | let node = StarNode(parentNode: nodeTree.rootNode, star: star) 59 | nodeTree.rootNode = node 60 | nodeTree.childrenNodes.append(node) 61 | } 62 | } else if let shape = item as? Shape { 63 | let node = ShapeNode(parentNode: nodeTree.rootNode, shape: shape) 64 | nodeTree.rootNode = node 65 | nodeTree.childrenNodes.append(node) 66 | } else if let trim = item as? Trim { 67 | let node = TrimPathNode(parentNode: nodeTree.rootNode, trim: trim, upstreamPaths: nodeTree.paths) 68 | nodeTree.rootNode = node 69 | nodeTree.childrenNodes.append(node) 70 | } else if let xform = item as? ShapeTransform { 71 | nodeTree.transform = xform 72 | continue 73 | } else if let group = item as? Group { 74 | 75 | let tree = group.items.initializeNodeTree() 76 | let node = GroupNode(name: group.name, parentNode: nodeTree.rootNode, tree: tree) 77 | nodeTree.rootNode = node 78 | nodeTree.childrenNodes.append(node) 79 | /// Now add all child paths to current tree 80 | nodeTree.paths.append(contentsOf: tree.paths) 81 | nodeTree.renderContainers.append(node.container) 82 | } 83 | 84 | if let pathNode = nodeTree.rootNode as? PathNode { 85 | //// Add path container to the node tree 86 | nodeTree.paths.append(pathNode.pathOutput) 87 | } 88 | 89 | if let renderNode = nodeTree.rootNode as? RenderNode { 90 | nodeTree.renderContainers.append(ShapeRenderLayer(renderer: renderNode.renderer)) 91 | } 92 | } 93 | return nodeTree 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/NodeProperties/NodeProperty.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NodeProperty.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /// A node property that holds a reference to a T ValueProvider and a T ValueContainer. 12 | class NodeProperty: AnyNodeProperty { 13 | 14 | var valueType: Any.Type { return T.self } 15 | 16 | var value: T { 17 | return typedContainer.outputValue 18 | } 19 | 20 | var valueContainer: AnyValueContainer { 21 | return typedContainer 22 | } 23 | 24 | var valueProvider: AnyValueProvider 25 | 26 | init(provider: AnyValueProvider) { 27 | self.valueProvider = provider 28 | self.typedContainer = ValueContainer(provider.value(frame: 0) as! T) 29 | self.typedContainer.setNeedsUpdate() 30 | } 31 | 32 | func needsUpdate(frame: CGFloat) -> Bool { 33 | return valueContainer.needsUpdate || valueProvider.hasUpdate(frame: frame) 34 | } 35 | 36 | func setProvider(provider: AnyValueProvider) { 37 | guard provider.valueType == valueType else { return } 38 | self.valueProvider = provider 39 | valueContainer.setNeedsUpdate() 40 | } 41 | 42 | func update(frame: CGFloat) { 43 | typedContainer.setValue(valueProvider.value(frame: frame), forFrame: frame) 44 | } 45 | 46 | fileprivate var typedContainer: ValueContainer 47 | } 48 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/NodeProperties/Protocols/AnyNodeProperty.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnyNodeProperty.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | /// A property of a node. The node property holds a provider and a container 11 | protocol AnyNodeProperty { 12 | 13 | /// Returns true if the property needs to recompute its stored value 14 | func needsUpdate(frame: CGFloat) -> Bool 15 | 16 | /// Updates the property for the frame 17 | func update(frame: CGFloat) 18 | 19 | /// The stored value container for the property 20 | var valueContainer: AnyValueContainer { get } 21 | 22 | /// The value provider for the property 23 | var valueProvider: AnyValueProvider { get } 24 | 25 | /// The Type of the value provider 26 | var valueType: Any.Type { get } 27 | 28 | /// Sets the value provider for the property. 29 | func setProvider(provider: AnyValueProvider) 30 | } 31 | 32 | extension AnyNodeProperty { 33 | 34 | /// Returns the most recently computed value for the keypath, returns nil if property wasn't found 35 | func getValueOfType() -> T? { 36 | return valueContainer.value as? T 37 | } 38 | 39 | /// Returns the most recently computed value for the keypath, returns nil if property wasn't found 40 | func getValue() -> Any? { 41 | return valueContainer.value 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/NodeProperties/Protocols/AnyValueContainer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnyValueContainer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /// The container for the value of a property. 12 | protocol AnyValueContainer: class { 13 | 14 | /// The stored value of the container 15 | var value: Any { get } 16 | 17 | /// Notifies the provider that it should update its container 18 | func setNeedsUpdate() 19 | 20 | /// When true the container needs to have its value updated by its provider 21 | var needsUpdate: Bool { get } 22 | 23 | /// The frame time of the last provided update 24 | var lastUpdateFrame: CGFloat { get } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/NodeProperties/Protocols/KeypathSearchable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KeypathSettable.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | /// Protocol that provides keypath search functionality. Returns all node properties associated with a keypath. 12 | protocol KeypathSearchable { 13 | 14 | /// The name of the Keypath 15 | var keypathName: String { get } 16 | 17 | /// A list of properties belonging to the keypath. 18 | var keypathProperties: [String : AnyNodeProperty] { get } 19 | 20 | /// Children Keypaths 21 | var childKeypaths: [KeypathSearchable] { get } 22 | 23 | var keypathLayer: CALayer? { get } 24 | } 25 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NodePropertyMap.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/21/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | protocol NodePropertyMap { 12 | var properties: [AnyNodeProperty] { get } 13 | } 14 | 15 | extension NodePropertyMap { 16 | 17 | var childKeypaths: [KeypathSearchable] { 18 | return [] 19 | } 20 | 21 | var keypathLayer: CALayer? { 22 | return nil 23 | } 24 | 25 | /// Checks if the node's local contents need to be rebuilt. 26 | func needsLocalUpdate(frame: CGFloat) -> Bool { 27 | for property in properties { 28 | if property.needsUpdate(frame: frame) { 29 | return true 30 | } 31 | } 32 | return false 33 | } 34 | 35 | /// Rebuilds only the local nodes that have an update for the frame 36 | func updateNodeProperties(frame: CGFloat) { 37 | properties.forEach { (property) in 38 | property.update(frame: frame) 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/NodeProperties/ValueContainer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ValueContainer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /// A container for a node value that is Typed to T. 12 | class ValueContainer: AnyValueContainer { 13 | 14 | private(set) var lastUpdateFrame: CGFloat = CGFloat.infinity 15 | 16 | func setValue(_ value: Any, forFrame: CGFloat) { 17 | if let typedValue = value as? T { 18 | needsUpdate = false 19 | lastUpdateFrame = forFrame 20 | outputValue = typedValue 21 | } 22 | } 23 | 24 | func setNeedsUpdate() { 25 | needsUpdate = true 26 | } 27 | 28 | var value: Any { 29 | return outputValue as Any 30 | } 31 | 32 | var outputValue: T { 33 | didSet { 34 | needsUpdate = false 35 | } 36 | } 37 | 38 | init(_ value: T) { 39 | self.outputValue = value 40 | } 41 | 42 | fileprivate(set) var needsUpdate: Bool = true 43 | } 44 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/NodeProperties/ValueProviders/GroupInterpolator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KeyframeGroupInterpolator.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/22/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /// A value provider that produces an array of values from an array of Keyframe Interpolators 12 | final class GroupInterpolator: AnyValueProvider where ValueType: Interpolatable { 13 | var valueType: Any.Type { 14 | return [ValueType].self 15 | } 16 | 17 | func hasUpdate(frame: CGFloat) -> Bool { 18 | let updated = keyframeInterpolators.first(where: {$0.hasUpdate(frame: frame)}) 19 | return updated != nil 20 | } 21 | 22 | func value(frame: CGFloat) -> Any { 23 | let output = keyframeInterpolators.map({$0.value(frame: frame) as! ValueType}) 24 | return output 25 | } 26 | 27 | /// Initialize with an array of array of keyframes. 28 | init(keyframeGroups: ContiguousArray>>) { 29 | self.keyframeInterpolators = ContiguousArray(keyframeGroups.map({KeyframeInterpolator(keyframes: $0)})) 30 | } 31 | let keyframeInterpolators: ContiguousArray> 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/NodeProperties/ValueProviders/SingleValueProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SingleValueProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | /// Returns a value for every frame. 12 | final class SingleValueProvider: AnyValueProvider { 13 | 14 | var value: ValueType { 15 | didSet { 16 | hasUpdate = true 17 | } 18 | } 19 | 20 | init(_ value: ValueType) { 21 | self.value = value 22 | } 23 | 24 | var valueType: Any.Type { 25 | return ValueType.self 26 | } 27 | 28 | func hasUpdate(frame: CGFloat) -> Bool { 29 | return hasUpdate 30 | } 31 | 32 | func value(frame: CGFloat) -> Any { 33 | hasUpdate = false 34 | return value 35 | } 36 | 37 | private var hasUpdate: Bool = true 38 | } 39 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransformNodeOutput.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | import QuartzCore 11 | 12 | class GroupOutputNode: NodeOutput { 13 | 14 | init(parent: NodeOutput?, rootNode: NodeOutput?) { 15 | self.parent = parent 16 | self.rootNode = rootNode 17 | } 18 | 19 | let parent: NodeOutput? 20 | let rootNode: NodeOutput? 21 | var isEnabled: Bool = true 22 | 23 | private(set) var outputPath: CGPath? = nil 24 | private(set) var transform: CATransform3D = CATransform3DIdentity 25 | 26 | func setTransform(_ xform: CATransform3D, forFrame: CGFloat) { 27 | transform = xform 28 | outputPath = nil 29 | } 30 | 31 | func hasOutputUpdates(_ forFrame: CGFloat) -> Bool { 32 | guard isEnabled else { 33 | let upstreamUpdates = parent?.hasOutputUpdates(forFrame) ?? false 34 | outputPath = parent?.outputPath 35 | return upstreamUpdates 36 | } 37 | 38 | let upstreamUpdates = parent?.hasOutputUpdates(forFrame) ?? false 39 | if upstreamUpdates { 40 | outputPath = nil 41 | } 42 | let rootUpdates = rootNode?.hasOutputUpdates(forFrame) ?? false 43 | if rootUpdates { 44 | outputPath = nil 45 | } 46 | 47 | var localUpdates: Bool = false 48 | if outputPath == nil { 49 | localUpdates = true 50 | 51 | let newPath = CGMutablePath() 52 | if let parentNode = parent, let parentPath = parentNode.outputPath { 53 | /// First add parent path. 54 | newPath.addPath(parentPath) 55 | } 56 | var xform = CATransform3DGetAffineTransform(transform) 57 | if let rootNode = rootNode, 58 | let rootPath = rootNode.outputPath, 59 | let xformedPath = rootPath.copy(using: &xform) { 60 | /// Now add root path. Note root path is transformed. 61 | newPath.addPath(xformedPath) 62 | } 63 | 64 | outputPath = newPath 65 | } 66 | 67 | return upstreamUpdates || localUpdates 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PassThroughOutputNode.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | class PassThroughOutputNode: NodeOutput { 12 | 13 | init(parent: NodeOutput?) { 14 | self.parent = parent 15 | } 16 | 17 | let parent: NodeOutput? 18 | 19 | var hasUpdate: Bool = false 20 | var isEnabled: Bool = true 21 | 22 | func hasOutputUpdates(_ forFrame: CGFloat) -> Bool { 23 | /// Changes to this node do not affect downstream nodes. 24 | let parentUpdate = parent?.hasOutputUpdates(forFrame) ?? false 25 | /// Changes to upstream nodes do, however, affect this nodes state. 26 | hasUpdate = hasUpdate || parentUpdate 27 | return parentUpdate 28 | } 29 | 30 | var outputPath: CGPath? { 31 | if let parent = parent { 32 | return parent.outputPath 33 | } 34 | return nil 35 | } 36 | 37 | func hasRenderUpdates(_ forFrame: CGFloat) -> Bool { 38 | /// Return true if there are upstream updates or if this node has updates 39 | let upstreamUpdates = parent?.hasOutputUpdates(forFrame) ?? false 40 | hasUpdate = hasUpdate || upstreamUpdates 41 | return hasUpdate 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/OutputNodes/PathOutputNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PathNodeOutput.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /// A node that has an output of a BezierPath 12 | class PathOutputNode: NodeOutput { 13 | 14 | init(parent: NodeOutput?) { 15 | self.parent = parent 16 | } 17 | 18 | let parent: NodeOutput? 19 | 20 | fileprivate(set) var outputPath: CGPath? = nil 21 | 22 | var lastUpdateFrame: CGFloat? = nil 23 | var lastPathBuildFrame: CGFloat? = nil 24 | var isEnabled: Bool = true 25 | 26 | func hasOutputUpdates(_ forFrame: CGFloat) -> Bool { 27 | guard isEnabled else { 28 | let upstreamUpdates = parent?.hasOutputUpdates(forFrame) ?? false 29 | outputPath = parent?.outputPath 30 | return upstreamUpdates 31 | } 32 | 33 | /// Ask if parent was updated 34 | let upstreamUpdates = parent?.hasOutputUpdates(forFrame) ?? false 35 | 36 | /// If parent was updated and the path hasn't been built for this frame, clear the path. 37 | if upstreamUpdates && lastPathBuildFrame != forFrame { 38 | outputPath = nil 39 | } 40 | 41 | if outputPath == nil { 42 | /// If the path is clear, build the new path. 43 | lastPathBuildFrame = forFrame 44 | let newPath = CGMutablePath() 45 | if let parentNode = parent, let parentPath = parentNode.outputPath { 46 | newPath.addPath(parentPath) 47 | } 48 | for path in pathObjects { 49 | for subPath in path.paths { 50 | newPath.addPath(subPath.cgPath()) 51 | } 52 | } 53 | outputPath = newPath 54 | } 55 | 56 | /// Return true if there were upstream updates or if this node was updated. 57 | return upstreamUpdates || (lastUpdateFrame == forFrame) 58 | } 59 | 60 | // MARK: Internal 61 | 62 | fileprivate(set) var totalLength: CGFloat = 0 63 | fileprivate(set) var pathObjects: [CompoundBezierPath] = [] 64 | 65 | @discardableResult func removePaths(updateFrame: CGFloat?) -> [CompoundBezierPath] { 66 | lastUpdateFrame = updateFrame 67 | let returnPaths = pathObjects 68 | outputPath = nil 69 | totalLength = 0 70 | pathObjects = [] 71 | return returnPaths 72 | } 73 | 74 | func setPath(_ path: BezierPath, updateFrame: CGFloat) { 75 | lastUpdateFrame = updateFrame 76 | outputPath = nil 77 | totalLength = path.length 78 | pathObjects = [CompoundBezierPath(path: path)] 79 | } 80 | 81 | func appendPath(_ path: CompoundBezierPath, updateFrame: CGFloat) { 82 | lastUpdateFrame = updateFrame 83 | outputPath = nil 84 | totalLength = totalLength + path.length 85 | pathObjects.append(path) 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FillRenderer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | import CoreGraphics 11 | 12 | extension FillRule { 13 | var cgFillRule: CGPathFillRule { 14 | switch self { 15 | case .evenOdd: 16 | return .evenOdd 17 | default: 18 | return .winding 19 | } 20 | } 21 | 22 | var caFillRule: CAShapeLayerFillRule { 23 | switch self { 24 | case .evenOdd: 25 | return CAShapeLayerFillRule.evenOdd 26 | default: 27 | return CAShapeLayerFillRule.nonZero 28 | } 29 | } 30 | } 31 | 32 | /// A rendered for a Path Fill 33 | final class FillRenderer: PassThroughOutputNode, Renderable { 34 | 35 | let shouldRenderInContext: Bool = false 36 | 37 | func updateShapeLayer(layer: CAShapeLayer) { 38 | layer.fillColor = color 39 | layer.opacity = Float(opacity) 40 | layer.fillRule = fillRule.caFillRule 41 | hasUpdate = false 42 | } 43 | 44 | var color: CGColor? { 45 | didSet { 46 | hasUpdate = true 47 | } 48 | } 49 | 50 | var opacity: CGFloat = 0 { 51 | didSet { 52 | hasUpdate = true 53 | } 54 | } 55 | 56 | var fillRule: FillRule = .none { 57 | didSet { 58 | hasUpdate = true 59 | } 60 | } 61 | 62 | func render(_ inContext: CGContext) { 63 | guard inContext.path != nil && inContext.path!.isEmpty == false else { 64 | return 65 | } 66 | guard let color = color else { return } 67 | hasUpdate = false 68 | inContext.setAlpha(opacity * 0.01) 69 | inContext.setFillColor(color) 70 | inContext.fillPath(using: fillRule.cgFillRule) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientStrokeRenderer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GradientStrokeRenderer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | // MARK: - Renderer 12 | 13 | final class GradientStrokeRenderer: PassThroughOutputNode, Renderable { 14 | 15 | override func hasOutputUpdates(_ forFrame: CGFloat) -> Bool { 16 | let updates = super.hasOutputUpdates(forFrame) 17 | return updates || strokeRender.hasUpdate || gradientRender.hasUpdate 18 | } 19 | 20 | var shouldRenderInContext: Bool = true 21 | 22 | func updateShapeLayer(layer: CAShapeLayer) { 23 | /// Not Applicable 24 | } 25 | 26 | let strokeRender: StrokeRenderer 27 | let gradientRender: GradientFillRenderer 28 | 29 | override init(parent: NodeOutput?) { 30 | self.strokeRender = StrokeRenderer(parent: nil) 31 | self.gradientRender = GradientFillRenderer(parent: nil) 32 | self.strokeRender.color = CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [1, 1, 1, 1]) 33 | super.init(parent: parent) 34 | } 35 | 36 | func render(_ inContext: CGContext) { 37 | guard inContext.path != nil && inContext.path!.isEmpty == false else { 38 | return 39 | } 40 | 41 | strokeRender.hasUpdate = false 42 | hasUpdate = false 43 | gradientRender.hasUpdate = false 44 | 45 | strokeRender.setupForStroke(inContext) 46 | 47 | inContext.replacePathWithStrokedPath() 48 | 49 | /// Now draw the gradient. 50 | gradientRender.render(inContext) 51 | 52 | } 53 | 54 | func renderBoundsFor(_ boundingBox: CGRect) -> CGRect { 55 | return strokeRender.renderBoundsFor(boundingBox) 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StrokeRenderer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | extension LineJoin { 12 | var cgLineJoin: CGLineJoin { 13 | switch self { 14 | case .bevel: 15 | return .bevel 16 | case .none: 17 | return .miter 18 | case .miter: 19 | return .miter 20 | case .round: 21 | return .round 22 | } 23 | } 24 | 25 | var caLineJoin: CAShapeLayerLineJoin { 26 | switch self { 27 | case .none: 28 | return CAShapeLayerLineJoin.miter 29 | case .miter: 30 | return CAShapeLayerLineJoin.miter 31 | case .round: 32 | return CAShapeLayerLineJoin.round 33 | case .bevel: 34 | return CAShapeLayerLineJoin.bevel 35 | } 36 | } 37 | } 38 | 39 | extension LineCap { 40 | var cgLineCap: CGLineCap { 41 | switch self { 42 | case .none: 43 | return .butt 44 | case .butt: 45 | return .butt 46 | case .round: 47 | return .round 48 | case .square: 49 | return .square 50 | } 51 | } 52 | 53 | var caLineCap: CAShapeLayerLineCap { 54 | switch self { 55 | case .none: 56 | return CAShapeLayerLineCap.butt 57 | case .butt: 58 | return CAShapeLayerLineCap.butt 59 | case .round: 60 | return CAShapeLayerLineCap.round 61 | case .square: 62 | return CAShapeLayerLineCap.square 63 | } 64 | } 65 | } 66 | 67 | // MARK: - Renderer 68 | 69 | /// A rendered that renders a stroke on a path. 70 | final class StrokeRenderer: PassThroughOutputNode, Renderable { 71 | 72 | var shouldRenderInContext: Bool = false 73 | 74 | var color: CGColor? { 75 | didSet { 76 | hasUpdate = true 77 | } 78 | } 79 | 80 | var opacity: CGFloat = 0 { 81 | didSet { 82 | hasUpdate = true 83 | } 84 | } 85 | 86 | var width: CGFloat = 0 { 87 | didSet { 88 | hasUpdate = true 89 | } 90 | } 91 | 92 | var miterLimit: CGFloat = 0 { 93 | didSet { 94 | hasUpdate = true 95 | } 96 | } 97 | 98 | var lineCap: LineCap = .none { 99 | didSet { 100 | hasUpdate = true 101 | } 102 | } 103 | 104 | var lineJoin: LineJoin = .none { 105 | didSet { 106 | hasUpdate = true 107 | } 108 | } 109 | 110 | var dashPhase: CGFloat? { 111 | didSet { 112 | hasUpdate = true 113 | } 114 | } 115 | 116 | var dashLengths: [CGFloat]? { 117 | didSet { 118 | hasUpdate = true 119 | } 120 | } 121 | 122 | func renderBoundsFor(_ boundingBox: CGRect) -> CGRect { 123 | return boundingBox.insetBy(dx: -width, dy: -width) 124 | } 125 | 126 | func setupForStroke(_ inContext: CGContext) { 127 | inContext.setLineWidth(width) 128 | inContext.setMiterLimit(miterLimit) 129 | inContext.setLineCap(lineCap.cgLineCap) 130 | inContext.setLineJoin(lineJoin.cgLineJoin) 131 | if let dashPhase = dashPhase, let lengths = dashLengths { 132 | inContext.setLineDash(phase: dashPhase, lengths: lengths) 133 | } else { 134 | inContext.setLineDash(phase: 0, lengths: []) 135 | } 136 | } 137 | 138 | func render(_ inContext: CGContext) { 139 | guard inContext.path != nil && inContext.path!.isEmpty == false else { 140 | return 141 | } 142 | guard let color = color else { return } 143 | hasUpdate = false 144 | setupForStroke(inContext) 145 | inContext.setAlpha(opacity) 146 | inContext.setStrokeColor(color) 147 | inContext.strokePath() 148 | } 149 | 150 | func updateShapeLayer(layer: CAShapeLayer) { 151 | layer.strokeColor = color 152 | layer.opacity = Float(opacity) 153 | layer.lineWidth = width 154 | layer.lineJoin = lineJoin.caLineJoin 155 | layer.lineCap = lineCap.caLineCap 156 | layer.lineDashPhase = dashPhase ?? 0 157 | layer.fillColor = nil 158 | if let dashPattern = dashLengths { 159 | layer.lineDashPattern = dashPattern.map({ NSNumber(value: Double($0)) }) 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EllipseNode.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/17/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | final class EllipseNodeProperties: NodePropertyMap, KeypathSearchable { 12 | 13 | var keypathName: String 14 | 15 | init(ellipse: Ellipse) { 16 | self.keypathName = ellipse.name 17 | self.direction = ellipse.direction 18 | self.position = NodeProperty(provider: KeyframeInterpolator(keyframes: ellipse.position.keyframes)) 19 | self.size = NodeProperty(provider: KeyframeInterpolator(keyframes: ellipse.size.keyframes)) 20 | self.keypathProperties = [ 21 | "Position" : position, 22 | "Size" : size 23 | ] 24 | self.properties = Array(keypathProperties.values) 25 | } 26 | 27 | let direction: PathDirection 28 | let position: NodeProperty 29 | let size: NodeProperty 30 | 31 | let keypathProperties: [String : AnyNodeProperty] 32 | let properties: [AnyNodeProperty] 33 | } 34 | 35 | final class EllipseNode: AnimatorNode, PathNode { 36 | 37 | let pathOutput: PathOutputNode 38 | 39 | let properties: EllipseNodeProperties 40 | 41 | init(parentNode: AnimatorNode?, ellipse: Ellipse) { 42 | self.pathOutput = PathOutputNode(parent: parentNode?.outputNode) 43 | self.properties = EllipseNodeProperties(ellipse: ellipse) 44 | self.parentNode = parentNode 45 | } 46 | 47 | // MARK: Animator Node 48 | 49 | var propertyMap: NodePropertyMap & KeypathSearchable { 50 | return properties 51 | } 52 | 53 | let parentNode: AnimatorNode? 54 | var hasLocalUpdates: Bool = false 55 | var hasUpstreamUpdates: Bool = false 56 | var lastUpdateFrame: CGFloat? = nil 57 | var isEnabled: Bool = true { 58 | didSet{ 59 | self.pathOutput.isEnabled = self.isEnabled 60 | } 61 | } 62 | 63 | func rebuildOutputs(frame: CGFloat) { 64 | let ellipseSize = properties.size.value.sizeValue 65 | let center = properties.position.value.pointValue 66 | 67 | // Unfortunately we HAVE to manually build out the ellipse. 68 | // Every Apple method constructs an ellipse from the 3 o-clock position 69 | // After effects constructs from the Noon position. 70 | // After effects does clockwise, but also has a flag for reversed. 71 | 72 | var half = ellipseSize * 0.5 73 | if properties.direction == .counterClockwise { 74 | half.width = half.width * -1 75 | } 76 | 77 | 78 | let q1 = CGPoint(x: center.x, y: center.y - half.height) 79 | let q2 = CGPoint(x: center.x + half.width, y: center.y) 80 | let q3 = CGPoint(x: center.x, y: center.y + half.height) 81 | let q4 = CGPoint(x: center.x - half.width, y: center.y) 82 | 83 | let cp = half * EllipseNode.ControlPointConstant 84 | 85 | var path = BezierPath(startPoint: CurveVertex(point: q1, 86 | inTangentRelative: CGPoint(x: -cp.width, y: 0), 87 | outTangentRelative: CGPoint(x: cp.width, y: 0))) 88 | path.addVertex(CurveVertex(point: q2, 89 | inTangentRelative: CGPoint(x: 0, y: -cp.height), 90 | outTangentRelative: CGPoint(x: 0, y: cp.height))) 91 | 92 | path.addVertex(CurveVertex(point: q3, 93 | inTangentRelative: CGPoint(x: cp.width, y: 0), 94 | outTangentRelative: CGPoint(x: -cp.width, y: 0))) 95 | 96 | path.addVertex(CurveVertex(point: q4, 97 | inTangentRelative: CGPoint(x: 0, y: cp.height), 98 | outTangentRelative: CGPoint(x: 0, y: -cp.height))) 99 | 100 | path.addVertex(CurveVertex(point: q1, 101 | inTangentRelative: CGPoint(x: -cp.width, y: 0), 102 | outTangentRelative: CGPoint(x: cp.width, y: 0))) 103 | path.close() 104 | pathOutput.setPath(path, updateFrame: frame) 105 | } 106 | 107 | static let ControlPointConstant: CGFloat = 0.55228 108 | 109 | } 110 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/PathNodes/ShapeNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PathNode.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/16/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | final class ShapeNodeProperties: NodePropertyMap, KeypathSearchable { 12 | 13 | var keypathName: String 14 | 15 | init(shape: Shape) { 16 | self.keypathName = shape.name 17 | self.path = NodeProperty(provider: KeyframeInterpolator(keyframes: shape.path.keyframes)) 18 | self.keypathProperties = [ 19 | "Path" : path 20 | ] 21 | self.properties = Array(keypathProperties.values) 22 | } 23 | 24 | let path: NodeProperty 25 | let keypathProperties: [String : AnyNodeProperty] 26 | let properties: [AnyNodeProperty] 27 | 28 | } 29 | 30 | final class ShapeNode: AnimatorNode, PathNode { 31 | 32 | let properties: ShapeNodeProperties 33 | 34 | let pathOutput: PathOutputNode 35 | 36 | init(parentNode: AnimatorNode?, shape: Shape) { 37 | self.pathOutput = PathOutputNode(parent: parentNode?.outputNode) 38 | self.properties = ShapeNodeProperties(shape: shape) 39 | self.parentNode = parentNode 40 | } 41 | 42 | // MARK: Animator Node 43 | var propertyMap: NodePropertyMap & KeypathSearchable { 44 | return properties 45 | } 46 | 47 | let parentNode: AnimatorNode? 48 | var hasLocalUpdates: Bool = false 49 | var hasUpstreamUpdates: Bool = false 50 | var lastUpdateFrame: CGFloat? = nil 51 | var isEnabled: Bool = true { 52 | didSet{ 53 | self.pathOutput.isEnabled = self.isEnabled 54 | } 55 | } 56 | 57 | func rebuildOutputs(frame: CGFloat) { 58 | pathOutput.setPath(properties.path.value, updateFrame: frame) 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FillNode.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/17/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | final class FillNodeProperties: NodePropertyMap, KeypathSearchable { 12 | 13 | var keypathName: String 14 | 15 | init(fill: Fill) { 16 | self.keypathName = fill.name 17 | self.color = NodeProperty(provider: KeyframeInterpolator(keyframes: fill.color.keyframes)) 18 | self.opacity = NodeProperty(provider: KeyframeInterpolator(keyframes: fill.opacity.keyframes)) 19 | self.type = fill.fillRule 20 | self.keypathProperties = [ 21 | "Opacity" : opacity, 22 | "Color" : color 23 | ] 24 | self.properties = Array(keypathProperties.values) 25 | } 26 | 27 | let opacity: NodeProperty 28 | let color: NodeProperty 29 | let type: FillRule 30 | 31 | let keypathProperties: [String : AnyNodeProperty] 32 | let properties: [AnyNodeProperty] 33 | 34 | } 35 | 36 | final class FillNode: AnimatorNode, RenderNode { 37 | 38 | let fillRender: FillRenderer 39 | var renderer: NodeOutput & Renderable { 40 | return fillRender 41 | } 42 | 43 | let fillProperties: FillNodeProperties 44 | 45 | init(parentNode: AnimatorNode?, fill: Fill) { 46 | self.fillRender = FillRenderer(parent: parentNode?.outputNode) 47 | self.fillProperties = FillNodeProperties(fill: fill) 48 | self.parentNode = parentNode 49 | } 50 | 51 | // MARK: Animator Node Protocol 52 | 53 | var propertyMap: NodePropertyMap & KeypathSearchable { 54 | return fillProperties 55 | } 56 | 57 | let parentNode: AnimatorNode? 58 | var hasLocalUpdates: Bool = false 59 | var hasUpstreamUpdates: Bool = false 60 | var lastUpdateFrame: CGFloat? = nil 61 | var isEnabled: Bool = true { 62 | didSet { 63 | fillRender.isEnabled = isEnabled 64 | } 65 | } 66 | 67 | func localUpdatesPermeateDownstream() -> Bool { 68 | return false 69 | } 70 | 71 | func rebuildOutputs(frame: CGFloat) { 72 | fillRender.color = fillProperties.color.value.cgColorValue 73 | fillRender.opacity = fillProperties.opacity.value.cgFloatValue * 0.01 74 | fillRender.fillRule = fillProperties.type 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GradientFillNode.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/22/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | final class GradientFillProperties: NodePropertyMap, KeypathSearchable { 12 | 13 | init(gradientfill: GradientFill) { 14 | self.keypathName = gradientfill.name 15 | self.opacity = NodeProperty(provider: KeyframeInterpolator(keyframes: gradientfill.opacity.keyframes)) 16 | self.startPoint = NodeProperty(provider: KeyframeInterpolator(keyframes: gradientfill.startPoint.keyframes)) 17 | self.endPoint = NodeProperty(provider: KeyframeInterpolator(keyframes: gradientfill.endPoint.keyframes)) 18 | self.colors = NodeProperty(provider: KeyframeInterpolator(keyframes: gradientfill.colors.keyframes)) 19 | self.gradientType = gradientfill.gradientType 20 | self.numberOfColors = gradientfill.numberOfColors 21 | self.keypathProperties = [ 22 | "Opacity" : opacity, 23 | "Start Point" : startPoint, 24 | "End Point" : endPoint, 25 | "Colors" : colors 26 | ] 27 | self.properties = Array(keypathProperties.values) 28 | } 29 | 30 | var keypathName: String 31 | 32 | let opacity: NodeProperty 33 | let startPoint: NodeProperty 34 | let endPoint: NodeProperty 35 | let colors: NodeProperty<[Double]> 36 | 37 | let gradientType: GradientType 38 | let numberOfColors: Int 39 | 40 | 41 | let keypathProperties: [String : AnyNodeProperty] 42 | let properties: [AnyNodeProperty] 43 | 44 | } 45 | 46 | final class GradientFillNode: AnimatorNode, RenderNode { 47 | 48 | let fillRender: GradientFillRenderer 49 | 50 | var renderer: NodeOutput & Renderable { 51 | return fillRender 52 | } 53 | 54 | let fillProperties: GradientFillProperties 55 | 56 | init(parentNode: AnimatorNode?, gradientFill: GradientFill) { 57 | self.fillRender = GradientFillRenderer(parent: parentNode?.outputNode) 58 | self.fillProperties = GradientFillProperties(gradientfill: gradientFill) 59 | self.parentNode = parentNode 60 | } 61 | 62 | // MARK: Animator Node Protocol 63 | 64 | var propertyMap: NodePropertyMap & KeypathSearchable { 65 | return fillProperties 66 | } 67 | 68 | let parentNode: AnimatorNode? 69 | var hasLocalUpdates: Bool = false 70 | var hasUpstreamUpdates: Bool = false 71 | var lastUpdateFrame: CGFloat? = nil 72 | var isEnabled: Bool = true { 73 | didSet { 74 | fillRender.isEnabled = isEnabled 75 | } 76 | } 77 | 78 | func localUpdatesPermeateDownstream() -> Bool { 79 | return false 80 | } 81 | 82 | func rebuildOutputs(frame: CGFloat) { 83 | fillRender.start = fillProperties.startPoint.value.pointValue 84 | fillRender.end = fillProperties.endPoint.value.pointValue 85 | fillRender.opacity = fillProperties.opacity.value.cgFloatValue * 0.01 86 | fillRender.colors = fillProperties.colors.value.map { CGFloat($0) } 87 | fillRender.type = fillProperties.gradientType 88 | fillRender.numberOfColors = fillProperties.numberOfColors 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StrokeNode.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/22/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | // MARK: - Properties 11 | 12 | final class StrokeNodeProperties: NodePropertyMap, KeypathSearchable { 13 | 14 | init(stroke: Stroke) { 15 | self.keypathName = stroke.name 16 | self.color = NodeProperty(provider: KeyframeInterpolator(keyframes: stroke.color.keyframes)) 17 | self.opacity = NodeProperty(provider: KeyframeInterpolator(keyframes: stroke.opacity.keyframes)) 18 | self.width = NodeProperty(provider: KeyframeInterpolator(keyframes: stroke.width.keyframes)) 19 | self.miterLimit = CGFloat(stroke.miterLimit) 20 | self.lineCap = stroke.lineCap 21 | self.lineJoin = stroke.lineJoin 22 | 23 | if let dashes = stroke.dashPattern { 24 | var dashPatterns = ContiguousArray>>() 25 | var dashPhase = ContiguousArray>() 26 | for dash in dashes { 27 | if dash.type == .offset { 28 | dashPhase = dash.value.keyframes 29 | } else { 30 | dashPatterns.append(dash.value.keyframes) 31 | } 32 | } 33 | self.dashPattern = NodeProperty(provider: GroupInterpolator(keyframeGroups: dashPatterns)) 34 | if dashPhase.count == 0 { 35 | self.dashPhase = NodeProperty(provider: SingleValueProvider(Vector1D(0))) 36 | } else { 37 | self.dashPhase = NodeProperty(provider: KeyframeInterpolator(keyframes: dashPhase)) 38 | } 39 | } else { 40 | self.dashPattern = NodeProperty(provider: SingleValueProvider([Vector1D]())) 41 | self.dashPhase = NodeProperty(provider: SingleValueProvider(Vector1D(0))) 42 | } 43 | self.keypathProperties = [ 44 | "Opacity" : opacity, 45 | "Color" : color, 46 | "Stroke Width" : width, 47 | "Dashes" : dashPattern, 48 | "Dash Phase" : dashPhase 49 | ] 50 | self.properties = Array(keypathProperties.values) 51 | } 52 | 53 | let keypathName: String 54 | let keypathProperties: [String : AnyNodeProperty] 55 | let properties: [AnyNodeProperty] 56 | 57 | let opacity: NodeProperty 58 | let color: NodeProperty 59 | let width: NodeProperty 60 | 61 | let dashPattern: NodeProperty<[Vector1D]> 62 | let dashPhase: NodeProperty 63 | 64 | let lineCap: LineCap 65 | let lineJoin: LineJoin 66 | let miterLimit: CGFloat 67 | 68 | } 69 | 70 | // MARK: - Node 71 | 72 | /// Node that manages stroking a path 73 | final class StrokeNode: AnimatorNode, RenderNode { 74 | 75 | let strokeRender: StrokeRenderer 76 | var renderer: NodeOutput & Renderable { 77 | return strokeRender 78 | } 79 | 80 | let strokeProperties: StrokeNodeProperties 81 | 82 | init(parentNode: AnimatorNode?, stroke: Stroke) { 83 | self.strokeRender = StrokeRenderer(parent: parentNode?.outputNode) 84 | self.strokeProperties = StrokeNodeProperties(stroke: stroke) 85 | self.parentNode = parentNode 86 | } 87 | 88 | // MARK: Animator Node Protocol 89 | 90 | var propertyMap: NodePropertyMap & KeypathSearchable { 91 | return strokeProperties 92 | } 93 | 94 | let parentNode: AnimatorNode? 95 | var hasLocalUpdates: Bool = false 96 | var hasUpstreamUpdates: Bool = false 97 | var lastUpdateFrame: CGFloat? = nil 98 | var isEnabled: Bool = true { 99 | didSet { 100 | strokeRender.isEnabled = isEnabled 101 | } 102 | } 103 | 104 | func localUpdatesPermeateDownstream() -> Bool { 105 | return false 106 | } 107 | 108 | func rebuildOutputs(frame: CGFloat) { 109 | strokeRender.color = strokeProperties.color.value.cgColorValue 110 | strokeRender.opacity = strokeProperties.opacity.value.cgFloatValue * 0.01 111 | strokeRender.width = strokeProperties.width.value.cgFloatValue 112 | strokeRender.miterLimit = strokeProperties.miterLimit 113 | strokeRender.lineCap = strokeProperties.lineCap 114 | strokeRender.lineJoin = strokeProperties.lineJoin 115 | 116 | /// Get dash lengths 117 | let dashLengths = strokeProperties.dashPattern.value.map { $0.cgFloatValue } 118 | if dashLengths.count > 0 { 119 | strokeRender.dashPhase = strokeProperties.dashPhase.value.cgFloatValue 120 | strokeRender.dashLengths = dashLengths 121 | } else { 122 | strokeRender.dashLengths = nil 123 | strokeRender.dashPhase = nil 124 | } 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Protocols/PathNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PathNode.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/17/19. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol PathNode { 11 | var pathOutput: PathOutputNode { get } 12 | } 13 | 14 | extension PathNode where Self: AnimatorNode { 15 | 16 | var outputNode: NodeOutput { 17 | return pathOutput 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/Protocols/RenderNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RenderNode.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/17/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | import QuartzCore 11 | 12 | /// A protocol that defines a node that holds render instructions 13 | protocol RenderNode { 14 | var renderer: Renderable & NodeOutput { get } 15 | } 16 | 17 | /// A protocol that defines anything with render instructions 18 | protocol Renderable { 19 | 20 | /// The last frame in which this node was updated. 21 | var hasUpdate: Bool { get } 22 | 23 | func hasRenderUpdates(_ forFrame: CGFloat) -> Bool 24 | 25 | /** 26 | Determines if the renderer requires a custom context for drawing. 27 | If yes the shape layer will perform a custom drawing pass. 28 | If no the shape layer will be a standard CAShapeLayer 29 | */ 30 | var shouldRenderInContext: Bool { get } 31 | 32 | /// Passes in the CAShapeLayer to update 33 | func updateShapeLayer(layer: CAShapeLayer) 34 | 35 | /// Asks the renderer what the renderable bounds is for the given box. 36 | func renderBoundsFor(_ boundingBox: CGRect) -> CGRect 37 | 38 | /// Renders the shape in a custom context 39 | func render(_ inContext: CGContext) 40 | } 41 | 42 | extension RenderNode where Self: AnimatorNode { 43 | 44 | var outputNode: NodeOutput { 45 | return renderer 46 | } 47 | 48 | } 49 | 50 | extension Renderable { 51 | 52 | func renderBoundsFor(_ boundingBox: CGRect) -> CGRect { 53 | /// Optional 54 | return boundingBox 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShapeContainerLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | /** 12 | The base layer that holds Shapes and Shape Renderers 13 | */ 14 | class ShapeContainerLayer: CALayer { 15 | 16 | private(set) var renderLayers: [ShapeContainerLayer] = [] 17 | 18 | override init() { 19 | super.init() 20 | self.actions = [ 21 | "position" : NSNull(), 22 | "bounds" : NSNull(), 23 | "anchorPoint" : NSNull(), 24 | "transform" : NSNull(), 25 | "opacity" : NSNull(), 26 | "hidden" : NSNull(), 27 | ] 28 | } 29 | 30 | required init?(coder aDecoder: NSCoder) { 31 | fatalError("init(coder:) has not been implemented") 32 | } 33 | 34 | override init(layer: Any) { 35 | guard let layer = layer as? ShapeContainerLayer else { 36 | fatalError("init(layer:) wrong class.") 37 | } 38 | super.init(layer: layer) 39 | } 40 | 41 | var renderScale: CGFloat = 1 { 42 | didSet { 43 | updateRenderScale() 44 | } 45 | } 46 | 47 | func insertRenderLayer(_ layer: ShapeContainerLayer) { 48 | renderLayers.append(layer) 49 | insertSublayer(layer, at: 0) 50 | } 51 | 52 | func markRenderUpdates(forFrame: CGFloat) { 53 | if self.hasRenderUpdate(forFrame: forFrame) { 54 | self.rebuildContents(forFrame: forFrame) 55 | } 56 | guard self.isHidden == false else { return } 57 | renderLayers.forEach { $0.markRenderUpdates(forFrame: forFrame) } 58 | } 59 | 60 | func hasRenderUpdate(forFrame: CGFloat) -> Bool { 61 | return false 62 | } 63 | 64 | func rebuildContents(forFrame: CGFloat) { 65 | /// Override 66 | } 67 | 68 | func updateRenderScale() { 69 | self.contentsScale = self.renderScale 70 | renderLayers.forEach( { $0.renderScale = renderScale } ) 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/NodeRenderSystem/RenderLayers/ShapeRenderLayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RenderLayer.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/18/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | /** 12 | The layer responsible for rendering shape objects 13 | */ 14 | final class ShapeRenderLayer: ShapeContainerLayer { 15 | 16 | fileprivate(set) var renderer: Renderable & NodeOutput 17 | 18 | let shapeLayer: CAShapeLayer = CAShapeLayer() 19 | 20 | init(renderer: Renderable & NodeOutput) { 21 | self.renderer = renderer 22 | super.init() 23 | self.anchorPoint = .zero 24 | self.actions = [ 25 | "position" : NSNull(), 26 | "bounds" : NSNull(), 27 | "anchorPoint" : NSNull(), 28 | "path" : NSNull(), 29 | "transform" : NSNull(), 30 | "opacity" : NSNull(), 31 | "hidden" : NSNull(), 32 | ] 33 | shapeLayer.actions = [ 34 | "position" : NSNull(), 35 | "bounds" : NSNull(), 36 | "anchorPoint" : NSNull(), 37 | "path" : NSNull(), 38 | "fillColor" : NSNull(), 39 | "strokeColor" : NSNull(), 40 | "lineWidth" : NSNull(), 41 | "miterLimit" : NSNull(), 42 | "lineDashPhase" : NSNull(), 43 | "hidden" : NSNull(), 44 | ] 45 | addSublayer(shapeLayer) 46 | } 47 | 48 | override init(layer: Any) { 49 | guard let layer = layer as? ShapeRenderLayer else { 50 | fatalError("init(layer:) wrong class.") 51 | } 52 | self.renderer = layer.renderer 53 | super.init(layer: layer) 54 | } 55 | 56 | required init?(coder aDecoder: NSCoder) { 57 | fatalError("init(coder:) has not been implemented") 58 | } 59 | 60 | override func hasRenderUpdate(forFrame: CGFloat) -> Bool { 61 | self.isHidden = !renderer.isEnabled 62 | guard self.isHidden == false else { return false } 63 | return renderer.hasRenderUpdates(forFrame) 64 | } 65 | 66 | override func rebuildContents(forFrame: CGFloat) { 67 | 68 | if renderer.shouldRenderInContext { 69 | if let newPath = renderer.outputPath { 70 | self.bounds = renderer.renderBoundsFor(newPath.boundingBox) 71 | } else { 72 | self.bounds = .zero 73 | } 74 | self.position = bounds.origin 75 | self.setNeedsDisplay() 76 | } else { 77 | shapeLayer.path = renderer.outputPath 78 | renderer.updateShapeLayer(layer: shapeLayer) 79 | } 80 | } 81 | 82 | override func draw(in ctx: CGContext) { 83 | if let path = renderer.outputPath { 84 | if !path.isEmpty { 85 | ctx.addPath(path) 86 | } 87 | } 88 | renderer.render(ctx) 89 | } 90 | 91 | override func updateRenderScale() { 92 | super.updateRenderScale() 93 | shapeLayer.contentsScale = self.renderScale 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Utility/Debugging/AnimatorNodeDebugging.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimatorNodeDebugging.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/18/19. 6 | // 7 | 8 | import Foundation 9 | 10 | extension AnimatorNode { 11 | 12 | func printNodeTree() { 13 | parentNode?.printNodeTree() 14 | print(String(describing: type(of: self))) 15 | 16 | if let group = self as? GroupNode { 17 | print("* |Children") 18 | group.rootNode?.printNodeTree() 19 | print("*") 20 | } else { 21 | print("|") 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Utility/Extensions/CGFloatExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGFloatExtensions.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/14/19. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | extension CGFloat { 12 | 13 | func isInRangeOrEqual(_ from: CGFloat, _ to: CGFloat) -> Bool { 14 | return (from <= self && self <= to) 15 | } 16 | 17 | func isInRange(_ from: CGFloat, _ to: CGFloat) -> Bool { 18 | return (from < self && self < to) 19 | } 20 | 21 | var squared: CGFloat { 22 | return self * self 23 | } 24 | 25 | var cubed: CGFloat { 26 | return self * self * self 27 | } 28 | 29 | var cubicRoot: CGFloat { 30 | return CGFloat(pow(Double(self), 1.0 / 3.0)) 31 | } 32 | 33 | fileprivate static func SolveQuadratic(_ a: CGFloat, _ b: CGFloat, _ c: CGFloat) -> CGFloat { 34 | var result = (-b + sqrt(b.squared - 4 * a * c)) / (2 * a); 35 | guard !result.isInRangeOrEqual(0, 1) else { 36 | return result 37 | } 38 | 39 | result = (-b - sqrt(b.squared - 4 * a * c)) / (2 * a); 40 | guard !result.isInRangeOrEqual(0, 1) else { 41 | return result 42 | } 43 | 44 | return -1; 45 | } 46 | 47 | fileprivate static func SolveCubic(_ a: CGFloat, _ b: CGFloat, _ c: CGFloat, _ d: CGFloat) -> CGFloat { 48 | if (a == 0) { 49 | return SolveQuadratic(b, c, d) 50 | } 51 | if (d == 0) { 52 | return 0 53 | } 54 | let a = a 55 | var b = b 56 | var c = c 57 | var d = d 58 | b /= a 59 | c /= a 60 | d /= a 61 | var q = (3.0 * c - b.squared) / 9.0 62 | let r = (-27.0 * d + b * (9.0 * c - 2.0 * b.squared)) / 54.0 63 | let disc = q.cubed + r.squared 64 | let term1 = b / 3.0 65 | 66 | if (disc > 0) { 67 | var s = r + sqrt(disc) 68 | s = (s < 0) ? -((-s).cubicRoot) : s.cubicRoot 69 | var t = r - sqrt(disc) 70 | t = (t < 0) ? -((-t).cubicRoot) : t.cubicRoot 71 | 72 | let result = -term1 + s + t; 73 | if result.isInRangeOrEqual(0, 1) { 74 | return result 75 | } 76 | } else if (disc == 0) { 77 | let r13 = (r < 0) ? -((-r).cubicRoot) : r.cubicRoot; 78 | 79 | var result = -term1 + 2.0 * r13; 80 | if result.isInRangeOrEqual(0, 1) { 81 | return result 82 | } 83 | 84 | result = -(r13 + term1); 85 | if result.isInRangeOrEqual(0, 1) { 86 | return result 87 | } 88 | 89 | } else { 90 | q = -q; 91 | var dum1 = q * q * q; 92 | dum1 = acos(r / sqrt(dum1)); 93 | let r13 = 2.0 * sqrt(q); 94 | 95 | var result = -term1 + r13 * cos(dum1 / 3.0); 96 | if result.isInRangeOrEqual(0, 1) { 97 | return result 98 | } 99 | result = -term1 + r13 * cos((dum1 + 2.0 * .pi) / 3.0); 100 | if result.isInRangeOrEqual(0, 1) { 101 | return result 102 | } 103 | result = -term1 + r13 * cos((dum1 + 4.0 * .pi) / 3.0); 104 | if result.isInRangeOrEqual(0, 1) { 105 | return result 106 | } 107 | } 108 | 109 | return -1; 110 | } 111 | 112 | func cubicBezierInterpolate(_ P0: CGPoint, _ P1: CGPoint, _ P2: CGPoint, _ P3: CGPoint) -> CGFloat { 113 | var t: CGFloat 114 | if (self == P0.x) { 115 | // Handle corner cases explicitly to prevent rounding errors 116 | t = 0 117 | } else if (self == P3.x) { 118 | t = 1 119 | } else { 120 | // Calculate t 121 | let a = -P0.x + 3 * P1.x - 3 * P2.x + P3.x; 122 | let b = 3 * P0.x - 6 * P1.x + 3 * P2.x; 123 | let c = -3 * P0.x + 3 * P1.x; 124 | let d = P0.x - self; 125 | let tTemp = CGFloat.SolveCubic(a, b, c, d); 126 | if (tTemp == -1) { 127 | return -1; 128 | } 129 | t = tTemp 130 | } 131 | 132 | // Calculate y from t 133 | return (1 - t).cubed * P0.y + 3 * t * (1 - t).squared * P1.y + 3 * t.squared * (1 - t) * P2.y + t.cubed * P3.y; 134 | } 135 | 136 | func cubicBezier(_ t: CGFloat, _ c1: CGFloat, _ c2: CGFloat, _ end: CGFloat) -> CGFloat { 137 | let t_ = (1.0 - t) 138 | let tt_ = t_ * t_ 139 | let ttt_ = t_ * t_ * t_ 140 | let tt = t * t 141 | let ttt = t * t * t 142 | 143 | return self * ttt_ 144 | + 3.0 * c1 * tt_ * t 145 | + 3.0 * c2 * t_ * tt 146 | + end * ttt; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Utility/Extensions/StringExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringExtensions.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/25/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | extension String { 12 | 13 | func hexColorComponents() -> (red: CGFloat, green: CGFloat, blue: CGFloat) { 14 | 15 | var cString:String = trimmingCharacters(in: .whitespacesAndNewlines).uppercased() 16 | 17 | if (cString.hasPrefix("#")) { 18 | cString.remove(at: cString.startIndex) 19 | } 20 | 21 | if ((cString.count) != 6) { 22 | return (red: 0, green: 0, blue: 0) 23 | } 24 | 25 | var rgbValue:UInt32 = 0 26 | Scanner(string: cString).scanHexInt32(&rgbValue) 27 | 28 | return (red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, 29 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, 30 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Utility/Helpers/AnimationContext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimationContext.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/1/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | import QuartzCore 11 | 12 | /// A completion block for animations. `true` is passed in if the animation completed playing. 13 | public typealias LottieCompletionBlock = (Bool) -> Void 14 | 15 | struct AnimationContext { 16 | 17 | init(playFrom: CGFloat, 18 | playTo: CGFloat, 19 | closure: LottieCompletionBlock?) { 20 | self.playTo = playTo 21 | self.playFrom = playFrom 22 | self.closure = AnimationCompletionDelegate(completionBlock: closure) 23 | } 24 | 25 | var playFrom: CGFloat 26 | var playTo: CGFloat 27 | var closure: AnimationCompletionDelegate 28 | 29 | } 30 | 31 | enum AnimationContextState { 32 | case playing 33 | case cancelled 34 | case complete 35 | } 36 | 37 | class AnimationCompletionDelegate: NSObject, CAAnimationDelegate { 38 | 39 | init(completionBlock: LottieCompletionBlock?) { 40 | self.completionBlock = completionBlock 41 | super.init() 42 | } 43 | 44 | var animationLayer: AnimationContainer? 45 | var animationKey: String? 46 | var ignoreDelegate: Bool = false 47 | var animationState: AnimationContextState = .playing 48 | 49 | let completionBlock: LottieCompletionBlock? 50 | 51 | public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { 52 | guard ignoreDelegate == false else { return } 53 | animationState = flag ? .complete : .cancelled 54 | if let animationLayer = animationLayer, let key = animationKey { 55 | animationLayer.removeAnimation(forKey: key) 56 | if flag { 57 | animationLayer.currentFrame = (anim as! CABasicAnimation).toValue as! CGFloat 58 | } 59 | } 60 | if let completionBlock = completionBlock { 61 | completionBlock(flag) 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Utility/Interpolatable/Interpolatable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Interpolatable.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/14/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | protocol Interpolatable { 12 | 13 | func interpolateTo(_ to: Self, 14 | amount: CGFloat, 15 | spatialOutTangent: CGPoint?, 16 | spatialInTangent: CGPoint?) -> Self 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Utility/Interpolatable/KeyframeExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KeyframeExtensions.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/14/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | extension Keyframe { 12 | 13 | /// Interpolates the keyTime into a value from 0-1 14 | func interpolatedProgress(_ to: Keyframe, keyTime: CGFloat) -> CGFloat { 15 | let startTime = time 16 | let endTime = to.time 17 | if keyTime <= startTime { 18 | return 0 19 | } 20 | if endTime <= keyTime { 21 | return 1 22 | } 23 | 24 | if isHold { 25 | return 0 26 | } 27 | 28 | let outTanPoint = outTangent?.pointValue ?? .zero 29 | let inTanPoint = to.inTangent?.pointValue ?? CGPoint(x: 1, y: 1) 30 | var progress: CGFloat = keyTime.remap(fromLow: startTime, fromHigh: endTime, toLow: 0, toHigh: 1) 31 | if !outTanPoint.isZero || !inTanPoint.equalTo(CGPoint(x: 1, y: 1)) { 32 | /// Cubic interpolation 33 | progress = progress.cubicBezierInterpolate(.zero, outTanPoint, inTanPoint, CGPoint(x: 1, y: 1)) 34 | } 35 | return progress 36 | } 37 | 38 | /// Interpolates the keyframes' by a progress from 0-1 39 | func interpolate(_ to: Keyframe, progress: CGFloat) -> T { 40 | return value.interpolateTo(to.value, amount: progress, spatialOutTangent: spatialOutTangent?.pointValue, spatialInTangent: to.spatialInTangent?.pointValue) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Utility/Primitives/ColorExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Color.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/14/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | extension Color: Codable { 12 | 13 | public init(from decoder: Decoder) throws { 14 | var container = try decoder.unkeyedContainer() 15 | 16 | var r1: Double 17 | if !container.isAtEnd { 18 | r1 = try container.decode(Double.self) 19 | } else { 20 | r1 = 0 21 | } 22 | 23 | var g1: Double 24 | if !container.isAtEnd { 25 | g1 = try container.decode(Double.self) 26 | } else { 27 | g1 = 0 28 | } 29 | 30 | var b1: Double 31 | if !container.isAtEnd { 32 | b1 = try container.decode(Double.self) 33 | } else { 34 | b1 = 0 35 | } 36 | 37 | var a1: Double 38 | if !container.isAtEnd { 39 | a1 = try container.decode(Double.self) 40 | } else { 41 | a1 = 1 42 | } 43 | if r1 > 1, g1 > 1, b1 > 1, a1 > 1 { 44 | r1 = r1 / 255 45 | g1 = g1 / 255 46 | b1 = b1 / 255 47 | a1 = a1 / 255 48 | } 49 | self.r = r1 50 | self.g = g1 51 | self.b = b1 52 | self.a = a1 53 | } 54 | 55 | public func encode(to encoder: Encoder) throws { 56 | var container = encoder.unkeyedContainer() 57 | try container.encode(r) 58 | try container.encode(g) 59 | try container.encode(b) 60 | try container.encode(a) 61 | } 62 | 63 | } 64 | 65 | extension Color { 66 | 67 | static var clearColor: CGColor { 68 | return CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [0, 0, 0, 0])! 69 | } 70 | 71 | var cgColorValue: CGColor { 72 | // TODO: Fix color spaces 73 | let colorspace = CGColorSpaceCreateDeviceRGB() 74 | return CGColor(colorSpace: colorspace, components: [CGFloat(r), CGFloat(g), CGFloat(b), CGFloat(a)]) ?? Color.clearColor 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Private/Utility/Primitives/PathElement.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PathElement.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/11/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /** 12 | A path section, containing one point and its length to the previous point. 13 | 14 | The relationship between this path element and the previous is implicit. 15 | Ideally a path section would be defined by two vertices and a length. 16 | We don't do this however, as it would effectively double the memory footprint 17 | of path data. 18 | 19 | */ 20 | struct PathElement { 21 | /// The absolute Length of the path element. 22 | let length: CGFloat 23 | 24 | /// The vertex of the element 25 | let vertex: CurveVertex 26 | 27 | /// Returns a new path element define the span from the receiver to the new vertex. 28 | func pathElementTo(_ toVertex: CurveVertex) -> PathElement { 29 | return PathElement(length: vertex.distanceTo(toVertex), vertex: toVertex) 30 | } 31 | 32 | /// Initializes a new path with length of 0 33 | init(vertex: CurveVertex) { 34 | self.length = 0 35 | self.vertex = vertex 36 | } 37 | 38 | /// Initializes a new path with length 39 | fileprivate init(length: CGFloat, vertex: CurveVertex) { 40 | self.length = length 41 | self.vertex = vertex 42 | } 43 | 44 | func updateVertex(newVertex: CurveVertex) -> PathElement { 45 | return PathElement(length: length, vertex: newVertex) 46 | } 47 | 48 | /// Splits an element span defined by the receiver and fromElement to a position 0-1 49 | func splitElementAtPosition(fromElement: PathElement, atLength: CGFloat) -> 50 | (leftSpan: (start: PathElement, end: PathElement), rightSpan: (start: PathElement, end: PathElement)) { 51 | /// Trim the span. Start and trim go into the first, trim and end go into second. 52 | let trimResults = fromElement.vertex.trimCurve(toVertex: vertex, atLength: atLength, curveLength: length, maxSamples: 3) 53 | 54 | /// Create the elements for the break 55 | let spanAStart = PathElement(length: fromElement.length, 56 | vertex: CurveVertex(point: fromElement.vertex.point, 57 | inTangent: fromElement.vertex.inTangent, 58 | outTangent: trimResults.start.outTangent)) 59 | /// Recalculating the length here is a waste as the trimCurve function also accurately calculates this length. 60 | let spanAEnd = spanAStart.pathElementTo(trimResults.trimPoint) 61 | 62 | let spanBStart = PathElement(vertex: trimResults.trimPoint) 63 | let spanBEnd = spanBStart.pathElementTo(trimResults.end) 64 | return (leftSpan: (start: spanAStart, end: spanAEnd), 65 | rightSpan: (start: spanBStart, end: spanBEnd)) 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/Animation/AnimationViewInitializers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimationViewInitializers.swift 3 | // lottie-swift-iOS 4 | // 5 | // Created by Brandon Withrow on 2/6/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension AnimationView { 11 | 12 | /** 13 | Loads a Lottie animation from a JSON file in the supplied bundle. 14 | 15 | - Parameter name: The string name of the lottie animation with no file 16 | extension provided. 17 | - Parameter bundle: The bundle in which the animation is located. 18 | Defaults to the Main bundle. 19 | - Parameter imageProvider: An image provider for the animation's image data. 20 | If none is supplied Lottie will search in the supplied bundle for images. 21 | */ 22 | convenience init(name: String, 23 | bundle: Bundle = Bundle.main, 24 | imageProvider: AnimationImageProvider? = nil, 25 | animationCache: AnimationCacheProvider? = LRUAnimationCache.sharedCache) { 26 | let animation = Animation.named(name, bundle: bundle, subdirectory: nil, animationCache: animationCache) 27 | let provider = imageProvider ?? BundleImageProvider(bundle: bundle, searchPath: nil) 28 | self.init(animation: animation, imageProvider: provider) 29 | } 30 | 31 | /** 32 | Loads a Lottie animation from a JSON file in a specific path on disk. 33 | 34 | - Parameter name: The absolute path of the Lottie Animation. 35 | - Parameter imageProvider: An image provider for the animation's image data. 36 | If none is supplied Lottie will search in the supplied filepath for images. 37 | */ 38 | convenience init(filePath: String, 39 | imageProvider: AnimationImageProvider? = nil, 40 | animationCache: AnimationCacheProvider? = LRUAnimationCache.sharedCache) { 41 | let animation = Animation.filepath(filePath, animationCache: animationCache) 42 | let provider = imageProvider ?? FilepathImageProvider(filepath: URL(fileURLWithPath: filePath).deletingLastPathComponent().path) 43 | self.init(animation: animation, imageProvider: provider) 44 | } 45 | 46 | /** 47 | Loads a Lottie animation asynchronously from the URL 48 | 49 | - Parameter url: The url to load the animation from. 50 | - Parameter imageProvider: An image provider for the animation's image data. 51 | If none is supplied Lottie will search in the main bundle for images. 52 | - Parameter closure: A closure to be called when the animation has loaded. 53 | */ 54 | convenience init(url: URL, 55 | imageProvider: AnimationImageProvider? = nil, 56 | closure: @escaping AnimationView.DownloadClosure, 57 | animationCache: AnimationCacheProvider? = LRUAnimationCache.sharedCache) { 58 | 59 | if let animationCache = animationCache, let animation = animationCache.animation(forKey: url.absoluteString) { 60 | self.init(animation: animation, imageProvider: imageProvider) 61 | closure(nil) 62 | } else { 63 | 64 | self.init(animation: nil, imageProvider: imageProvider) 65 | 66 | Animation.loadedFrom(url: url, closure: { (animation) in 67 | if let animation = animation { 68 | self.animation = animation 69 | closure(nil) 70 | } else { 71 | closure(LottieDownloadError.downloadFailed) 72 | } 73 | }, animationCache: animationCache) 74 | } 75 | } 76 | 77 | typealias DownloadClosure = (Error?) -> Void 78 | 79 | } 80 | 81 | enum LottieDownloadError: Error { 82 | case downloadFailed 83 | } 84 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/AnimationCache/AnimationCacheProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimationCacheProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/5/19. 6 | // 7 | 8 | import Foundation 9 | /** 10 | `AnimationCacheProvider` is a protocol that describes an Animation Cache. 11 | Animation Cache is used when loading `Animation` models. Using an Animation Cache 12 | can increase performance when loading an animation multiple times. 13 | 14 | Lottie comes with a prebuilt LRU Animation Cache. 15 | */ 16 | public protocol AnimationCacheProvider { 17 | 18 | func animation(forKey: String) -> Animation? 19 | 20 | func setAnimation(_ animation: Animation, forKey: String) 21 | 22 | func clearCache() 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/AnimationCache/LRUAnimationCache.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LRUAnimationCache.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/5/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /** 11 | An Animation Cache that will store animations up to `cacheSize`. 12 | 13 | Once `cacheSize` is reached, the least recently used animation will be ejected. 14 | The default size of the cache is 100. 15 | */ 16 | public class LRUAnimationCache: AnimationCacheProvider { 17 | 18 | public init() { } 19 | 20 | /// Clears the Cache. 21 | public func clearCache() { 22 | cacheMap.removeAll() 23 | lruList.removeAll() 24 | } 25 | 26 | /// The global shared Cache. 27 | public static let sharedCache = LRUAnimationCache() 28 | 29 | /// The size of the cache. 30 | public var cacheSize: Int = 100 31 | 32 | public func animation(forKey: String) -> Animation? { 33 | guard let animation = cacheMap[forKey] else { 34 | return nil 35 | } 36 | if let index = lruList.firstIndex(of: forKey) { 37 | lruList.remove(at: index) 38 | lruList.append(forKey) 39 | } 40 | return animation 41 | } 42 | 43 | public func setAnimation(_ animation: Animation, forKey: String) { 44 | cacheMap[forKey] = animation 45 | lruList.append(forKey) 46 | if lruList.count > cacheSize { 47 | let removed = lruList.remove(at: 0) 48 | if removed != forKey { 49 | cacheMap[removed] = nil 50 | } 51 | } 52 | } 53 | 54 | fileprivate var cacheMap: [String : Animation] = [:] 55 | fileprivate var lruList: [String] = [] 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/DynamicProperties/AnimationKeypath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimationKeypath.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /** 11 | `AnimationKeypath` is an object that describes a keypath search for nodes in the 12 | animation JSON. `AnimationKeypath` matches views and properties inside of `AnimationView` 13 | to their backing `Animation` model by name. 14 | 15 | A keypath can be used to set properties on an existing animation, or can be validated 16 | with an existing `Animation`. 17 | 18 | `AnimationKeypath` can describe a specific object, or can use wildcards for fuzzy matching 19 | of objects. Acceptable wildcards are either "*" (star) or "**" (double star). 20 | Single star will search a single depth for the next object. 21 | Double star will search any depth. 22 | 23 | Read More at https://airbnb.io/lottie/#/ios?id=dynamic-animation-properties 24 | 25 | EG: 26 | @"Layer.Shape Group.Stroke 1.Color" 27 | Represents a specific color node on a specific stroke. 28 | 29 | @"**.Stroke 1.Color" 30 | Represents the color node for every Stroke named "Stroke 1" in the animation. 31 | */ 32 | public struct AnimationKeypath { 33 | 34 | /// Creates a keypath from a dot separated string. The string is separated by "." 35 | public init(keypath: String) { 36 | self.keys = keypath.components(separatedBy: ".") 37 | } 38 | 39 | /// Creates a keypath from a list of strings. 40 | public init(keys: [String]) { 41 | self.keys = keys 42 | } 43 | 44 | let keys: [String] 45 | 46 | } 47 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/DynamicProperties/AnyValueProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnyValueProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/30/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /** 12 | `AnyValueProvider` is a protocol that return animation data for a property at a 13 | given time. Every fame an `AnimationView` queries all of its properties and asks 14 | if their ValueProvider has an update. If it does the AnimationView will read the 15 | property and update that portion of the animation. 16 | 17 | Value Providers can be used to dynamically set animation properties at run time. 18 | */ 19 | public protocol AnyValueProvider { 20 | 21 | /// The Type of the value provider 22 | var valueType: Any.Type { get } 23 | 24 | /// Asks the provider if it has an update for the given frame. 25 | func hasUpdate(frame: AnimationFrameTime) -> Bool 26 | 27 | /// Asks the provider to update the container with its value for the frame. 28 | func value(frame: AnimationFrameTime) -> Any 29 | } 30 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ColorValueProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /// A `ValueProvider` that returns a CGColor Value 12 | public final class ColorValueProvider: AnyValueProvider { 13 | 14 | /// Returns a Color for a CGColor(Frame Time) 15 | public typealias ColorValueBlock = (CGFloat) -> Color 16 | 17 | /// The color value of the provider. 18 | public var color: Color { 19 | didSet { 20 | hasUpdate = true 21 | } 22 | } 23 | 24 | /// Initializes with a block provider 25 | public init(block: @escaping ColorValueBlock) { 26 | self.block = block 27 | self.color = Color(r: 0, g: 0, b: 0, a: 1) 28 | } 29 | 30 | /// Initializes with a single color. 31 | public init(_ color: Color) { 32 | self.color = color 33 | self.block = nil 34 | hasUpdate = true 35 | } 36 | 37 | // MARK: ValueProvider Protocol 38 | 39 | public var valueType: Any.Type { 40 | return Color.self 41 | } 42 | 43 | public func hasUpdate(frame: CGFloat) -> Bool { 44 | if block != nil { 45 | return true 46 | } 47 | return hasUpdate 48 | } 49 | 50 | public func value(frame: CGFloat) -> Any { 51 | hasUpdate = false 52 | let newColor: Color 53 | if let block = block { 54 | newColor = block(frame) 55 | } else { 56 | newColor = color 57 | } 58 | return newColor 59 | } 60 | 61 | // MARK: Private 62 | 63 | private var hasUpdate: Bool = true 64 | 65 | private var block: ColorValueBlock? 66 | } 67 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DoubleValueProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /// A `ValueProvider` that returns a CGFloat Value 12 | public final class FloatValueProvider: AnyValueProvider { 13 | 14 | /// Returns a CGFloat for a CGFloat(Frame Time) 15 | public typealias CGFloatValueBlock = (CGFloat) -> CGFloat 16 | 17 | public var float: CGFloat { 18 | didSet { 19 | hasUpdate = true 20 | } 21 | } 22 | 23 | /// Initializes with a block provider 24 | public init(block: @escaping CGFloatValueBlock) { 25 | self.block = block 26 | self.float = 0 27 | } 28 | 29 | /// Initializes with a single float. 30 | public init(_ float: CGFloat) { 31 | self.float = float 32 | self.block = nil 33 | hasUpdate = true 34 | } 35 | 36 | // MARK: ValueProvider Protocol 37 | 38 | public var valueType: Any.Type { 39 | return Vector1D.self 40 | } 41 | 42 | public func hasUpdate(frame: CGFloat) -> Bool { 43 | if block != nil { 44 | return true 45 | } 46 | return hasUpdate 47 | } 48 | 49 | public func value(frame: CGFloat) -> Any { 50 | hasUpdate = false 51 | let newCGFloat: CGFloat 52 | if let block = block { 53 | newCGFloat = block(frame) 54 | } else { 55 | newCGFloat = float 56 | } 57 | return Vector1D(Double(newCGFloat)) 58 | } 59 | 60 | // MARK: Private 61 | 62 | private var hasUpdate: Bool = true 63 | 64 | private var block: CGFloatValueBlock? 65 | } 66 | 67 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GradientValueProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Enrique Bermúdez on 10/27/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /// A `ValueProvider` that returns a Gradient Color Value. 12 | public final class GradientValueProvider: AnyValueProvider { 13 | 14 | /// Returns a [Color] for a CGFloat(Frame Time). 15 | public typealias ColorsValueBlock = (CGFloat) -> [Color] 16 | /// Returns a [Double](Color locations) for a CGFloat(Frame Time). 17 | public typealias ColorLocationsBlock = (CGFloat) -> [Double] 18 | 19 | /// The colors values of the provider. 20 | public var colors: [Color] { 21 | didSet { 22 | updateValueArray() 23 | hasUpdate = true 24 | } 25 | } 26 | 27 | /// The color location values of the provider. 28 | public var locations: [Double] { 29 | didSet { 30 | updateValueArray() 31 | hasUpdate = true 32 | } 33 | } 34 | 35 | /// Initializes with a block provider. 36 | public init(block: @escaping ColorsValueBlock, 37 | locations: ColorLocationsBlock? = nil) { 38 | self.block = block 39 | self.locationsBlock = locations 40 | self.colors = [] 41 | self.locations = [] 42 | } 43 | 44 | /// Initializes with an array of colors. 45 | public init(_ colors: [Color], 46 | locations: [Double] = []) { 47 | self.colors = colors 48 | self.locations = locations 49 | updateValueArray() 50 | hasUpdate = true 51 | } 52 | 53 | // MARK: ValueProvider Protocol 54 | 55 | public var valueType: Any.Type { 56 | return [Double].self 57 | } 58 | 59 | public func hasUpdate(frame: CGFloat) -> Bool { 60 | if block != nil || locationsBlock != nil { 61 | return true 62 | } 63 | return hasUpdate 64 | } 65 | 66 | public func value(frame: CGFloat) -> Any { 67 | hasUpdate = false 68 | 69 | if let block = block { 70 | let newColors = block(frame) 71 | let newLocations = locationsBlock?(frame) ?? [] 72 | value = value(from: newColors, locations: newLocations) 73 | } 74 | 75 | return value 76 | } 77 | 78 | // MARK: Private 79 | 80 | private func value(from colors: [Color], locations: [Double]) -> [Double] { 81 | 82 | var colorValues = [Double]() 83 | var alphaValues = [Double]() 84 | var shouldAddAlphaValues = false 85 | 86 | for i in 0.. i ? locations[i] : 91 | (Double(i) / Double(colors.count - 1)) 92 | 93 | colorValues.append(location) 94 | colorValues.append(colors[i].r) 95 | colorValues.append(colors[i].g) 96 | colorValues.append(colors[i].b) 97 | 98 | alphaValues.append(location) 99 | alphaValues.append(colors[i].a) 100 | } 101 | 102 | return colorValues + (shouldAddAlphaValues ? alphaValues : []) 103 | } 104 | 105 | private func updateValueArray() { 106 | value = value(from: colors, locations: locations) 107 | } 108 | 109 | private var hasUpdate: Bool = true 110 | 111 | private var block: ColorsValueBlock? 112 | private var locationsBlock: ColorLocationsBlock? 113 | private var value: [Double] = [] 114 | } 115 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/DynamicProperties/ValueProviders/PointValueProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PointValueProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | /// A `ValueProvider` that returns a CGPoint Value 11 | public final class PointValueProvider: AnyValueProvider { 12 | 13 | /// Returns a CGPoint for a CGFloat(Frame Time) 14 | public typealias PointValueBlock = (CGFloat) -> CGPoint 15 | 16 | public var point: CGPoint { 17 | didSet { 18 | hasUpdate = true 19 | } 20 | } 21 | 22 | /// Initializes with a block provider 23 | public init(block: @escaping PointValueBlock) { 24 | self.block = block 25 | self.point = .zero 26 | } 27 | 28 | /// Initializes with a single point. 29 | public init(_ point: CGPoint) { 30 | self.point = point 31 | self.block = nil 32 | hasUpdate = true 33 | } 34 | 35 | // MARK: ValueProvider Protocol 36 | 37 | public var valueType: Any.Type { 38 | return Vector3D.self 39 | } 40 | 41 | public func hasUpdate(frame: CGFloat) -> Bool { 42 | if block != nil { 43 | return true 44 | } 45 | return hasUpdate 46 | } 47 | 48 | public func value(frame: CGFloat) -> Any { 49 | hasUpdate = false 50 | let newPoint: CGPoint 51 | if let block = block { 52 | newPoint = block(frame) 53 | } else { 54 | newPoint = point 55 | } 56 | return newPoint.vector3dValue 57 | } 58 | 59 | // MARK: Private 60 | 61 | private var hasUpdate: Bool = true 62 | 63 | private var block: PointValueBlock? 64 | } 65 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SizeValueProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /// A `ValueProvider` that returns a CGSize Value 12 | public final class SizeValueProvider: AnyValueProvider { 13 | 14 | /// Returns a CGSize for a CGFloat(Frame Time) 15 | public typealias SizeValueBlock = (CGFloat) -> CGSize 16 | 17 | public var size: CGSize { 18 | didSet { 19 | hasUpdate = true 20 | } 21 | } 22 | 23 | /// Initializes with a block provider 24 | public init(block: @escaping SizeValueBlock) { 25 | self.block = block 26 | self.size = .zero 27 | } 28 | 29 | /// Initializes with a single size. 30 | public init(_ size: CGSize) { 31 | self.size = size 32 | self.block = nil 33 | hasUpdate = true 34 | } 35 | 36 | // MARK: ValueProvider Protocol 37 | 38 | public var valueType: Any.Type { 39 | return Vector3D.self 40 | } 41 | 42 | public func hasUpdate(frame: CGFloat) -> Bool { 43 | if block != nil { 44 | return true 45 | } 46 | return hasUpdate 47 | } 48 | 49 | public func value(frame: CGFloat) -> Any { 50 | hasUpdate = false 51 | let newSize: CGSize 52 | if let block = block { 53 | newSize = block(frame) 54 | } else { 55 | newSize = size 56 | } 57 | return newSize.vector3dValue 58 | } 59 | 60 | // MARK: Private 61 | 62 | private var hasUpdate: Bool = true 63 | 64 | private var block: SizeValueBlock? 65 | } 66 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/ImageProvider/AnimationImageProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LottieImageProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/25/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /** 12 | Image provider is a protocol that is used to supply images to `AnimationView`. 13 | 14 | Some animations require a reference to an image. The image provider loads and 15 | provides those images to the `AnimationView`. Lottie includes a couple of 16 | prebuilt Image Providers that supply images from a Bundle, or from a FilePath. 17 | 18 | Additionally custom Image Providers can be made to load images from a URL, 19 | or to Cache images. 20 | */ 21 | public protocol AnimationImageProvider { 22 | func imageForAsset(asset: ImageAsset) -> CGImage? 23 | } 24 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/Primitives/AnimationTime.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimationTime.swift 3 | // lottie-swift-iOS 4 | // 5 | // Created by Brandon Withrow on 2/6/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | 11 | /// Defines animation time in Frames (Seconds * Framerate). 12 | public typealias AnimationFrameTime = CGFloat 13 | 14 | /// Defines animation time by a progress from 0 (beginning of the animation) to 1 (end of the animation) 15 | public typealias AnimationProgressTime = CGFloat 16 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/Primitives/Color.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Color.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public enum ColorFormatDenominator { 11 | case One 12 | case OneHundred 13 | case TwoFiftyFive 14 | 15 | var value: Double { 16 | switch self { 17 | case .One: 18 | return 1.0 19 | case .OneHundred: 20 | return 100.0 21 | case .TwoFiftyFive: 22 | return 255.0 23 | } 24 | } 25 | } 26 | 27 | public struct Color { 28 | 29 | public var r: Double 30 | public var g: Double 31 | public var b: Double 32 | public var a: Double 33 | 34 | public init(r: Double, g: Double, b: Double, a: Double, denominator: ColorFormatDenominator = .One) { 35 | self.r = r / denominator.value 36 | self.g = g / denominator.value 37 | self.b = b / denominator.value 38 | self.a = a / denominator.value 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/Primitives/Vectors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Vectors.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct Vector1D { 11 | 12 | public init(_ value: Double) { 13 | self.value = value 14 | } 15 | 16 | let value: Double 17 | 18 | } 19 | 20 | 21 | /** 22 | A three dimensional vector. 23 | These vectors are encoded and decoded from [Double] 24 | */ 25 | public struct Vector3D { 26 | 27 | var x: Double 28 | var y: Double 29 | var z: Double 30 | 31 | public init(x: Double, y: Double, z: Double) { 32 | self.x = x 33 | self.y = y 34 | self.z = z 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/TextProvider/AnimationTextProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimationImageProvider.swift 3 | // Lottie_iOS 4 | // 5 | // Created by Alexandr Goncharov on 07/06/2019. 6 | // 7 | 8 | import Foundation 9 | 10 | /** 11 | Text provider is a protocol that is used to supply text to `AnimationView`. 12 | */ 13 | public protocol AnimationTextProvider: AnyObject { 14 | func textFor(keypathName: String, sourceText: String) -> String 15 | } 16 | 17 | /// Text provider that simply map values from dictionary 18 | public final class DictionaryTextProvider: AnimationTextProvider { 19 | 20 | public init(_ values: [String: String]) { 21 | self.values = values 22 | } 23 | 24 | let values: [String: String] 25 | 26 | public func textFor(keypathName: String, sourceText: String) -> String { 27 | return values[keypathName] ?? sourceText 28 | } 29 | } 30 | 31 | /// Default text provider. Uses text in the animation file 32 | public final class DefaultTextProvider: AnimationTextProvider { 33 | public func textFor(keypathName: String, sourceText: String) -> String { 34 | return sourceText 35 | } 36 | 37 | public init() {} 38 | } 39 | 40 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/iOS/AnimatedButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimatedButton.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | #if os(iOS) || os(tvOS) || os(watchOS) 10 | import UIKit 11 | /** 12 | An interactive button that plays an animation when pressed. 13 | */ 14 | final public class AnimatedButton: AnimatedControl { 15 | 16 | /// Sets the play range for the given UIControlEvent. 17 | public func setPlayRange(fromProgress: AnimationProgressTime, toProgress: AnimationProgressTime, event: UIControl.Event) { 18 | rangesForEvents[event.rawValue] = (from: fromProgress, to: toProgress) 19 | } 20 | 21 | /// Sets the play range for the given UIControlEvent. 22 | public func setPlayRange(fromMarker fromName: String, toMarker toName: String, event: UIControl.Event) { 23 | if let start = animationView.progressTime(forMarker: fromName), 24 | let end = animationView.progressTime(forMarker: toName) { 25 | rangesForEvents[event.rawValue] = (from: start, to: end) 26 | } 27 | } 28 | 29 | public override init(animation: Animation) { 30 | super.init(animation: animation) 31 | self.accessibilityTraits = UIAccessibilityTraits.button 32 | } 33 | 34 | public override init() { 35 | super.init() 36 | self.accessibilityTraits = UIAccessibilityTraits.button 37 | } 38 | 39 | fileprivate var rangesForEvents: [UInt : (from: CGFloat, to: CGFloat)] = [UIControl.Event.touchUpInside.rawValue : (from: 0, to: 1)] 40 | 41 | required public init?(coder aDecoder: NSCoder) { 42 | super.init(coder: aDecoder) 43 | } 44 | 45 | public override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { 46 | let _ = super.beginTracking(touch, with: event) 47 | let touchEvent = UIControl.Event.touchDown 48 | if let playrange = rangesForEvents[touchEvent.rawValue] { 49 | animationView.play(fromProgress: playrange.from, toProgress: playrange.to, loopMode: LottieLoopMode.playOnce) 50 | } 51 | return true 52 | } 53 | 54 | public override func endTracking(_ touch: UITouch?, with event: UIEvent?) { 55 | super.endTracking(touch, with: event) 56 | let touchEvent: UIControl.Event 57 | if let touch = touch, bounds.contains(touch.location(in: self)) { 58 | touchEvent = UIControl.Event.touchUpInside 59 | } else { 60 | touchEvent = UIControl.Event.touchUpOutside 61 | } 62 | 63 | if let playrange = rangesForEvents[touchEvent.rawValue] { 64 | animationView.play(fromProgress: playrange.from, toProgress: playrange.to, loopMode: LottieLoopMode.playOnce) 65 | } 66 | } 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/iOS/AnimationSubview.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimationSubview.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | #if os(iOS) || os(tvOS) || os(watchOS) 10 | import UIKit 11 | 12 | /// A view that can be added to a keypath of an AnimationView 13 | public final class AnimationSubview: UIView { 14 | 15 | var viewLayer: CALayer? { 16 | return layer 17 | } 18 | 19 | } 20 | #endif 21 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/iOS/BundleImageProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LottieBundleImageProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 1/25/19. 6 | // 7 | 8 | import Foundation 9 | import CoreGraphics 10 | #if os(iOS) || os(tvOS) || os(watchOS) 11 | import UIKit 12 | 13 | /** 14 | An `AnimationImageProvider` that provides images by name from a specific bundle. 15 | The BundleImageProvider is initialized with a bundle and an optional searchPath. 16 | */ 17 | public class BundleImageProvider: AnimationImageProvider { 18 | 19 | let bundle: Bundle 20 | let searchPath: String? 21 | 22 | /** 23 | Initializes an image provider with a bundle and an optional subpath. 24 | 25 | Provides images for an animation from a bundle. Additionally the provider can 26 | search a specific subpath for the images. 27 | 28 | - Parameter bundle: The bundle containing images for the provider. 29 | - Parameter searchPath: The subpath is a path within the bundle to search for image assets. 30 | 31 | */ 32 | public init(bundle: Bundle, searchPath: String?) { 33 | self.bundle = bundle 34 | self.searchPath = searchPath 35 | } 36 | 37 | public func imageForAsset(asset: ImageAsset) -> CGImage? { 38 | 39 | if asset.name.hasPrefix("data:"), 40 | let url = URL(string: asset.name), 41 | let data = try? Data(contentsOf: url), 42 | let image = UIImage(data: data) { 43 | return image.cgImage 44 | } 45 | 46 | let imagePath: String? 47 | /// Try to find the image in the bundle. 48 | if let searchPath = searchPath { 49 | /// Search in the provided search path for the image 50 | var directoryPath = URL(fileURLWithPath: searchPath) 51 | directoryPath.appendPathComponent(asset.directory) 52 | 53 | if let path = bundle.path(forResource: asset.name, ofType: nil, inDirectory: directoryPath.path) { 54 | /// First search for the image in the asset provided sub directory. 55 | imagePath = path 56 | } else if let path = bundle.path(forResource: asset.name, ofType: nil, inDirectory: searchPath) { 57 | /// Try finding the image in the search path. 58 | imagePath = path 59 | } else { 60 | imagePath = bundle.path(forResource: asset.name, ofType: nil) 61 | } 62 | } else { 63 | if let path = bundle.path(forResource: asset.name, ofType: nil, inDirectory: asset.directory) { 64 | /// First search for the image in the asset provided sub directory. 65 | imagePath = path 66 | } else { 67 | /// First search for the image in bundle. 68 | imagePath = bundle.path(forResource: asset.name, ofType: nil) 69 | } 70 | } 71 | 72 | guard let foundPath = imagePath, let image = UIImage(contentsOfFile: foundPath) else { 73 | /// No image found. 74 | return nil 75 | } 76 | return image.cgImage 77 | } 78 | 79 | } 80 | #endif 81 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/iOS/Compatibility/CompatibleAnimationKeypath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CompatibleAnimationKeypath.swift 3 | // Lottie_iOS 4 | // 5 | // Created by Tyler Hedrick on 3/6/19. 6 | // 7 | 8 | import Foundation 9 | #if os(iOS) || os(tvOS) || os(watchOS) 10 | 11 | /// An Objective-C compatible wrapper around Lottie's AnimationKeypath 12 | @objc 13 | public final class CompatibleAnimationKeypath: NSObject { 14 | 15 | /// Creates a keypath from a dot separated string. The string is separated by "." 16 | @objc 17 | public init(keypath: String) { 18 | animationKeypath = AnimationKeypath(keypath: keypath) 19 | } 20 | 21 | /// Creates a keypath from a list of strings. 22 | @objc 23 | public init(keys: [String]) { 24 | animationKeypath = AnimationKeypath(keys: keys) 25 | } 26 | 27 | public let animationKeypath: AnimationKeypath 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/iOS/FilepathImageProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilepathImageProvider.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/1/19. 6 | // 7 | 8 | import Foundation 9 | #if os(iOS) || os(tvOS) || os(watchOS) 10 | import UIKit 11 | 12 | /** 13 | Provides an image for a lottie animation from a provided Bundle. 14 | */ 15 | public class FilepathImageProvider: AnimationImageProvider { 16 | 17 | let filepath: URL 18 | 19 | /** 20 | Initializes an image provider with a specific filepath. 21 | 22 | - Parameter filepath: The absolute filepath containing the images. 23 | 24 | */ 25 | public init(filepath: String) { 26 | self.filepath = URL(fileURLWithPath: filepath) 27 | } 28 | 29 | public init(filepath: URL) { 30 | self.filepath = filepath 31 | } 32 | 33 | public func imageForAsset(asset: ImageAsset) -> CGImage? { 34 | 35 | if asset.name.hasPrefix("data:"), 36 | let url = URL(string: asset.name), 37 | let data = try? Data(contentsOf: url), 38 | let image = UIImage(data: data) { 39 | return image.cgImage 40 | } 41 | 42 | let directPath = filepath.appendingPathComponent(asset.name).path 43 | if FileManager.default.fileExists(atPath: directPath) { 44 | return UIImage(contentsOfFile: directPath)?.cgImage 45 | } 46 | 47 | let pathWithDirectory = filepath.appendingPathComponent(asset.directory).appendingPathComponent(asset.name).path 48 | if FileManager.default.fileExists(atPath: pathWithDirectory) { 49 | return UIImage(contentsOfFile: pathWithDirectory)?.cgImage 50 | } 51 | 52 | return nil 53 | } 54 | 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/iOS/LottieView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LottieView.swift 3 | // lottie-swift-iOS 4 | // 5 | // Created by Brandon Withrow on 2/6/19. 6 | // 7 | 8 | import Foundation 9 | #if os(iOS) || os(tvOS) || os(watchOS) 10 | import UIKit 11 | 12 | //public typealias LottieView = UIView 13 | 14 | open class LottieView: UIView { 15 | 16 | var viewLayer: CALayer? { 17 | return layer 18 | } 19 | 20 | func layoutAnimation() { 21 | 22 | } 23 | 24 | func animationMovedToWindow() { 25 | 26 | } 27 | 28 | open override func didMoveToWindow() { 29 | super.didMoveToWindow() 30 | animationMovedToWindow() 31 | } 32 | 33 | var screenScale: CGFloat { 34 | return UIScreen.main.scale 35 | } 36 | 37 | func commonInit() { 38 | contentMode = .scaleAspectFit 39 | clipsToBounds = true 40 | NotificationCenter.default.addObserver(self, selector: #selector(animationWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) 41 | NotificationCenter.default.addObserver(self, selector: #selector(animationWillMoveToBackground), name: UIApplication.didEnterBackgroundNotification, object: nil) 42 | } 43 | 44 | open override var contentMode: UIView.ContentMode { 45 | didSet { 46 | setNeedsLayout() 47 | } 48 | } 49 | 50 | open override func layoutSubviews() { 51 | super.layoutSubviews() 52 | self.layoutAnimation() 53 | } 54 | 55 | @objc func animationWillMoveToBackground() { 56 | } 57 | 58 | @objc func animationWillEnterForeground() { 59 | } 60 | 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /Pods/lottie-ios/lottie-swift/src/Public/iOS/UIColorExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColorExtension.swift 3 | // lottie-swift 4 | // 5 | // Created by Brandon Withrow on 2/4/19. 6 | // 7 | 8 | import Foundation 9 | #if os(iOS) || os(tvOS) || os(watchOS) 10 | import UIKit 11 | 12 | public extension UIColor { 13 | 14 | var lottieColorValue: Color { 15 | var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0 16 | getRed(&r, green: &g, blue: &b, alpha: &a) 17 | return Color(r: Double(r), g: Double(g), b: Double(b), a: Double(a)) 18 | } 19 | 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UserOnboarding_iOS 2 | Tutorial to demonstrate a simple way to create UserOnboarding with the help of CollectionView and Lottie. 3 | 4 | 5 | 6 | ## Prerequisites 7 | * Swift 5 8 | * XCode 9 | * CocoaPods 10 | 11 | 12 | ## Technology used 13 | * Xcode 14 | * Swift 5 15 | 16 | ## How to use ? 17 | 1. Download or clone the repository. 18 | 2. Import the project through Xcode. 19 | 3. Run the application in mobile or simulator running iOS 13 20 | 21 | ## Credits 22 | © Shubham Kumar Singh | 2020 23 | -------------------------------------------------------------------------------- /UserOnboarding.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /UserOnboarding.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /UserOnboarding.xcodeproj/xcuserdata/shubham.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | UserOnboarding.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 2 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /UserOnboarding.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /UserOnboarding.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /UserOnboarding.xcworkspace/xcuserdata/shubham.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /UserOnboarding/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // UserOnboarding 4 | // 5 | // Created by Shubham Singh on 24/04/20. 6 | // Copyright © 2020 Shubham Singh. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | 21 | // MARK: UISceneSession Lifecycle 22 | 23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 24 | // Called when a new scene session is being created. 25 | // Use this method to select a configuration to create the new scene with. 26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 27 | } 28 | 29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 30 | // Called when the user discards a scene session. 31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 33 | } 34 | 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /UserOnboarding/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /UserOnboarding/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /UserOnboarding/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /UserOnboarding/CollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewCell.swift 3 | // UserOnboarding 4 | // 5 | // Created by Shubham Singh on 25/04/20. 6 | // Copyright © 2020 Shubham Singh. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CollectionViewCell: UICollectionViewCell { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /UserOnboarding/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIMainStoryboardFile 45 | Main 46 | UIRequiredDeviceCapabilities 47 | 48 | armv7 49 | 50 | UISupportedInterfaceOrientations 51 | 52 | UIInterfaceOrientationPortrait 53 | UIInterfaceOrientationLandscapeLeft 54 | UIInterfaceOrientationLandscapeRight 55 | 56 | UISupportedInterfaceOrientations~ipad 57 | 58 | UIInterfaceOrientationPortrait 59 | UIInterfaceOrientationPortraitUpsideDown 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /UserOnboarding/OnboardingCollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OnboardingCollectionViewCell.swift 3 | // UserOnboarding 4 | // 5 | // Created by Shubham Singh on 25/04/20. 6 | // Copyright © 2020 Shubham Singh. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Lottie 11 | 12 | // Model to be used by the CollectionView 13 | struct Page { 14 | let animationName: String 15 | let title: String 16 | let description: String 17 | } 18 | 19 | // Custom UICollectionViewCell 20 | class OnboardingCollectionViewCell: UICollectionViewCell { 21 | 22 | @IBOutlet weak var animationContainer: UIView! 23 | @IBOutlet weak var titleLabel: UILabel! 24 | @IBOutlet weak var descriptionTextView: UITextView! 25 | 26 | static let identifier = "OnboardingCollectionViewCell" 27 | 28 | // Instance of the Lottie AnimationView 29 | var animation = AnimationView() 30 | 31 | 32 | override func awakeFromNib() { 33 | super.awakeFromNib() 34 | } 35 | 36 | // function to configure the cell 37 | func configureCell(page: Page){ 38 | 39 | // define the animation and the size 40 | animation = AnimationView(name: page.animationName) 41 | animation.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height * 0.8) 42 | 43 | // customize the animation 44 | animation.animationSpeed = 1 45 | animation.loopMode = .loop 46 | animation.play() 47 | 48 | animationContainer.addSubview(animation) 49 | 50 | // set the title and description of the screen 51 | self.titleLabel.text = page.title 52 | self.descriptionTextView.text = page.description 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /UserOnboarding/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // UserOnboarding 4 | // 5 | // Created by Shubham Singh on 24/04/20. 6 | // Copyright © 2020 Shubham Singh. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 12 | 13 | var window: UIWindow? 14 | 15 | 16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 20 | guard let _ = (scene as? UIWindowScene) else { return } 21 | } 22 | 23 | func sceneDidDisconnect(_ scene: UIScene) { 24 | // Called as the scene is being released by the system. 25 | // This occurs shortly after the scene enters the background, or when its session is discarded. 26 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 28 | } 29 | 30 | func sceneDidBecomeActive(_ scene: UIScene) { 31 | // Called when the scene has moved from an inactive state to an active state. 32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 33 | } 34 | 35 | func sceneWillResignActive(_ scene: UIScene) { 36 | // Called when the scene will move from an active state to an inactive state. 37 | // This may occur due to temporary interruptions (ex. an incoming phone call). 38 | } 39 | 40 | func sceneWillEnterForeground(_ scene: UIScene) { 41 | // Called as the scene transitions from the background to the foreground. 42 | // Use this method to undo the changes made on entering the background. 43 | } 44 | 45 | func sceneDidEnterBackground(_ scene: UIScene) { 46 | // Called as the scene transitions from the foreground to the background. 47 | // Use this method to save data, release shared resources, and store enough scene-specific state information 48 | // to restore the scene back to its current state. 49 | } 50 | 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /UserOnboarding/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // UserOnboarding 4 | // 5 | // Created by Shubham Singh on 24/04/20. 6 | // Copyright © 2020 Shubham Singh. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { 12 | 13 | // MARK:- outlets for the viewController 14 | @IBOutlet weak var collectionView: UICollectionView! 15 | @IBOutlet weak var pageControl: UIPageControl! 16 | @IBOutlet weak var getStartedButton: UIButton! 17 | 18 | // data for the Onboarding Screens 19 | let pages: [Page] = [Page(animationName: "animation1", title: "Learn to Code", description: "Find awesome tutorials on how to code and improve your coding practices"), 20 | Page(animationName: "animation2", title: "Code with Friends", description: "Practice with friends and solve problems together to earn points"), 21 | Page(animationName: "animation3", title: "Always there to Help", description: "Having Trouble? Get guidance from our experienced Mentors")] 22 | 23 | 24 | // MARK:- lifeCycle methods for the ViewController 25 | override func viewDidLoad() { 26 | super.viewDidLoad() 27 | 28 | // to make the button rounded 29 | self.getStartedButton.layer.cornerRadius = 20 30 | 31 | // register the custom CollectionViewCell and assign the delegates to the ViewController 32 | self.collectionView.backgroundColor = .white 33 | self.collectionView.dataSource = self 34 | self.collectionView.delegate = self 35 | self.collectionView.register(UINib(nibName: OnboardingCollectionViewCell.identifier, bundle: Bundle.main), 36 | forCellWithReuseIdentifier: "OnboardingCollectionViewCell") 37 | 38 | // set the number of pages to the number of Onboarding Screens 39 | self.pageControl.numberOfPages = self.pages.count 40 | } 41 | 42 | // MARK:- outlet functions for the viewController 43 | @IBAction func pageChanged(_ sender: Any) { 44 | let pc = sender as! UIPageControl 45 | 46 | // scrolling the collectionView to the selected page 47 | collectionView.scrollToItem(at: IndexPath(item: pc.currentPage, section: 0), 48 | at: .centeredHorizontally, animated: true) 49 | } 50 | 51 | @IBAction func getStartedButtonTapped(_ sender: Any) { 52 | // move the user to the other view controller 53 | print("Move to other view controller") 54 | } 55 | 56 | 57 | 58 | // MARK:- collectionView dataSource & collectionView FlowLayout delegates 59 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 60 | return pages.count 61 | } 62 | 63 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 64 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OnboardingCollectionViewCell.identifier, 65 | for: indexPath) as! OnboardingCollectionViewCell 66 | // function for configuring the cell, defined in the Custom cell class 67 | cell.configureCell(page: pages[indexPath.item]) 68 | return cell 69 | } 70 | 71 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, 72 | sizeForItemAt indexPath: IndexPath) -> CGSize { 73 | return CGSize(width: self.collectionView.frame.width, height: self.collectionView.frame.height) 74 | } 75 | 76 | // to update the UIPageControl 77 | func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, 78 | forItemAt indexPath: IndexPath) { 79 | pageControl.currentPage = collectionView.indexPathsForVisibleItems[0].item 80 | } 81 | } 82 | 83 | --------------------------------------------------------------------------------