lottie-ios 3.2.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (585) hide show
  1. package/.github/FUNDING.yml +1 -1
  2. package/.github/actions/setup/action.yml +32 -0
  3. package/.github/issue_template.md +6 -23
  4. package/.github/workflows/main.yml +95 -0
  5. package/.spi.yml +6 -0
  6. package/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +7 -0
  7. package/.swiftpm/xcode/package.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  8. package/.swiftpm/xcode/xcuserdata/{brandonwithrow.xcuserdatad → cal.xcuserdatad}/xcschemes/xcschememanagement.plist +25 -15
  9. package/.swiftpm/xcode/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  10. package/Gemfile +4 -0
  11. package/Gemfile.lock +102 -0
  12. package/Lottie.xcodeproj/project.pbxproj +2005 -1974
  13. package/Lottie.xcodeproj/project.xcworkspace/contents.xcworkspacedata +1 -1
  14. package/Lottie.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +23 -0
  15. package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  16. package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_iOS.xcscheme → Lottie (iOS).xcscheme } +15 -18
  17. package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_macOS.xcscheme → Lottie (macOS).xcscheme } +7 -20
  18. package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_tvOS.xcscheme → Lottie (tvOS).xcscheme } +5 -18
  19. package/Lottie.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +37 -0
  20. package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +24 -0
  21. package/Lottie.xcworkspace/contents.xcworkspacedata +10 -0
  22. package/Lottie.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  23. package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +34 -0
  24. package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  25. package/{Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad → Lottie.xcworkspace/xcuserdata/cal.xcuserdatad}/xcdebugger/Breakpoints_v2.xcbkptlist +2 -2
  26. package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/xcdebugger/Expressions.xcexplist +153 -0
  27. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  28. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +39 -0
  29. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +25 -0
  30. package/Mintfile +3 -0
  31. package/Package.swift +5 -15
  32. package/README.md +40 -59
  33. package/Rakefile +125 -0
  34. package/Sources/Private/CoreAnimation/Animations/CAAnimation+TimingConfiguration.swift +76 -0
  35. package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +322 -0
  36. package/Sources/Private/CoreAnimation/Animations/CombinedShapeAnimation.swift +53 -0
  37. package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +41 -0
  38. package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +28 -0
  39. package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +167 -0
  40. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +229 -0
  41. package/Sources/Private/CoreAnimation/Animations/OpacityAnimation.swift +52 -0
  42. package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +31 -0
  43. package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +246 -0
  44. package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +95 -0
  45. package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +70 -0
  46. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +205 -0
  47. package/Sources/Private/CoreAnimation/Animations/VisibilityAnimation.swift +37 -0
  48. package/Sources/Private/CoreAnimation/CompatibilityTracker.swift +130 -0
  49. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +492 -0
  50. package/Sources/Private/CoreAnimation/Extensions/CALayer+fillBounds.swift +35 -0
  51. package/Sources/Private/CoreAnimation/Extensions/KeyframeGroup+exactlyOneKeyframe.swift +37 -0
  52. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combinedIfPossible.swift +61 -0
  53. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +77 -0
  54. package/Sources/Private/CoreAnimation/Layers/BaseAnimationLayer.swift +33 -0
  55. package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +87 -0
  56. package/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift +131 -0
  57. package/Sources/Private/CoreAnimation/Layers/GradientRenderLayer.swift +87 -0
  58. package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +79 -0
  59. package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +60 -0
  60. package/Sources/Private/CoreAnimation/Layers/MaskCompositionLayer.swift +138 -0
  61. package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +140 -0
  62. package/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +259 -0
  63. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +305 -0
  64. package/Sources/Private/CoreAnimation/Layers/SolidLayer.swift +47 -0
  65. package/Sources/Private/CoreAnimation/Layers/TextLayer.swift +91 -0
  66. package/Sources/Private/CoreAnimation/Layers/TransformLayer.swift +11 -0
  67. package/Sources/Private/CoreAnimation/ValueProviderStore.swift +139 -0
  68. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/CompositionLayer.swift +94 -86
  69. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/ImageCompositionLayer.swift +24 -21
  70. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/MaskContainerLayer.swift +77 -54
  71. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/NullCompositionLayer.swift +5 -5
  72. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/PreCompositionLayer.swift +59 -42
  73. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/ShapeCompositionLayer.swift +22 -20
  74. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/SolidCompositionLayer.swift +26 -17
  75. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/CompLayers/TextCompositionLayer.swift +46 -35
  76. package/{lottie-swift/src/Private/LayerContainers/AnimationContainer.swift → Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift} +203 -135
  77. package/Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift +47 -0
  78. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/CompositionLayersInitializer.swift +33 -24
  79. package/{lottie-swift/src/Private/LayerContainers/Utility/TextLayer.swift → Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift} +122 -106
  80. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/InvertedMatteLayer.swift +25 -24
  81. package/Sources/Private/MainThread/LayerContainers/Utility/LayerFontProvider.swift +41 -0
  82. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/LayerImageProvider.swift +20 -16
  83. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTextProvider.swift +40 -0
  84. package/{lottie-swift/src/Private → Sources/Private/MainThread}/LayerContainers/Utility/LayerTransformNode.swift +83 -67
  85. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Extensions/ItemsExtension.swift +6 -4
  86. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/NodeProperty.swift +29 -21
  87. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/AnyNodeProperty.swift +16 -10
  88. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/AnyValueContainer.swift +7 -7
  89. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/KeypathSearchable.swift +5 -5
  90. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift +10 -8
  91. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/ValueContainer.swift +25 -21
  92. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/ValueProviders/GroupInterpolator.swift +23 -17
  93. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/ValueProviders/KeyframeInterpolator.swift +128 -108
  94. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/NodeProperties/ValueProviders/SingleValueProvider.swift +22 -17
  95. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +113 -79
  96. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift +22 -16
  97. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift +19 -15
  98. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/PathOutputNode.swift +22 -20
  99. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift +22 -23
  100. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +242 -0
  101. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientStrokeRenderer.swift +29 -22
  102. package/{lottie-swift/src/Private/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift → Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift} +92 -65
  103. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +22 -18
  104. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +139 -0
  105. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +170 -0
  106. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +94 -57
  107. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/PathNodes/ShapeNode.swift +42 -29
  108. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +105 -66
  109. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +155 -0
  110. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift +51 -37
  111. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +54 -42
  112. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +65 -57
  113. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +84 -58
  114. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +138 -119
  115. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Protocols/AnimatorNode.swift +81 -80
  116. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Protocols/PathNode.swift +5 -3
  117. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Protocols/RenderNode.swift +22 -17
  118. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +26 -24
  119. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/RenderLayers/ShapeRenderLayer.swift +32 -27
  120. package/Sources/Private/Model/Animation.swift +160 -0
  121. package/Sources/Private/Model/Assets/Asset.swift +43 -0
  122. package/{lottie-swift/src → Sources}/Private/Model/Assets/AssetLibrary.swift +40 -13
  123. package/Sources/Private/Model/Assets/ImageAsset.swift +112 -0
  124. package/{lottie-swift/src → Sources}/Private/Model/Assets/PrecompAsset.swift +20 -10
  125. package/Sources/Private/Model/DictionaryInitializable.swift +67 -0
  126. package/Sources/Private/Model/Extensions/Bundle.swift +34 -0
  127. package/{lottie-swift/src → Sources}/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift +8 -4
  128. package/Sources/Private/Model/Keyframes/KeyframeData.swift +113 -0
  129. package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +197 -0
  130. package/{lottie-swift/src → Sources}/Private/Model/Layers/ImageLayerModel.swift +21 -11
  131. package/Sources/Private/Model/Layers/LayerModel.swift +228 -0
  132. package/{lottie-swift/src → Sources}/Private/Model/Layers/PreCompLayerModel.swift +39 -22
  133. package/{lottie-swift/src → Sources}/Private/Model/Layers/ShapeLayerModel.swift +23 -12
  134. package/{lottie-swift/src → Sources}/Private/Model/Layers/SolidLayerModel.swift +31 -19
  135. package/{lottie-swift/src → Sources}/Private/Model/Layers/TextLayerModel.swift +33 -19
  136. package/Sources/Private/Model/Objects/DashPattern.swift +44 -0
  137. package/Sources/Private/Model/Objects/Marker.swift +33 -0
  138. package/Sources/Private/Model/Objects/Mask.swift +80 -0
  139. package/Sources/Private/Model/Objects/Transform.swift +179 -0
  140. package/Sources/Private/Model/ShapeItems/Ellipse.swift +75 -0
  141. package/Sources/Private/Model/ShapeItems/Fill.swift +74 -0
  142. package/Sources/Private/Model/ShapeItems/GradientFill.swift +124 -0
  143. package/Sources/Private/Model/ShapeItems/GradientStroke.swift +186 -0
  144. package/{lottie-swift/src → Sources}/Private/Model/ShapeItems/Group.swift +21 -10
  145. package/{lottie-swift/src → Sources}/Private/Model/ShapeItems/Merge.swift +29 -11
  146. package/Sources/Private/Model/ShapeItems/Rectangle.swift +73 -0
  147. package/Sources/Private/Model/ShapeItems/Repeater.swift +136 -0
  148. package/Sources/Private/Model/ShapeItems/Shape.swift +56 -0
  149. package/Sources/Private/Model/ShapeItems/ShapeItem.swift +163 -0
  150. package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +136 -0
  151. package/Sources/Private/Model/ShapeItems/Star.swift +132 -0
  152. package/Sources/Private/Model/ShapeItems/Stroke.swift +102 -0
  153. package/Sources/Private/Model/ShapeItems/Trim.swift +78 -0
  154. package/Sources/Private/Model/Text/Font.swift +61 -0
  155. package/{lottie-swift/src → Sources}/Private/Model/Text/Glyph.swift +63 -39
  156. package/Sources/Private/Model/Text/TextAnimator.swift +165 -0
  157. package/Sources/Private/Model/Text/TextDocument.swift +123 -0
  158. package/Sources/Private/RootAnimationLayer.swift +51 -0
  159. package/{lottie-swift/src → Sources}/Private/Utility/Debugging/AnimatorNodeDebugging.swift +7 -7
  160. package/{lottie-swift/src → Sources}/Private/Utility/Debugging/LayerDebugging.swift +72 -47
  161. package/Sources/Private/Utility/Debugging/TestHelpers.swift +10 -0
  162. package/{lottie-swift/src → Sources}/Private/Utility/Extensions/AnimationKeypathExtension.swift +69 -59
  163. package/Sources/Private/Utility/Extensions/BlendMode+Filter.swift +31 -0
  164. package/Sources/Private/Utility/Extensions/CGColor+RGB.swift +22 -0
  165. package/{lottie-swift/src → Sources}/Private/Utility/Extensions/CGFloatExtensions.swift +70 -67
  166. package/Sources/Private/Utility/Extensions/DataExtension.swift +27 -0
  167. package/Sources/Private/Utility/Extensions/MathKit.swift +451 -0
  168. package/Sources/Private/Utility/Extensions/StringExtensions.swift +39 -0
  169. package/{lottie-swift/src → Sources}/Private/Utility/Helpers/AnimationContext.swift +42 -16
  170. package/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift +135 -0
  171. package/{lottie-swift/src → Sources}/Private/Utility/Interpolatable/KeyframeExtensions.swift +13 -10
  172. package/Sources/Private/Utility/Interpolatable/KeyframeGroup+Extensions.swift +59 -0
  173. package/{lottie-swift/src → Sources}/Private/Utility/Primitives/BezierPath.swift +229 -142
  174. package/Sources/Private/Utility/Primitives/CGPointExtension.swift +35 -0
  175. package/{lottie-swift/src → Sources}/Private/Utility/Primitives/ColorExtension.swift +46 -14
  176. package/{lottie-swift/src → Sources}/Private/Utility/Primitives/CompoundBezierPath.swift +58 -49
  177. package/Sources/Private/Utility/Primitives/CurveVertex.swift +186 -0
  178. package/Sources/Private/Utility/Primitives/PathElement.swift +75 -0
  179. package/Sources/Private/Utility/Primitives/UnitBezier.swift +115 -0
  180. package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +341 -0
  181. package/Sources/Public/Animation/AnimationPublic.swift +269 -0
  182. package/Sources/Public/Animation/AnimationView.swift +1315 -0
  183. package/Sources/Public/Animation/AnimationViewInitializers.swift +107 -0
  184. package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +22 -0
  185. package/{lottie-swift/src → Sources}/Public/AnimationCache/LRUAnimationCache.swift +22 -18
  186. package/Sources/Public/DynamicProperties/AnimationKeypath.swift +49 -0
  187. package/Sources/Public/DynamicProperties/AnyValueProvider.swift +132 -0
  188. package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +54 -36
  189. package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +40 -36
  190. package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +125 -0
  191. package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +40 -35
  192. package/{lottie-swift/src → Sources}/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +40 -35
  193. package/{lottie-swift/src → Sources}/Public/FontProvider/AnimationFontProvider.swift +15 -8
  194. package/Sources/Public/ImageProvider/AnimationImageProvider.swift +21 -0
  195. package/Sources/Public/Keyframes/Interpolatable.swift +253 -0
  196. package/Sources/Public/Keyframes/Keyframe.swift +92 -0
  197. package/Sources/Public/Logging/LottieLogger.swift +124 -0
  198. package/Sources/Public/LottieConfiguration.swift +143 -0
  199. package/{lottie-swift/src → Sources}/Public/Primitives/AnimationTime.swift +1 -1
  200. package/{lottie-swift/src → Sources}/Public/Primitives/Color.swift +10 -6
  201. package/{lottie-swift/src → Sources}/Public/Primitives/Vectors.swift +13 -12
  202. package/Sources/Public/TextProvider/AnimationTextProvider.swift +53 -0
  203. package/{lottie-swift/src → Sources}/Public/iOS/AnimatedButton.swift +37 -27
  204. package/{lottie-swift/src → Sources}/Public/iOS/AnimatedControl.swift +103 -92
  205. package/{lottie-swift/src → Sources}/Public/iOS/AnimatedSwitch.swift +124 -93
  206. package/{lottie-swift/src → Sources}/Public/iOS/AnimationSubview.swift +4 -4
  207. package/Sources/Public/iOS/AnimationViewBase.swift +78 -0
  208. package/{lottie-swift/src → Sources}/Public/iOS/BundleImageProvider.swift +38 -35
  209. package/{lottie-swift/src → Sources}/Public/iOS/Compatibility/CompatibleAnimationKeypath.swift +5 -1
  210. package/{lottie-swift/src → Sources}/Public/iOS/Compatibility/CompatibleAnimationView.swift +39 -30
  211. package/{lottie-swift/src → Sources}/Public/iOS/FilepathImageProvider.swift +25 -21
  212. package/{lottie-swift/src → Sources}/Public/iOS/UIColorExtension.swift +5 -5
  213. package/{lottie-swift/src/Public/MacOS/AnimationSubview.swift → Sources/Public/macOS/AnimationSubview.macOS.swift} +4 -5
  214. package/{lottie-swift/src/Public/MacOS/LottieView.swift → Sources/Public/macOS/AnimationViewBase.macOS.swift} +58 -50
  215. package/{lottie-swift/src/Public/MacOS/BundleImageProvider.swift → Sources/Public/macOS/BundleImageProvider.macOS.swift} +32 -32
  216. package/Sources/Public/macOS/FilepathImageProvider.macOS.swift +69 -0
  217. package/Tests/AnimationKeypathTests.swift +94 -0
  218. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~-7Vi1RszY1XYnR2CCkEwIpKG8NwwA9zsZEz_WD7Dv6kKh4RC7N7ob8NIRVHGUJKp7eXxlpeI_gzD87Pcs_2u0g== +0 -0
  219. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~-SKV2drO-SFlrlh-wrzECDMkUSr-aF1lV9h-5onOy94zSTsD-oI45s0-KpOK45L-kq3hRY7v9vm-xmh00_eheg== +0 -0
  220. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~-_CU_vuaiFfObSeDFfmp7GuB20ThMSAL-P_RUMowiQLbdu-y0bU9upIm3q8g6XmXUG5hP6J1az0Ma5Hi_rhhRg== +0 -0
  221. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~03aPYP6VHJjZj5DlphGarj0xdw43qu09Onx5SReZoPvg9zh5uL212E-KWfGct9jf6JG0JFV2tdbBi7X_8bH9aw== +0 -0
  222. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~1Z82GPBBPc1VLvn4O7V5glb6lgyXteNlDREUzV_TPymM4ra4UkBMklzV90lEqoYRCDuRVzaQHaDYbmYp3-8CFw== +0 -0
  223. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~1mFDCboXpUu9pSHAiVGr1O_QgqEEtvJp_LUhickxLZo0Z5pj3fvadn1l2MzEOd4bFsVBZifUvcyPa7dzlMWF-A== +0 -0
  224. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~2_L9PUjv2JDKu1n8bDLb4XLB-yex6ZVjDDMwfuKAr7teDw-SKgLgkW6H-m_gjWChIVdB4vW6yvHP7XJxvXtRNA== +0 -0
  225. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw== +1 -0
  226. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~4krT4ZMzDOu34msFUq0Xod142kw4pAeSWX4JSxlsjOI0Wanu3343qeespgFi61MTWq1DdH9XXspVKqGlGm_fyw== +0 -0
  227. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~5_aJsdP-e3dRTAUnH-y1U2plaCuUi1vyHriaZuNK0xFe8wGl9Qft6uLCX2Qt6CRBKJQluEe9o0uRWw1eb42FHQ== +0 -0
  228. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~8b0bSqV7eND54zvHvu1v2Htpm7yn-BOEFw5d3mITJrXWNykJ5BTR9WbrD80JEctNcT-rDqO2xfrQk1tFWeY6Sw== +0 -0
  229. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~9u8KAGpgtSm-mQ12Py8RZUbYbDlBhM3w1I2MQO53K2CSn6IePp7g65DBcdXTYMfG1bgoJ-6x30fjnGe-2UYsDQ== +0 -0
  230. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Bw7uMs4wqB9ahfEqGii2FkQ9pvZmG6HGe2hmbAT2wyM5hpn8Xh5dELysMcEz6hEsqmn6HdRdLOLZhC_fNaXzgA== +0 -0
  231. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~BwUq2xXQYuE8ya6HT6lfNsdtEjz5AKGf8GvLY6VBxQyIY1vgj_Gov-3NeM69OS66BQRDK0PG9H4Oyg0R48E4vg== +0 -0
  232. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~EkDVUR6dcnzxV_lYjkrJ5QGMVTCvb_upAoBF6DBu61sQkGvZN3fSRTsJ1XfJIZO-JUzdNoVA3D_CcvokL0gnQg== +0 -0
  233. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~FUkcLSJ8RAuPenM4HFG1R-sN5-cDBGcTxgR2jaVCna7xV0ZTyBHriB1Nn59mariNlJDiCoBtMUQEmauGxWtfBA== +0 -0
  234. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~FqsuZe4RVLOOVUYLTL-GTIohZ8TdSfxx7m2KJtLYFPGOdE4XorTX7Oc7kXbhghPRppXT3jW-slI37M34YNEvLQ== +0 -0
  235. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~G4F_NtyTj3i46fmKm0NorHAeq8tYWWYf6uv5yC1DwzdpWVoYbOPufmFNvdEbxZt4AMdV0gKx3HI46EAXNOQVFg== +0 -0
  236. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~GxetzGUNDgaBBXcTmLK6p9JBDX3I3QPshshbui1IaEWvJbQko-E36tCKwaJYHbleAWz9FqkAM_Tqx3YOmSVkVg== +0 -0
  237. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~H1Wjd5kKWDW4t3SDodxiHV72V8WT0xwPubw5cJTNLkPRLgaILFPh-dpy8EOUNgy1KzrDujFsm9EcTsbuqtMPLA== +0 -0
  238. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~JpI5MH4zCgebUHFpXVn4zjtsGtMNnO7BQZWfNARAB5UWa9gqz6YXHR3uLCJ_AvJ3lh53BUVkavsx9TY2FMmxbA== +0 -0
  239. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~JujNYkJtcux0Ni4QnR64zu4Wz_zYjyKvYaYZm5ypxTLPSzF3_jNE_NO4sdbDamF8wEqWoky1uf4ZE0JT3L607A== +0 -0
  240. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~KJSEA6DKnb2_FRPSqKZGh41eo-C8x448J9kEBrH012bUrZfOSDvrgmIrU0Vz7Ri3gaS9aKKmSaVMvXsHSlTJVA== +0 -0
  241. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~MStOwu3jBlJtcRnxrseVOuhI4kCj--ggFPG7sqrq5w1hjrI3bVyD-bm1Jwyx0noY3wT1rHDEvaGWnV2qsGjGwg== +0 -0
  242. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~McsJ8kFVf3IjhgXIRdw8Xx-EXgbV071bmlj2BBnk52xrWl3sEeiIyxwUsF7mIWvMRWfcFfu4VGHYyqfk2BeHXw== +0 -0
  243. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~NHt9fVe4kDdbxnglKcEwXaRK-WsYEOaD23Kbl8SJPRMYHr_Z6SJd_HmG3BROHHR_M6TgSmucONpDJdTj5tjuFw== +0 -0
  244. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Nfo2iwCPcfAcOBIVyoUAK0-PIfr5qYxIKZt-uaSaTBdrTNxAuJ1ItmeDPZ3VdJJmxD_c22No7x482bdd3_yYtw== +0 -0
  245. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~S2Qlu11xBhEd5aGSzWsnw1TR8u8PiOF93GO0j5bfNoAFCVzxKOwhRFoIXba2EpQnLQqFdIKyhWN3l70A4GPHmg== +0 -0
  246. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~W7a7M37RO9jgck2zeR0471Pm7e8K0Kqj5tXEouDjvqKZXSrWxMaWD28oqkKKYAiU4608R4S9mM11KyphljdMSw== +0 -0
  247. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~XUo1oyPCrlL7CA74wG-OzQ06VOWJYWvHGFHU7keZN1SKaIXjHX5qi_kBzjG_rBCi89-S8GVmCy7S3PHSjG8SbQ== +0 -0
  248. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Xh0VmDvFNMELHu08-vrs54pegVyUwwDRxx_nXkwyD0NjnYozyqcGAKAr_QWHmw6F8XyuWg51M9KGpJJIFzzGuw== +0 -0
  249. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Xve-wMBp_lxVUgD9qH5GwieGP9cAWtm0xULZvdGjBRUMvaevmpCB5gnbMBuIXAO6a1c9v6WUq0jNVX7ut5HvOw== +0 -0
  250. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~ZU1XkZFgnEE22CXEF-pOlcj5f10x-KM1Vw9d4IOLu-NiTZcz7koYPixhdrB1PJr8J-h9NpJmfqEastfxamA1jQ== +0 -0
  251. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~_YkNYEHTsbbtFILJpzH3HenH0t4ShI25dIMdve541CF5bl-jPF3X3F7tq-t5dvP0TEkATsOJdLQdBp1xv4Q-ag== +0 -0
  252. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~boy6mpn2jkwm60jjgQ0TG25UqRdN46LzmgTVCrpy6nBOgkLCGkGHcbceiwjU1itS_vj3-iQX0ZnrWOQrPyfHNA== +0 -0
  253. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~bwzpVZ9hAqGDHhXs2FRA82dfGfLmc7-m0uQhZDDfHHO7hQ17M_Np341BZX4WDLhYYS4cdUgaDodlNpdfpG3nXw== +0 -0
  254. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~cBxe-9PpAGFdAsYkmdN3lJVqEliLcRYlyoAov0aPZfJGwUr_cOm3XpjO7nmf_2eLf8UAx-rycjnJzw07xLrNCA== +1 -0
  255. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~dirWk6W4Pav1oyciuflfJlRu0iuxbYOmrpQapOJ0mV9C1SQ-jvDRv_7h753Cy18-SwULARUdWsyUy3yNNvxF7w== +0 -0
  256. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~ebwZVjSEHroc9jtIm4jd_h_YAqEBcOkAZ4HPNJT8pLCldjRcTq-obQLakxXOhfuoOBlYBoZLuO-Y0lskeZRYKw== +0 -0
  257. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~gfcRcmRIr0h09d0jiZsA7nUeQv2XtapxuYEXZy1Z9um0tTJQvz-O5ef5f7zhLenLvjnDtDtlY_aY4Hvpce6e1Q== +0 -0
  258. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~hgOgiVCyv2R0W-f0qKw5xYPeUwj8_ccCM9vKH_7vAQcCO9t8BwR1APGRBv20AONmp-PYMXmtgsBlQkNBRBpdQA== +0 -0
  259. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~hrhCl-YRAAr8ByNB_LCgEBsVNHMp92gTIUknetpUHMjcXl4Hpn_uY-h6C45oga0ZALnfGCo6iKTmiPLa4Qvnpg== +0 -0
  260. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~n2yoR7JsyL4DSUwmjnpE4Iq9Qi_eeZrmpPU8cdehDFKfESK7nwxXxfrSMQbk0BQ2lgGPadoRcd1-qr1xVz97jA== +0 -0
  261. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~nMCcZm8WvPogyO_nuJ926Q3Q2dqVMN2LdjEL1Kq2wJ_RG-rH-e_6v41l1xZbCsQTa3XykQdEiXNc0HtAvT6IRA== +0 -0
  262. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~oc3C7xkUt-OWDL6rrsxs-seS4Fu1bqBWAAXCHalgShaGg9MUrOiRbHT2DcAnhyQFKx6x5FRbvjmYoQWrQiXJZA== +0 -0
  263. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~p-ihj7SEgkDXpMu9hvKE_wiX9cvtwyXrdIn964BfedXHKGpC6o7mMPxEyC0kRPVi_EZs_MRV5bAPEpl5h5we0g== +0 -0
  264. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~qlhO_D9oE8uSKH-mZqyRF9pp4Zv1Tv0dIYcqrH4hb1VWlIxcdxmg2j0M8496cQeFXC5bn_JMXdBlD-d6cnFF8w== +0 -0
  265. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~tjpiyIxJR_boTdUNrtFDuKIZoY84fI4lA1oMJbq9e2ZmYKIK5FeRN2O8cV_yMOYJGr4lbv03kTmT70mCjUc2_Q== +0 -0
  266. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~wULeoj18eEKJWAKx1uFQVwS48cUGFcYPRJQj1Ro5XNJsWCwppGSCdIPhwifD6Z2f_j3zfI2SmC2Gg81sBXXW7g== +0 -0
  267. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~zrEihMys4NVV5rx6FmuzEGO2TjloI3OiC7yzIhvqYoRo43ibb2F-Km6Jf4NX-ac62pOLBYZRcjQTvYMpn75_oA== +0 -0
  268. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~-7Vi1RszY1XYnR2CCkEwIpKG8NwwA9zsZEz_WD7Dv6kKh4RC7N7ob8NIRVHGUJKp7eXxlpeI_gzD87Pcs_2u0g== +0 -0
  269. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~-SKV2drO-SFlrlh-wrzECDMkUSr-aF1lV9h-5onOy94zSTsD-oI45s0-KpOK45L-kq3hRY7v9vm-xmh00_eheg== +0 -0
  270. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~-_CU_vuaiFfObSeDFfmp7GuB20ThMSAL-P_RUMowiQLbdu-y0bU9upIm3q8g6XmXUG5hP6J1az0Ma5Hi_rhhRg== +0 -0
  271. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~03aPYP6VHJjZj5DlphGarj0xdw43qu09Onx5SReZoPvg9zh5uL212E-KWfGct9jf6JG0JFV2tdbBi7X_8bH9aw== +0 -0
  272. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~1Z82GPBBPc1VLvn4O7V5glb6lgyXteNlDREUzV_TPymM4ra4UkBMklzV90lEqoYRCDuRVzaQHaDYbmYp3-8CFw== +0 -0
  273. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~1mFDCboXpUu9pSHAiVGr1O_QgqEEtvJp_LUhickxLZo0Z5pj3fvadn1l2MzEOd4bFsVBZifUvcyPa7dzlMWF-A== +0 -0
  274. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~2_L9PUjv2JDKu1n8bDLb4XLB-yex6ZVjDDMwfuKAr7teDw-SKgLgkW6H-m_gjWChIVdB4vW6yvHP7XJxvXtRNA== +0 -0
  275. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw== +0 -0
  276. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~4krT4ZMzDOu34msFUq0Xod142kw4pAeSWX4JSxlsjOI0Wanu3343qeespgFi61MTWq1DdH9XXspVKqGlGm_fyw== +0 -0
  277. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~5_aJsdP-e3dRTAUnH-y1U2plaCuUi1vyHriaZuNK0xFe8wGl9Qft6uLCX2Qt6CRBKJQluEe9o0uRWw1eb42FHQ== +0 -0
  278. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~8b0bSqV7eND54zvHvu1v2Htpm7yn-BOEFw5d3mITJrXWNykJ5BTR9WbrD80JEctNcT-rDqO2xfrQk1tFWeY6Sw== +0 -0
  279. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~9u8KAGpgtSm-mQ12Py8RZUbYbDlBhM3w1I2MQO53K2CSn6IePp7g65DBcdXTYMfG1bgoJ-6x30fjnGe-2UYsDQ== +0 -0
  280. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Bw7uMs4wqB9ahfEqGii2FkQ9pvZmG6HGe2hmbAT2wyM5hpn8Xh5dELysMcEz6hEsqmn6HdRdLOLZhC_fNaXzgA== +0 -0
  281. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~BwUq2xXQYuE8ya6HT6lfNsdtEjz5AKGf8GvLY6VBxQyIY1vgj_Gov-3NeM69OS66BQRDK0PG9H4Oyg0R48E4vg== +0 -0
  282. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~EkDVUR6dcnzxV_lYjkrJ5QGMVTCvb_upAoBF6DBu61sQkGvZN3fSRTsJ1XfJIZO-JUzdNoVA3D_CcvokL0gnQg== +0 -0
  283. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~FUkcLSJ8RAuPenM4HFG1R-sN5-cDBGcTxgR2jaVCna7xV0ZTyBHriB1Nn59mariNlJDiCoBtMUQEmauGxWtfBA== +0 -0
  284. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~FqsuZe4RVLOOVUYLTL-GTIohZ8TdSfxx7m2KJtLYFPGOdE4XorTX7Oc7kXbhghPRppXT3jW-slI37M34YNEvLQ== +0 -0
  285. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~G4F_NtyTj3i46fmKm0NorHAeq8tYWWYf6uv5yC1DwzdpWVoYbOPufmFNvdEbxZt4AMdV0gKx3HI46EAXNOQVFg== +0 -0
  286. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~GxetzGUNDgaBBXcTmLK6p9JBDX3I3QPshshbui1IaEWvJbQko-E36tCKwaJYHbleAWz9FqkAM_Tqx3YOmSVkVg== +0 -0
  287. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~H1Wjd5kKWDW4t3SDodxiHV72V8WT0xwPubw5cJTNLkPRLgaILFPh-dpy8EOUNgy1KzrDujFsm9EcTsbuqtMPLA== +0 -0
  288. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~JpI5MH4zCgebUHFpXVn4zjtsGtMNnO7BQZWfNARAB5UWa9gqz6YXHR3uLCJ_AvJ3lh53BUVkavsx9TY2FMmxbA== +0 -0
  289. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~JujNYkJtcux0Ni4QnR64zu4Wz_zYjyKvYaYZm5ypxTLPSzF3_jNE_NO4sdbDamF8wEqWoky1uf4ZE0JT3L607A== +0 -0
  290. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~KJSEA6DKnb2_FRPSqKZGh41eo-C8x448J9kEBrH012bUrZfOSDvrgmIrU0Vz7Ri3gaS9aKKmSaVMvXsHSlTJVA== +0 -0
  291. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~MStOwu3jBlJtcRnxrseVOuhI4kCj--ggFPG7sqrq5w1hjrI3bVyD-bm1Jwyx0noY3wT1rHDEvaGWnV2qsGjGwg== +0 -0
  292. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~McsJ8kFVf3IjhgXIRdw8Xx-EXgbV071bmlj2BBnk52xrWl3sEeiIyxwUsF7mIWvMRWfcFfu4VGHYyqfk2BeHXw== +0 -0
  293. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~NHt9fVe4kDdbxnglKcEwXaRK-WsYEOaD23Kbl8SJPRMYHr_Z6SJd_HmG3BROHHR_M6TgSmucONpDJdTj5tjuFw== +0 -0
  294. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Nfo2iwCPcfAcOBIVyoUAK0-PIfr5qYxIKZt-uaSaTBdrTNxAuJ1ItmeDPZ3VdJJmxD_c22No7x482bdd3_yYtw== +0 -0
  295. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~S2Qlu11xBhEd5aGSzWsnw1TR8u8PiOF93GO0j5bfNoAFCVzxKOwhRFoIXba2EpQnLQqFdIKyhWN3l70A4GPHmg== +0 -0
  296. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~W7a7M37RO9jgck2zeR0471Pm7e8K0Kqj5tXEouDjvqKZXSrWxMaWD28oqkKKYAiU4608R4S9mM11KyphljdMSw== +0 -0
  297. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~XUo1oyPCrlL7CA74wG-OzQ06VOWJYWvHGFHU7keZN1SKaIXjHX5qi_kBzjG_rBCi89-S8GVmCy7S3PHSjG8SbQ== +0 -0
  298. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Xh0VmDvFNMELHu08-vrs54pegVyUwwDRxx_nXkwyD0NjnYozyqcGAKAr_QWHmw6F8XyuWg51M9KGpJJIFzzGuw== +0 -0
  299. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Xve-wMBp_lxVUgD9qH5GwieGP9cAWtm0xULZvdGjBRUMvaevmpCB5gnbMBuIXAO6a1c9v6WUq0jNVX7ut5HvOw== +0 -0
  300. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~ZU1XkZFgnEE22CXEF-pOlcj5f10x-KM1Vw9d4IOLu-NiTZcz7koYPixhdrB1PJr8J-h9NpJmfqEastfxamA1jQ== +0 -0
  301. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~_YkNYEHTsbbtFILJpzH3HenH0t4ShI25dIMdve541CF5bl-jPF3X3F7tq-t5dvP0TEkATsOJdLQdBp1xv4Q-ag== +0 -0
  302. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~boy6mpn2jkwm60jjgQ0TG25UqRdN46LzmgTVCrpy6nBOgkLCGkGHcbceiwjU1itS_vj3-iQX0ZnrWOQrPyfHNA== +0 -0
  303. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~bwzpVZ9hAqGDHhXs2FRA82dfGfLmc7-m0uQhZDDfHHO7hQ17M_Np341BZX4WDLhYYS4cdUgaDodlNpdfpG3nXw== +0 -0
  304. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~cBxe-9PpAGFdAsYkmdN3lJVqEliLcRYlyoAov0aPZfJGwUr_cOm3XpjO7nmf_2eLf8UAx-rycjnJzw07xLrNCA== +0 -0
  305. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~dirWk6W4Pav1oyciuflfJlRu0iuxbYOmrpQapOJ0mV9C1SQ-jvDRv_7h753Cy18-SwULARUdWsyUy3yNNvxF7w== +0 -0
  306. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~ebwZVjSEHroc9jtIm4jd_h_YAqEBcOkAZ4HPNJT8pLCldjRcTq-obQLakxXOhfuoOBlYBoZLuO-Y0lskeZRYKw== +0 -0
  307. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~gfcRcmRIr0h09d0jiZsA7nUeQv2XtapxuYEXZy1Z9um0tTJQvz-O5ef5f7zhLenLvjnDtDtlY_aY4Hvpce6e1Q== +0 -0
  308. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~hgOgiVCyv2R0W-f0qKw5xYPeUwj8_ccCM9vKH_7vAQcCO9t8BwR1APGRBv20AONmp-PYMXmtgsBlQkNBRBpdQA== +0 -0
  309. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~hrhCl-YRAAr8ByNB_LCgEBsVNHMp92gTIUknetpUHMjcXl4Hpn_uY-h6C45oga0ZALnfGCo6iKTmiPLa4Qvnpg== +0 -0
  310. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~n2yoR7JsyL4DSUwmjnpE4Iq9Qi_eeZrmpPU8cdehDFKfESK7nwxXxfrSMQbk0BQ2lgGPadoRcd1-qr1xVz97jA== +0 -0
  311. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~nMCcZm8WvPogyO_nuJ926Q3Q2dqVMN2LdjEL1Kq2wJ_RG-rH-e_6v41l1xZbCsQTa3XykQdEiXNc0HtAvT6IRA== +0 -0
  312. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~oc3C7xkUt-OWDL6rrsxs-seS4Fu1bqBWAAXCHalgShaGg9MUrOiRbHT2DcAnhyQFKx6x5FRbvjmYoQWrQiXJZA== +0 -0
  313. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~p-ihj7SEgkDXpMu9hvKE_wiX9cvtwyXrdIn964BfedXHKGpC6o7mMPxEyC0kRPVi_EZs_MRV5bAPEpl5h5we0g== +0 -0
  314. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~qlhO_D9oE8uSKH-mZqyRF9pp4Zv1Tv0dIYcqrH4hb1VWlIxcdxmg2j0M8496cQeFXC5bn_JMXdBlD-d6cnFF8w== +0 -0
  315. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~tjpiyIxJR_boTdUNrtFDuKIZoY84fI4lA1oMJbq9e2ZmYKIK5FeRN2O8cV_yMOYJGr4lbv03kTmT70mCjUc2_Q== +0 -0
  316. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~wULeoj18eEKJWAKx1uFQVwS48cUGFcYPRJQj1Ro5XNJsWCwppGSCdIPhwifD6Z2f_j3zfI2SmC2Gg81sBXXW7g== +0 -0
  317. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~zrEihMys4NVV5rx6FmuzEGO2TjloI3OiC7yzIhvqYoRo43ibb2F-Km6Jf4NX-ac62pOLBYZRcjQTvYMpn75_oA== +0 -0
  318. package/Tests/Artifacts/LottieTests.xcresult/Info.plist +29 -0
  319. package/Tests/AutomaticEngineTests.swift +57 -0
  320. package/Tests/BundleTests.swift +25 -0
  321. package/Tests/DataURLTests.swift +64 -0
  322. package/Tests/ParsingTests.swift +42 -0
  323. package/Tests/PerformanceTests.swift +215 -0
  324. package/Tests/Samples/9squares_AlBoardman.json +1 -0
  325. package/Tests/Samples/Boat_Loader.json +1 -0
  326. package/Tests/Samples/HamburgerArrow.json +1 -0
  327. package/Tests/Samples/IconTransitions.json +1 -0
  328. package/Tests/Samples/Images/dog.png +0 -0
  329. package/Tests/Samples/Issues/issue_1403.json +1 -0
  330. package/Tests/Samples/Issues/issue_1407.json +1 -0
  331. package/Tests/Samples/Issues/issue_1488.json +1 -0
  332. package/Tests/Samples/Issues/issue_1505.json +1 -0
  333. package/Tests/Samples/Issues/issue_1628.json +1 -0
  334. package/Tests/Samples/Issues/pr_1536.json +1 -0
  335. package/Tests/Samples/Issues/pr_1563.json +8439 -0
  336. package/Tests/Samples/Issues/pr_1592.json +5527 -0
  337. package/Tests/Samples/Issues/pr_1599.json +738 -0
  338. package/Tests/Samples/Issues/pr_1604_1.json +1 -0
  339. package/Tests/Samples/Issues/pr_1604_2.json +1 -0
  340. package/Tests/Samples/LottieFiles/LICENSE.md +14 -0
  341. package/Tests/Samples/LottieFiles/bounce_strokes.json +1 -0
  342. package/Tests/Samples/LottieFiles/cactus.json +1 -0
  343. package/Tests/Samples/LottieFiles/dog_car_ride.json +1 -0
  344. package/Tests/Samples/LottieFiles/draft_icon.json +1 -0
  345. package/Tests/Samples/LottieFiles/gradient_1.json +1 -0
  346. package/Tests/Samples/LottieFiles/gradient_2.json +1 -0
  347. package/Tests/Samples/LottieFiles/gradient_pill.json +1 -0
  348. package/Tests/Samples/LottieFiles/gradient_shapes.json +1 -0
  349. package/Tests/Samples/LottieFiles/gradient_square.json +1 -0
  350. package/Tests/Samples/LottieFiles/growth.json +1 -0
  351. package/Tests/Samples/LottieFiles/infinity_loader.json +1 -0
  352. package/Tests/Samples/LottieFiles/loading_dots_1.json +1 -0
  353. package/Tests/Samples/LottieFiles/loading_dots_2.json +1 -0
  354. package/Tests/Samples/LottieFiles/loading_dots_3.json +1 -0
  355. package/Tests/Samples/LottieFiles/loading_gradient_strokes.json +1 -0
  356. package/Tests/Samples/LottieFiles/settings_slider.json +1 -0
  357. package/Tests/Samples/LottieFiles/shop.json +1 -0
  358. package/Tests/Samples/LottieFiles/step_loader.json +1 -0
  359. package/Tests/Samples/LottieLogo1.json +1 -0
  360. package/Tests/Samples/LottieLogo1_masked.json +1 -0
  361. package/Tests/Samples/LottieLogo2.json +1 -0
  362. package/Tests/Samples/MotionCorpse_Jrcanest.json +1 -0
  363. package/Tests/Samples/Nonanimating/BasicLayers.json +1 -0
  364. package/Tests/Samples/Nonanimating/DisableNodesTest.json +1 -0
  365. package/Tests/Samples/Nonanimating/FirstText.json +1 -0
  366. package/Tests/Samples/Nonanimating/GeometryTransformTest.json +1 -0
  367. package/Tests/Samples/Nonanimating/Text_AnimatedProperties.json +1 -0
  368. package/Tests/Samples/Nonanimating/Text_Glyph.json +1 -0
  369. package/Tests/Samples/Nonanimating/Text_NoAnimation.json +1 -0
  370. package/Tests/Samples/Nonanimating/Text_NoGlyph.json +1 -0
  371. package/Tests/Samples/Nonanimating/Zoom.json +1 -0
  372. package/Tests/Samples/Nonanimating/_dog.json +1 -0
  373. package/Tests/Samples/Nonanimating/base64Test.json +1 -0
  374. package/Tests/Samples/Nonanimating/blend_mode_test.json +1 -0
  375. package/Tests/Samples/Nonanimating/keypathTest.json +1 -0
  376. package/Tests/Samples/Nonanimating/verifyLineHeight.json +1 -0
  377. package/Tests/Samples/PinJump.json +1 -0
  378. package/Tests/Samples/Private/BrokenLottieFiles/growth_man.json +874 -0
  379. package/Tests/Samples/Private/BrokenLottieFiles/rocket.json +1 -0
  380. package/Tests/Samples/Private/China_EmptyState_Itinerary.json +1 -0
  381. package/Tests/Samples/Private/LoaderHourglass.json +12070 -0
  382. package/Tests/Samples/Private/README.md +7 -0
  383. package/Tests/Samples/Private/Urgency/alarm_animated.json +1 -0
  384. package/Tests/Samples/Private/Urgency/diamond_animated.json +1 -0
  385. package/Tests/Samples/Private/Urgency/eye_animated.json +1 -0
  386. package/Tests/Samples/Private/Urgency/light_bulb_animated.json +1 -0
  387. package/Tests/Samples/Private/Urgency/light_bulb_static.json +1 -0
  388. package/Tests/Samples/Private/Urgency/piggy_bank_static.json +1 -0
  389. package/Tests/Samples/Private/Urgency/price_tag_legacy.json +1 -0
  390. package/Tests/Samples/Private/Urgency/rausch_alarm.json +1 -0
  391. package/Tests/Samples/Private/Urgency/rausch_alert.json +1 -0
  392. package/Tests/Samples/Private/Urgency/rausch_clock.json +1 -0
  393. package/Tests/Samples/Private/Urgency/rausch_diamond.json +1 -0
  394. package/Tests/Samples/Private/Urgency/rausch_money.json +1 -0
  395. package/Tests/Samples/Private/Urgency/rausch_piggy_bank.json +1 -0
  396. package/Tests/Samples/Private/Urgency/rausch_tag.json +1 -0
  397. package/Tests/Samples/Private/Urgency/red_envelope_animated.json +1 -0
  398. package/Tests/Samples/Private/Urgency/tag_animated.json +1 -0
  399. package/Tests/Samples/Private/Urgency/trophy_animated.json +1 -0
  400. package/Tests/Samples/Private/Urgency/wings_key_animated.json +1 -0
  401. package/Tests/Samples/Private/_flexible.json +1 -0
  402. package/Tests/Samples/Private/aircover.json +1 -0
  403. package/Tests/Samples/Private/belo_spin_rausch.json +1 -0
  404. package/Tests/Samples/Private/celebration.json +2821 -0
  405. package/Tests/Samples/Private/checkbox.json +1 -0
  406. package/Tests/Samples/Private/checkbox_small.json +1 -0
  407. package/Tests/Samples/Private/getting_your_trip_ready.json +3540 -0
  408. package/Tests/Samples/Private/gradient_afternoon.json +1 -0
  409. package/Tests/Samples/Private/gradient_brand.json +1 -0
  410. package/Tests/Samples/Private/gradient_evening.json +1 -0
  411. package/Tests/Samples/Private/gradient_morning.json +1 -0
  412. package/Tests/Samples/Private/issue_1467.json +1 -0
  413. package/Tests/Samples/Private/loading_dots.json +1 -0
  414. package/Tests/Samples/Private/loading_dots_small.json +1 -0
  415. package/Tests/Samples/Private/payment_loader.json +1 -0
  416. package/Tests/Samples/Private/radio_button.json +1 -0
  417. package/Tests/Samples/Private/selfie_intro.json +1 -0
  418. package/Tests/Samples/Private/stepper_add.json +1 -0
  419. package/Tests/Samples/Private/stepper_subtract.json +1 -0
  420. package/Tests/Samples/Private/switch.json +1 -0
  421. package/Tests/Samples/Private/thumb.json +1 -0
  422. package/Tests/Samples/Private/toggle_no.json +1 -0
  423. package/Tests/Samples/Private/toggle_yes.json +1 -0
  424. package/Tests/Samples/Private/user_error_black_and_white.json +1 -0
  425. package/Tests/Samples/Private/user_error_cut_off.json +1 -0
  426. package/Tests/Samples/Switch.json +1 -0
  427. package/Tests/Samples/Switch_States.json +1 -0
  428. package/Tests/Samples/TwitterHeart.json +1 -0
  429. package/Tests/Samples/TwitterHeartButton.json +1 -0
  430. package/Tests/Samples/TypeFace/A.json +1 -0
  431. package/Tests/Samples/TypeFace/Apostrophe.json +1 -0
  432. package/Tests/Samples/TypeFace/B.json +1 -0
  433. package/Tests/Samples/TypeFace/BlinkingCursor.json +1 -0
  434. package/Tests/Samples/TypeFace/C.json +1 -0
  435. package/Tests/Samples/TypeFace/Colon.json +1 -0
  436. package/Tests/Samples/TypeFace/Comma.json +1 -0
  437. package/Tests/Samples/TypeFace/D.json +1 -0
  438. package/Tests/Samples/TypeFace/E.json +1 -0
  439. package/Tests/Samples/TypeFace/F.json +1 -0
  440. package/Tests/Samples/TypeFace/G.json +1 -0
  441. package/Tests/Samples/TypeFace/H.json +1 -0
  442. package/Tests/Samples/TypeFace/I.json +1 -0
  443. package/Tests/Samples/TypeFace/J.json +1 -0
  444. package/Tests/Samples/TypeFace/K.json +1 -0
  445. package/Tests/Samples/TypeFace/L.json +1 -0
  446. package/Tests/Samples/TypeFace/M.json +1 -0
  447. package/Tests/Samples/TypeFace/N.json +1 -0
  448. package/Tests/Samples/TypeFace/O.json +1 -0
  449. package/Tests/Samples/TypeFace/P.json +1 -0
  450. package/Tests/Samples/TypeFace/Q.json +1 -0
  451. package/Tests/Samples/TypeFace/R.json +1 -0
  452. package/Tests/Samples/TypeFace/S.json +1 -0
  453. package/Tests/Samples/TypeFace/T.json +1 -0
  454. package/Tests/Samples/TypeFace/U.json +1 -0
  455. package/Tests/Samples/TypeFace/V.json +1 -0
  456. package/Tests/Samples/TypeFace/W.json +1 -0
  457. package/Tests/Samples/TypeFace/X.json +1 -0
  458. package/Tests/Samples/TypeFace/Y.json +1 -0
  459. package/Tests/Samples/TypeFace/Z.json +1 -0
  460. package/Tests/Samples/Watermelon.json +1 -0
  461. package/Tests/Samples/setValueTest.json +1 -0
  462. package/Tests/Samples/timeremap.json +1 -0
  463. package/Tests/Samples/vcTransition1.json +1 -0
  464. package/Tests/Samples/vcTransition2.json +1 -0
  465. package/Tests/SnapshotConfiguration.swift +153 -0
  466. package/Tests/SnapshotTests.swift +265 -0
  467. package/Tests/Utils/Bundle+Module.swift +30 -0
  468. package/Tests/Utils/HardcodedFontProvider.swift +19 -0
  469. package/Tests/Utils/HardcodedImageProvider.swift +23 -0
  470. package/Tests/Utils/Snapshotting+presentationLayer.swift +47 -0
  471. package/Tests/ValueProvidersTests.swift +27 -0
  472. package/lottie-ios.podspec +12 -12
  473. package/package.json +1 -1
  474. package/script/lint/airbnb.swiftformat +68 -0
  475. package/script/lint/swiftlint.yml +38 -0
  476. package/script/test-carthage/Cartfile +1 -0
  477. package/script/test-carthage/Cartfile.resolved +1 -0
  478. package/script/test-carthage/Carthage/Build/.lottie-ios.version +19 -0
  479. package/script/test-carthage/Carthage/Build/Lottie.xcframework/Info.plist +46 -0
  480. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/BCSymbolMaps/BF971162-BE99-3507-B5B3-11947DC6B176.bcsymbolmap +14778 -0
  481. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Headers/Lottie-Swift.h +673 -0
  482. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Info.plist +0 -0
  483. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Lottie +0 -0
  484. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Modules/Lottie.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  485. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Modules/Lottie.swiftmodule/arm64-apple-ios.swiftmodule +0 -0
  486. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Modules/Lottie.swiftmodule/arm64.swiftdoc +0 -0
  487. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Modules/Lottie.swiftmodule/arm64.swiftmodule +0 -0
  488. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Modules/module.modulemap +4 -0
  489. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/dSYMs/Lottie.framework.dSYM/Contents/Info.plist +20 -0
  490. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/dSYMs/Lottie.framework.dSYM/Contents/Resources/DWARF/Lottie +0 -0
  491. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Headers/Lottie-Swift.h +1352 -0
  492. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Info.plist +0 -0
  493. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Lottie +0 -0
  494. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo +0 -0
  495. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/Project/arm64.swiftsourceinfo +0 -0
  496. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo +0 -0
  497. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/Project/x86_64.swiftsourceinfo +0 -0
  498. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  499. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/arm64-apple-ios-simulator.swiftmodule +0 -0
  500. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/arm64.swiftdoc +0 -0
  501. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/arm64.swiftmodule +0 -0
  502. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  503. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/x86_64-apple-ios-simulator.swiftmodule +0 -0
  504. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/x86_64.swiftdoc +0 -0
  505. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/x86_64.swiftmodule +0 -0
  506. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/module.modulemap +4 -0
  507. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/_CodeSignature/CodeResources +256 -0
  508. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/dSYMs/Lottie.framework.dSYM/Contents/Info.plist +20 -0
  509. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/dSYMs/Lottie.framework.dSYM/Contents/Resources/DWARF/Lottie +0 -0
  510. package/script/test-carthage/Carthage/Checkouts/lottie-ios/Lottie.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  511. package/script/test-carthage/Carthage/Checkouts/lottie-ios/Lottie.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +37 -0
  512. package/script/test-carthage/Carthage/Checkouts/lottie-ios/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  513. package/script/test-carthage/CarthageTest/AppDelegate.swift +27 -0
  514. package/script/test-carthage/CarthageTest/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  515. package/script/test-carthage/CarthageTest/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
  516. package/script/test-carthage/CarthageTest/Assets.xcassets/Contents.json +6 -0
  517. package/script/test-carthage/CarthageTest/Base.lproj/LaunchScreen.storyboard +25 -0
  518. package/script/test-carthage/CarthageTest/Base.lproj/Main.storyboard +24 -0
  519. package/script/test-carthage/CarthageTest/Info.plist +66 -0
  520. package/script/test-carthage/CarthageTest/SceneDelegate.swift +10 -0
  521. package/script/test-carthage/CarthageTest/ViewController.swift +15 -0
  522. package/script/test-carthage/CarthageTest.xcodeproj/project.pbxproj +378 -0
  523. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  524. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  525. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  526. package/script/test-carthage/CarthageTest.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  527. package/script/test-carthage/Mintfile +1 -0
  528. package/script/test-spm/LottieSPM.xcworkspace/contents.xcworkspacedata +7 -0
  529. package/script/test-spm/LottieSPM.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  530. package/script/test-spm/Mintfile +1 -0
  531. package/.swiftpm/xcode/package.xcworkspace/xcuserdata/brandonwithrow.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  532. package/Lottie/Info.plist +0 -22
  533. package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/brandonwithrow.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  534. package/Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad/xcschemes/LottieLibraryMacOS.xcscheme +0 -80
  535. package/Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad/xcschemes/xcschememanagement.plist +0 -57
  536. package/lottie-swift/Assets/.gitkeep +0 -0
  537. package/lottie-swift/src/Private/LayerContainers/Utility/LayerFontProvider.swift +0 -37
  538. package/lottie-swift/src/Private/LayerContainers/Utility/LayerTextProvider.swift +0 -36
  539. package/lottie-swift/src/Private/Model/Animation.swift +0 -107
  540. package/lottie-swift/src/Private/Model/Assets/Asset.swift +0 -27
  541. package/lottie-swift/src/Private/Model/Assets/ImageAsset.swift +0 -48
  542. package/lottie-swift/src/Private/Model/Keyframes/Keyframe.swift +0 -128
  543. package/lottie-swift/src/Private/Model/Keyframes/KeyframeGroup.swift +0 -108
  544. package/lottie-swift/src/Private/Model/Layers/LayerModel.swift +0 -150
  545. package/lottie-swift/src/Private/Model/Objects/DashPattern.swift +0 -24
  546. package/lottie-swift/src/Private/Model/Objects/Marker.swift +0 -23
  547. package/lottie-swift/src/Private/Model/Objects/Mask.swift +0 -48
  548. package/lottie-swift/src/Private/Model/Objects/Transform.swift +0 -105
  549. package/lottie-swift/src/Private/Model/ShapeItems/Ellipse.swift +0 -50
  550. package/lottie-swift/src/Private/Model/ShapeItems/FillI.swift +0 -49
  551. package/lottie-swift/src/Private/Model/ShapeItems/GradientFill.swift +0 -86
  552. package/lottie-swift/src/Private/Model/ShapeItems/GradientStroke.swift +0 -125
  553. package/lottie-swift/src/Private/Model/ShapeItems/Rectangle.swift +0 -50
  554. package/lottie-swift/src/Private/Model/ShapeItems/Repeater.swift +0 -80
  555. package/lottie-swift/src/Private/Model/ShapeItems/Shape.swift +0 -37
  556. package/lottie-swift/src/Private/Model/ShapeItems/ShapeItem.swift +0 -95
  557. package/lottie-swift/src/Private/Model/ShapeItems/ShapeTransform.swift +0 -68
  558. package/lottie-swift/src/Private/Model/ShapeItems/Star.swift +0 -86
  559. package/lottie-swift/src/Private/Model/ShapeItems/Stroke.swift +0 -67
  560. package/lottie-swift/src/Private/Model/ShapeItems/Trim.swift +0 -53
  561. package/lottie-swift/src/Private/Model/Text/Font.swift +0 -35
  562. package/lottie-swift/src/Private/Model/Text/TextAnimator.swift +0 -99
  563. package/lottie-swift/src/Private/Model/Text/TextDocument.swift +0 -70
  564. package/lottie-swift/src/Private/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +0 -109
  565. package/lottie-swift/src/Private/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +0 -132
  566. package/lottie-swift/src/Private/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +0 -141
  567. package/lottie-swift/src/Private/Utility/Extensions/MathKit.swift +0 -539
  568. package/lottie-swift/src/Private/Utility/Extensions/StringExtensions.swift +0 -32
  569. package/lottie-swift/src/Private/Utility/Interpolatable/Interpolatable.swift +0 -18
  570. package/lottie-swift/src/Private/Utility/Interpolatable/InterpolatableExtensions.swift +0 -170
  571. package/lottie-swift/src/Private/Utility/Primitives/CurveVertex.swift +0 -177
  572. package/lottie-swift/src/Private/Utility/Primitives/PathElement.swift +0 -68
  573. package/lottie-swift/src/Private/Utility/Primitives/VectorsExtensions.swift +0 -218
  574. package/lottie-swift/src/Public/Animation/AnimationPublic.swift +0 -196
  575. package/lottie-swift/src/Public/Animation/AnimationView.swift +0 -1007
  576. package/lottie-swift/src/Public/Animation/AnimationViewInitializers.swift +0 -83
  577. package/lottie-swift/src/Public/AnimationCache/AnimationCacheProvider.swift +0 -24
  578. package/lottie-swift/src/Public/DynamicProperties/AnimationKeypath.swift +0 -46
  579. package/lottie-swift/src/Public/DynamicProperties/AnyValueProvider.swift +0 -29
  580. package/lottie-swift/src/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +0 -114
  581. package/lottie-swift/src/Public/ImageProvider/AnimationImageProvider.swift +0 -23
  582. package/lottie-swift/src/Public/MacOS/FilepathImageProvider.swift +0 -67
  583. package/lottie-swift/src/Public/TextProvider/AnimationTextProvider.swift +0 -39
  584. package/lottie-swift/src/Public/iOS/LottieView.swift +0 -62
  585. package/lottie-swift-testing.podspec +0 -32
@@ -0,0 +1,1315 @@
1
+ //
2
+ // AnimationView.swift
3
+ // lottie-swift
4
+ //
5
+ // Created by Brandon Withrow on 1/23/19.
6
+ //
7
+
8
+ import Foundation
9
+ import QuartzCore
10
+
11
+ // MARK: - LottieBackgroundBehavior
12
+
13
+ /// Describes the behavior of an AnimationView when the app is moved to the background.
14
+ public enum LottieBackgroundBehavior {
15
+ /// Stop the animation and reset it to the beginning of its current play time. The completion block is called.
16
+ case stop
17
+
18
+ /// Pause the animation in its current state. The completion block is called.
19
+ /// - This is the default when using the Main Thread rendering engine.
20
+ case pause
21
+
22
+ /// Pause the animation and restart it when the application moves to the foreground. The completion block is stored and called when the animation completes.
23
+ case pauseAndRestore
24
+
25
+ /// Stops the animation and sets it to the end of its current play time. The completion block is called.
26
+ case forceFinish
27
+
28
+ /// The animation continues playing in the background.
29
+ /// - This is the default when using the Core Animation rendering engine.
30
+ /// Playing an animation using the Core Animation engine doesn't come with any CPU overhead,
31
+ /// so using `.continuePlaying` avoids the need to stop and then resume the animation
32
+ /// (which does come with some CPU overhead).
33
+ /// - This mode should not be used with the Main Thread rendering engine.
34
+ case continuePlaying
35
+
36
+ // MARK: Public
37
+
38
+ /// The default background behavior, based on the rendering engine being used to play the animation.
39
+ /// - Playing an animation using the Main Thread rendering engine comes with CPU overhead,
40
+ /// so the animation should be paused or stopped when the `AnimationView` is not visible.
41
+ /// - Playing an animation using the Core Animation rendering engine does not come with any
42
+ /// CPU overhead, so these animations do not need to be paused in the background.
43
+ public static func `default`(for renderingEngine: RenderingEngine) -> LottieBackgroundBehavior {
44
+ switch renderingEngine {
45
+ case .mainThread:
46
+ return .pause
47
+ case .coreAnimation:
48
+ return .continuePlaying
49
+ }
50
+ }
51
+ }
52
+
53
+ // MARK: - LottieLoopMode
54
+
55
+ /// Defines animation loop behavior
56
+ public enum LottieLoopMode {
57
+ /// Animation is played once then stops.
58
+ case playOnce
59
+ /// Animation will loop from beginning to end until stopped.
60
+ case loop
61
+ /// Animation will play forward, then backwards and loop until stopped.
62
+ case autoReverse
63
+ /// Animation will loop from beginning to end up to defined amount of times.
64
+ case `repeat`(Float)
65
+ /// Animation will play forward, then backwards a defined amount of times.
66
+ case repeatBackwards(Float)
67
+ }
68
+
69
+ // MARK: Equatable
70
+
71
+ extension LottieLoopMode: Equatable {
72
+ public static func == (lhs: LottieLoopMode, rhs: LottieLoopMode) -> Bool {
73
+ switch (lhs, rhs) {
74
+ case (.repeat(let lhsAmount), .repeat(let rhsAmount)),
75
+ (.repeatBackwards(let lhsAmount), .repeatBackwards(let rhsAmount)):
76
+ return lhsAmount == rhsAmount
77
+ case (.playOnce, .playOnce),
78
+ (.loop, .loop),
79
+ (.autoReverse, .autoReverse):
80
+ return true
81
+ default:
82
+ return false
83
+ }
84
+ }
85
+ }
86
+
87
+ // MARK: - AnimationView
88
+
89
+ @IBDesignable
90
+ final public class AnimationView: AnimationViewBase {
91
+
92
+ // MARK: Lifecycle
93
+
94
+ // MARK: - Public (Initializers)
95
+
96
+ /// Initializes an AnimationView with an animation.
97
+ public init(
98
+ animation: Animation?,
99
+ imageProvider: AnimationImageProvider? = nil,
100
+ textProvider: AnimationTextProvider = DefaultTextProvider(),
101
+ fontProvider: AnimationFontProvider = DefaultFontProvider(),
102
+ configuration: LottieConfiguration = .shared,
103
+ logger: LottieLogger = .shared)
104
+ {
105
+ self.animation = animation
106
+ self.imageProvider = imageProvider ?? BundleImageProvider(bundle: Bundle.main, searchPath: nil)
107
+ self.textProvider = textProvider
108
+ self.fontProvider = fontProvider
109
+ self.configuration = configuration
110
+ self.logger = logger
111
+ super.init(frame: .zero)
112
+ commonInit()
113
+ makeAnimationLayer(usingEngine: configuration.renderingEngine)
114
+ if let animation = animation {
115
+ frame = animation.bounds
116
+ }
117
+ }
118
+
119
+ public init(
120
+ configuration: LottieConfiguration = .shared,
121
+ logger: LottieLogger = .shared)
122
+ {
123
+ animation = nil
124
+ imageProvider = BundleImageProvider(bundle: Bundle.main, searchPath: nil)
125
+ textProvider = DefaultTextProvider()
126
+ fontProvider = DefaultFontProvider()
127
+ self.configuration = configuration
128
+ self.logger = logger
129
+ super.init(frame: .zero)
130
+ commonInit()
131
+ }
132
+
133
+ public override init(frame: CGRect) {
134
+ animation = nil
135
+ imageProvider = BundleImageProvider(bundle: Bundle.main, searchPath: nil)
136
+ textProvider = DefaultTextProvider()
137
+ fontProvider = DefaultFontProvider()
138
+ configuration = .shared
139
+ logger = .shared
140
+ super.init(frame: frame)
141
+ commonInit()
142
+ }
143
+
144
+ required public init?(coder aDecoder: NSCoder) {
145
+ imageProvider = BundleImageProvider(bundle: Bundle.main, searchPath: nil)
146
+ textProvider = DefaultTextProvider()
147
+ fontProvider = DefaultFontProvider()
148
+ configuration = .shared
149
+ logger = .shared
150
+ super.init(coder: aDecoder)
151
+ commonInit()
152
+ }
153
+
154
+ // MARK: Public
155
+
156
+ /// The configuration that this `AnimationView` uses when playing its animation
157
+ public let configuration: LottieConfiguration
158
+
159
+ /// Value Providers that have been registered using `setValueProvider(_:keypath:)`
160
+ public private(set) var valueProviders = [AnimationKeypath: AnyValueProvider]()
161
+
162
+ /// Describes the behavior of an AnimationView when the app is moved to the background.
163
+ ///
164
+ /// The default for the Main Thread animation engine is `pause`,
165
+ /// which pauses the animation when the application moves to
166
+ /// the background. This prevents the animation from consuming CPU
167
+ /// resources when not on-screen. The completion block is called with
168
+ /// `false` for completed.
169
+ ///
170
+ /// The default for the Core Animation engine is `continuePlaying`,
171
+ /// since the Core Animation engine does not have any CPU overhead.
172
+ public var backgroundBehavior: LottieBackgroundBehavior {
173
+ get {
174
+ let currentBackgroundBehavior = _backgroundBehavior ?? .default(for: currentRenderingEngine ?? .mainThread)
175
+
176
+ if
177
+ currentRenderingEngine == .mainThread,
178
+ _backgroundBehavior == .continuePlaying
179
+ {
180
+ logger.assertionFailure("""
181
+ `LottieBackgroundBehavior.continuePlaying` should not be used with the Main Thread
182
+ rendering engine, since this would waste CPU resources on playing an animation
183
+ that is not visible. Consider using a different background mode, or switching to
184
+ the Core Animation rendering engine (which does not have any CPU overhead).
185
+ """)
186
+ }
187
+
188
+ return currentBackgroundBehavior
189
+ }
190
+ set {
191
+ _backgroundBehavior = newValue
192
+ }
193
+ }
194
+
195
+ /// Sets the animation backing the animation view. Setting this will clear the
196
+ /// view's contents, completion blocks and current state. The new animation will
197
+ /// be loaded up and set to the beginning of its timeline.
198
+ public var animation: Animation? {
199
+ didSet {
200
+ makeAnimationLayer(usingEngine: configuration.renderingEngine)
201
+ }
202
+ }
203
+
204
+ /// Sets the image provider for the animation view. An image provider provides the
205
+ /// animation with its required image data.
206
+ ///
207
+ /// Setting this will cause the animation to reload its image contents.
208
+ public var imageProvider: AnimationImageProvider {
209
+ didSet {
210
+ animationLayer?.imageProvider = imageProvider.cachedImageProvider
211
+ reloadImages()
212
+ }
213
+ }
214
+
215
+ /// Sets the text provider for animation view. A text provider provides the
216
+ /// animation with values for text layers
217
+ public var textProvider: AnimationTextProvider {
218
+ didSet {
219
+ animationLayer?.textProvider = textProvider
220
+ }
221
+ }
222
+
223
+ /// Sets the text provider for animation view. A text provider provides the
224
+ /// animation with values for text layers
225
+ public var fontProvider: AnimationFontProvider {
226
+ didSet {
227
+ animationLayer?.fontProvider = fontProvider
228
+ }
229
+ }
230
+
231
+ /// Returns `true` if the animation is currently playing.
232
+ public var isAnimationPlaying: Bool {
233
+ guard let animationLayer = animationLayer else {
234
+ return false
235
+ }
236
+
237
+ if let valueFromLayer = animationLayer.isAnimationPlaying {
238
+ return valueFromLayer
239
+ } else {
240
+ return animationLayer.animation(forKey: activeAnimationName) != nil
241
+ }
242
+ }
243
+
244
+ /// Returns `true` if the animation will start playing when this view is added to a window.
245
+ public var isAnimationQueued: Bool {
246
+ animationContext != nil && waitingToPlayAnimation
247
+ }
248
+
249
+ /// Sets the loop behavior for `play` calls. Defaults to `playOnce`
250
+ public var loopMode: LottieLoopMode = .playOnce {
251
+ didSet {
252
+ updateInFlightAnimation()
253
+ }
254
+ }
255
+
256
+ /// When `true` the animation view will rasterize its contents when not animating.
257
+ /// Rasterizing will improve performance of static animations.
258
+ ///
259
+ /// Note: this will not produce crisp results at resolutions above the animations natural resolution.
260
+ ///
261
+ /// Defaults to `false`
262
+ public var shouldRasterizeWhenIdle = false {
263
+ didSet {
264
+ updateRasterizationState()
265
+ }
266
+ }
267
+
268
+ /// Sets the current animation time with a Progress Time
269
+ ///
270
+ /// Note: Setting this will stop the current animation, if any.
271
+ /// Note 2: If `animation` is nil, setting this will fallback to 0
272
+ public var currentProgress: AnimationProgressTime {
273
+ set {
274
+ if let animation = animation {
275
+ currentFrame = animation.frameTime(forProgress: newValue)
276
+ } else {
277
+ currentFrame = 0
278
+ }
279
+ }
280
+ get {
281
+ if let animation = animation {
282
+ return animation.progressTime(forFrame: currentFrame)
283
+ } else {
284
+ return 0
285
+ }
286
+ }
287
+ }
288
+
289
+ /// Sets the current animation time with a time in seconds.
290
+ ///
291
+ /// Note: Setting this will stop the current animation, if any.
292
+ /// Note 2: If `animation` is nil, setting this will fallback to 0
293
+ public var currentTime: TimeInterval {
294
+ set {
295
+ if let animation = animation {
296
+ currentFrame = animation.frameTime(forTime: newValue)
297
+ } else {
298
+ currentFrame = 0
299
+ }
300
+ }
301
+ get {
302
+ if let animation = animation {
303
+ return animation.time(forFrame: currentFrame)
304
+ } else {
305
+ return 0
306
+ }
307
+ }
308
+ }
309
+
310
+ /// Sets the current animation time with a frame in the animations framerate.
311
+ ///
312
+ /// Note: Setting this will stop the current animation, if any.
313
+ public var currentFrame: AnimationFrameTime {
314
+ set {
315
+ removeCurrentAnimationIfNecessary()
316
+ updateAnimationFrame(newValue)
317
+ }
318
+ get {
319
+ animationLayer?.currentFrame ?? 0
320
+ }
321
+ }
322
+
323
+ /// Returns the current animation frame while an animation is playing.
324
+ public var realtimeAnimationFrame: AnimationFrameTime {
325
+ isAnimationPlaying ? animationLayer?.presentation()?.currentFrame ?? currentFrame : currentFrame
326
+ }
327
+
328
+ /// Returns the current animation frame while an animation is playing.
329
+ public var realtimeAnimationProgress: AnimationProgressTime {
330
+ if let animation = animation {
331
+ return animation.progressTime(forFrame: realtimeAnimationFrame)
332
+ }
333
+ return 0
334
+ }
335
+
336
+ /// Sets the speed of the animation playback. Defaults to 1
337
+ public var animationSpeed: CGFloat = 1 {
338
+ didSet {
339
+ updateInFlightAnimation()
340
+ }
341
+ }
342
+
343
+ /// When `true` the animation will play back at the framerate encoded in the
344
+ /// `Animation` model. When `false` the animation will play at the framerate
345
+ /// of the device.
346
+ ///
347
+ /// Defaults to false
348
+ public var respectAnimationFrameRate = false {
349
+ didSet {
350
+ animationLayer?.respectAnimationFrameRate = respectAnimationFrameRate
351
+ }
352
+ }
353
+
354
+ /// Controls the cropping of an Animation. Setting this property will crop the animation
355
+ /// to the current views bounds by the viewport frame. The coordinate space is specified
356
+ /// in the animation's coordinate space.
357
+ ///
358
+ /// Animatable.
359
+ public var viewportFrame: CGRect? = nil {
360
+ didSet {
361
+
362
+ // This is really ugly, but is needed to trigger a layout pass within an animation block.
363
+ // Typically this happens automatically, when layout objects are UIView based.
364
+ // The animation layer is a CALayer which will not implicitly grab the animation
365
+ // duration of a UIView animation block.
366
+ //
367
+ // By setting bounds and then resetting bounds the UIView animation block's
368
+ // duration and curve are captured and added to the layer. This is used in the
369
+ // layout block to animate the animationLayer's position and size.
370
+ let rect = bounds
371
+ self.bounds = CGRect.zero
372
+ self.bounds = rect
373
+ self.setNeedsLayout()
374
+ }
375
+ }
376
+
377
+ override public var intrinsicContentSize: CGSize {
378
+ if let animation = animation {
379
+ return animation.bounds.size
380
+ }
381
+ return .zero
382
+ }
383
+
384
+ /// The rendering engine currently being used by this view.
385
+ /// - This will only be `nil` in cases where the configuration is `automatic`
386
+ /// but a `RootAnimationLayer` hasn't been constructed yet
387
+ public var currentRenderingEngine: RenderingEngine? {
388
+ switch configuration.renderingEngine {
389
+ case .specific(let engine):
390
+ return engine
391
+
392
+ case .automatic:
393
+ guard let animationLayer = animationLayer else {
394
+ return nil
395
+ }
396
+
397
+ if animationLayer is CoreAnimationLayer {
398
+ return .coreAnimation
399
+ } else {
400
+ return .mainThread
401
+ }
402
+ }
403
+ }
404
+
405
+ /// Plays the animation from its current state to the end.
406
+ ///
407
+ /// - Parameter completion: An optional completion closure to be called when the animation completes playing.
408
+ public func play(completion: LottieCompletionBlock? = nil) {
409
+ guard let animation = animation else {
410
+ return
411
+ }
412
+
413
+ /// Build a context for the animation.
414
+ let context = AnimationContext(
415
+ playFrom: CGFloat(animation.startFrame),
416
+ playTo: CGFloat(animation.endFrame),
417
+ closure: completion)
418
+ removeCurrentAnimationIfNecessary()
419
+ addNewAnimationForContext(context)
420
+ }
421
+
422
+ /// Plays the animation from a progress (0-1) to a progress (0-1).
423
+ ///
424
+ /// - Parameter fromProgress: The start progress of the animation. If `nil` the animation will start at the current progress.
425
+ /// - Parameter toProgress: The end progress of the animation.
426
+ /// - Parameter loopMode: The loop behavior of the animation. If `nil` the view's `loopMode` property will be used.
427
+ /// - Parameter completion: An optional completion closure to be called when the animation stops.
428
+ public func play(
429
+ fromProgress: AnimationProgressTime? = nil,
430
+ toProgress: AnimationProgressTime,
431
+ loopMode: LottieLoopMode? = nil,
432
+ completion: LottieCompletionBlock? = nil)
433
+ {
434
+ guard let animation = animation else {
435
+ return
436
+ }
437
+
438
+ removeCurrentAnimationIfNecessary()
439
+ if let loopMode = loopMode {
440
+ /// Set the loop mode, if one was supplied
441
+ self.loopMode = loopMode
442
+ }
443
+ let context = AnimationContext(
444
+ playFrom: animation.frameTime(forProgress: fromProgress ?? currentProgress),
445
+ playTo: animation.frameTime(forProgress: toProgress),
446
+ closure: completion)
447
+ addNewAnimationForContext(context)
448
+ }
449
+
450
+ /// Plays the animation from a start frame to an end frame in the animation's framerate.
451
+ ///
452
+ /// - Parameter fromFrame: The start frame of the animation. If `nil` the animation will start at the current frame.
453
+ /// - Parameter toFrame: The end frame of the animation.
454
+ /// - Parameter loopMode: The loop behavior of the animation. If `nil` the view's `loopMode` property will be used.
455
+ /// - Parameter completion: An optional completion closure to be called when the animation stops.
456
+ public func play(
457
+ fromFrame: AnimationFrameTime? = nil,
458
+ toFrame: AnimationFrameTime,
459
+ loopMode: LottieLoopMode? = nil,
460
+ completion: LottieCompletionBlock? = nil)
461
+ {
462
+ removeCurrentAnimationIfNecessary()
463
+ if let loopMode = loopMode {
464
+ /// Set the loop mode, if one was supplied
465
+ self.loopMode = loopMode
466
+ }
467
+
468
+ let context = AnimationContext(
469
+ playFrom: fromFrame ?? currentProgress,
470
+ playTo: toFrame,
471
+ closure: completion)
472
+ addNewAnimationForContext(context)
473
+ }
474
+
475
+ /// Plays the animation from a named marker to another marker.
476
+ ///
477
+ /// Markers are point in time that are encoded into the Animation data and assigned
478
+ /// a name.
479
+ ///
480
+ /// NOTE: If markers are not found the play command will exit.
481
+ ///
482
+ /// - Parameter fromMarker: The start marker for the animation playback. If `nil` the
483
+ /// animation will start at the current progress.
484
+ /// - Parameter toMarker: The end marker for the animation playback.
485
+ /// - Parameter loopMode: The loop behavior of the animation. If `nil` the view's `loopMode` property will be used.
486
+ /// - Parameter completion: An optional completion closure to be called when the animation stops.
487
+ public func play(
488
+ fromMarker: String? = nil,
489
+ toMarker: String,
490
+ loopMode: LottieLoopMode? = nil,
491
+ completion: LottieCompletionBlock? = nil)
492
+ {
493
+
494
+ guard let animation = animation, let markers = animation.markerMap, let to = markers[toMarker] else {
495
+ return
496
+ }
497
+
498
+ removeCurrentAnimationIfNecessary()
499
+ if let loopMode = loopMode {
500
+ /// Set the loop mode, if one was supplied
501
+ self.loopMode = loopMode
502
+ }
503
+
504
+ let fromTime: CGFloat
505
+ if let fromName = fromMarker, let from = markers[fromName] {
506
+ fromTime = CGFloat(from.frameTime)
507
+ } else {
508
+ fromTime = currentFrame
509
+ }
510
+
511
+ let context = AnimationContext(
512
+ playFrom: fromTime,
513
+ playTo: CGFloat(to.frameTime),
514
+ closure: completion)
515
+ addNewAnimationForContext(context)
516
+ }
517
+
518
+ /// Stops the animation and resets the view to its start frame.
519
+ ///
520
+ /// The completion closure will be called with `false`
521
+ public func stop() {
522
+ removeCurrentAnimation()
523
+ currentFrame = 0
524
+ }
525
+
526
+ /// Pauses the animation in its current state.
527
+ ///
528
+ /// The completion closure will be called with `false`
529
+ public func pause() {
530
+ removeCurrentAnimation()
531
+ }
532
+
533
+ /// Reloads the images supplied to the animation from the `imageProvider`
534
+ public func reloadImages() {
535
+ animationLayer?.reloadImages()
536
+ }
537
+
538
+ /// Forces the AnimationView to redraw its contents.
539
+ public func forceDisplayUpdate() {
540
+ animationLayer?.forceDisplayUpdate()
541
+ }
542
+
543
+ /// Sets a ValueProvider for the specified keypath. The value provider will be set
544
+ /// on all properties that match the keypath.
545
+ ///
546
+ /// Nearly all properties of a Lottie animation can be changed at runtime using a
547
+ /// combination of `Animation Keypaths` and `Value Providers`.
548
+ /// Setting a ValueProvider on a keypath will cause the animation to update its
549
+ /// contents and read the new Value Provider.
550
+ ///
551
+ /// A value provider provides a typed value on a frame by frame basis.
552
+ ///
553
+ /// - Parameter valueProvider: The new value provider for the properties.
554
+ /// - Parameter keypath: The keypath used to search for properties.
555
+ ///
556
+ /// Example:
557
+ /// ```
558
+ /// /// A keypath that finds the color value for all `Fill 1` nodes.
559
+ /// let fillKeypath = AnimationKeypath(keypath: "**.Fill 1.Color")
560
+ /// /// A Color Value provider that returns a reddish color.
561
+ /// let redValueProvider = ColorValueProvider(Color(r: 1, g: 0.2, b: 0.3, a: 1))
562
+ /// /// Set the provider on the animationView.
563
+ /// animationView.setValueProvider(redValueProvider, keypath: fillKeypath)
564
+ /// ```
565
+ public func setValueProvider(_ valueProvider: AnyValueProvider, keypath: AnimationKeypath) {
566
+ guard let animationLayer = animationLayer else { return }
567
+
568
+ valueProviders[keypath] = valueProvider
569
+ animationLayer.setValueProvider(valueProvider, keypath: keypath)
570
+ }
571
+
572
+ /// Reads the value of a property specified by the Keypath.
573
+ /// Returns nil if no property is found.
574
+ ///
575
+ /// - Parameter for: The keypath used to search for the property.
576
+ /// - Parameter atFrame: The Frame Time of the value to query. If nil then the current frame is used.
577
+ public func getValue(for keypath: AnimationKeypath, atFrame: AnimationFrameTime?) -> Any? {
578
+ animationLayer?.getValue(for: keypath, atFrame: atFrame)
579
+ }
580
+
581
+ /// Reads the original value of a property specified by the Keypath.
582
+ /// This will ignore any value providers and can be useful when implementing a value providers that makes change to the original value from the animation.
583
+ /// Returns nil if no property is found.
584
+ ///
585
+ /// - Parameter for: The keypath used to search for the property.
586
+ /// - Parameter atFrame: The Frame Time of the value to query. If nil then the current frame is used.
587
+ public func getOriginalValue(for keypath: AnimationKeypath, atFrame: AnimationFrameTime?) -> Any? {
588
+ animationLayer?.getOriginalValue(for: keypath, atFrame: atFrame)
589
+ }
590
+
591
+ /// Logs all child keypaths.
592
+ public func logHierarchyKeypaths() {
593
+ animationLayer?.logHierarchyKeypaths()
594
+ }
595
+
596
+ /// Searches for the nearest child layer to the first Keypath and adds the subview
597
+ /// to that layer. The subview will move and animate with the child layer.
598
+ /// Furthermore the subview will be in the child layers coordinate space.
599
+ ///
600
+ /// Note: if no layer is found for the keypath, then nothing happens.
601
+ ///
602
+ /// - Parameter subview: The subview to add to the found animation layer.
603
+ /// - Parameter keypath: The keypath used to find the animation layer.
604
+ ///
605
+ /// Example:
606
+ /// ```
607
+ /// /// A keypath that finds `Layer 1`
608
+ /// let layerKeypath = AnimationKeypath(keypath: "Layer 1")
609
+ ///
610
+ /// /// Wrap the custom view in an `AnimationSubview`
611
+ /// let subview = AnimationSubview()
612
+ /// subview.addSubview(customView)
613
+ ///
614
+ /// /// Set the provider on the animationView.
615
+ /// animationView.addSubview(subview, forLayerAt: layerKeypath)
616
+ /// ```
617
+ public func addSubview(_ subview: AnimationSubview, forLayerAt keypath: AnimationKeypath) {
618
+ guard let sublayer = animationLayer?.layer(for: keypath) else {
619
+ return
620
+ }
621
+ setNeedsLayout()
622
+ layoutIfNeeded()
623
+ forceDisplayUpdate()
624
+ addSubview(subview)
625
+ if let subViewLayer = subview.viewLayer {
626
+ sublayer.addSublayer(subViewLayer)
627
+ }
628
+ }
629
+
630
+ /// Converts a CGRect from the AnimationView's coordinate space into the
631
+ /// coordinate space of the layer found at Keypath.
632
+ ///
633
+ /// If no layer is found, nil is returned
634
+ ///
635
+ /// - Parameter rect: The CGRect to convert.
636
+ /// - Parameter toLayerAt: The keypath used to find the layer.
637
+ public func convert(_ rect: CGRect, toLayerAt keypath: AnimationKeypath?) -> CGRect? {
638
+ guard let animationLayer = animationLayer else { return nil }
639
+ guard let keypath = keypath else {
640
+ return viewLayer?.convert(rect, to: animationLayer)
641
+ }
642
+ guard let sublayer = animationLayer.layer(for: keypath) else {
643
+ return nil
644
+ }
645
+ setNeedsLayout()
646
+ layoutIfNeeded()
647
+ forceDisplayUpdate()
648
+ return animationLayer.convert(rect, to: sublayer)
649
+ }
650
+
651
+ /// Converts a CGPoint from the AnimationView's coordinate space into the
652
+ /// coordinate space of the layer found at Keypath.
653
+ ///
654
+ /// If no layer is found, nil is returned
655
+ ///
656
+ /// - Parameter point: The CGPoint to convert.
657
+ /// - Parameter toLayerAt: The keypath used to find the layer.
658
+ public func convert(_ point: CGPoint, toLayerAt keypath: AnimationKeypath?) -> CGPoint? {
659
+ guard let animationLayer = animationLayer else { return nil }
660
+ guard let keypath = keypath else {
661
+ return viewLayer?.convert(point, to: animationLayer)
662
+ }
663
+ guard let sublayer = animationLayer.layer(for: keypath) else {
664
+ return nil
665
+ }
666
+ setNeedsLayout()
667
+ layoutIfNeeded()
668
+ forceDisplayUpdate()
669
+ return animationLayer.convert(point, to: sublayer)
670
+ }
671
+
672
+ /// Sets the enabled state of all animator nodes found with the keypath search.
673
+ /// This can be used to interactively enable / disable parts of the animation.
674
+ ///
675
+ /// - Parameter isEnabled: When true the animator nodes affect the rendering tree. When false the node is removed from the tree.
676
+ /// - Parameter keypath: The keypath used to find the node(s).
677
+ public func setNodeIsEnabled(isEnabled: Bool, keypath: AnimationKeypath) {
678
+ guard let animationLayer = animationLayer else { return }
679
+ let nodes = animationLayer.animatorNodes(for: keypath)
680
+ if let nodes = nodes {
681
+ for node in nodes {
682
+ node.isEnabled = isEnabled
683
+ }
684
+ forceDisplayUpdate()
685
+ }
686
+ }
687
+
688
+ /// Markers are a way to describe a point in time by a key name.
689
+ ///
690
+ /// Markers are encoded into animation JSON. By using markers a designer can mark
691
+ /// playback points for a developer to use without having to worry about keeping
692
+ /// track of animation frames. If the animation file is updated, the developer
693
+ /// does not need to update playback code.
694
+ ///
695
+ /// Returns the Progress Time for the marker named. Returns nil if no marker found.
696
+ public func progressTime(forMarker named: String) -> AnimationProgressTime? {
697
+ guard let animation = animation else {
698
+ return nil
699
+ }
700
+ return animation.progressTime(forMarker: named)
701
+ }
702
+
703
+ /// Markers are a way to describe a point in time by a key name.
704
+ ///
705
+ /// Markers are encoded into animation JSON. By using markers a designer can mark
706
+ /// playback points for a developer to use without having to worry about keeping
707
+ /// track of animation frames. If the animation file is updated, the developer
708
+ /// does not need to update playback code.
709
+ ///
710
+ /// Returns the Frame Time for the marker named. Returns nil if no marker found.
711
+ public func frameTime(forMarker named: String) -> AnimationFrameTime? {
712
+ guard let animation = animation else {
713
+ return nil
714
+ }
715
+ return animation.frameTime(forMarker: named)
716
+ }
717
+
718
+ // MARK: Internal
719
+
720
+ var animationLayer: RootAnimationLayer? = nil
721
+
722
+ /// Set animation name from Interface Builder
723
+ @IBInspectable var animationName: String? {
724
+ didSet {
725
+ self.animation = animationName.flatMap {
726
+ Animation.named($0, animationCache: nil)
727
+ }
728
+ }
729
+ }
730
+
731
+ override func layoutAnimation() {
732
+ guard let animation = animation, let animationLayer = animationLayer else { return }
733
+ var position = animation.bounds.center
734
+ let xform: CATransform3D
735
+ var shouldForceUpdates = false
736
+
737
+ if let viewportFrame = viewportFrame {
738
+ shouldForceUpdates = contentMode == .redraw
739
+
740
+ let compAspect = viewportFrame.size.width / viewportFrame.size.height
741
+ let viewAspect = bounds.size.width / bounds.size.height
742
+ let dominantDimension = compAspect > viewAspect ? bounds.size.width : bounds.size.height
743
+ let compDimension = compAspect > viewAspect ? viewportFrame.size.width : viewportFrame.size.height
744
+ let scale = dominantDimension / compDimension
745
+
746
+ let viewportOffset = animation.bounds.center - viewportFrame.center
747
+ xform = CATransform3DTranslate(CATransform3DMakeScale(scale, scale, 1), viewportOffset.x, viewportOffset.y, 0)
748
+ position = bounds.center
749
+ } else {
750
+ switch contentMode {
751
+ case .scaleToFill:
752
+ position = bounds.center
753
+ xform = CATransform3DMakeScale(
754
+ bounds.size.width / animation.size.width,
755
+ bounds.size.height / animation.size.height,
756
+ 1);
757
+ case .scaleAspectFit:
758
+ position = bounds.center
759
+ let compAspect = animation.size.width / animation.size.height
760
+ let viewAspect = bounds.size.width / bounds.size.height
761
+ let dominantDimension = compAspect > viewAspect ? bounds.size.width : bounds.size.height
762
+ let compDimension = compAspect > viewAspect ? animation.size.width : animation.size.height
763
+ let scale = dominantDimension / compDimension
764
+ xform = CATransform3DMakeScale(scale, scale, 1)
765
+ case .scaleAspectFill:
766
+ position = bounds.center
767
+ let compAspect = animation.size.width / animation.size.height
768
+ let viewAspect = bounds.size.width / bounds.size.height
769
+ let scaleWidth = compAspect < viewAspect
770
+ let dominantDimension = scaleWidth ? bounds.size.width : bounds.size.height
771
+ let compDimension = scaleWidth ? animation.size.width : animation.size.height
772
+ let scale = dominantDimension / compDimension
773
+ xform = CATransform3DMakeScale(scale, scale, 1)
774
+ case .redraw:
775
+ shouldForceUpdates = true
776
+ xform = CATransform3DIdentity
777
+ case .center:
778
+ position = bounds.center
779
+ xform = CATransform3DIdentity
780
+ case .top:
781
+ position.x = bounds.center.x
782
+ xform = CATransform3DIdentity
783
+ case .bottom:
784
+ position.x = bounds.center.x
785
+ position.y = bounds.maxY - animation.bounds.midY
786
+ xform = CATransform3DIdentity
787
+ case .left:
788
+ position.y = bounds.center.y
789
+ xform = CATransform3DIdentity
790
+ case .right:
791
+ position.y = bounds.center.y
792
+ position.x = bounds.maxX - animation.bounds.midX
793
+ xform = CATransform3DIdentity
794
+ case .topLeft:
795
+ xform = CATransform3DIdentity
796
+ case .topRight:
797
+ position.x = bounds.maxX - animation.bounds.midX
798
+ xform = CATransform3DIdentity
799
+ case .bottomLeft:
800
+ position.y = bounds.maxY - animation.bounds.midY
801
+ xform = CATransform3DIdentity
802
+ case .bottomRight:
803
+ position.x = bounds.maxX - animation.bounds.midX
804
+ position.y = bounds.maxY - animation.bounds.midY
805
+ xform = CATransform3DIdentity
806
+
807
+ #if os(iOS) || os(tvOS)
808
+ @unknown default:
809
+ logger.assertionFailure("unsupported contentMode: \(contentMode.rawValue)")
810
+ xform = CATransform3DIdentity
811
+ #endif
812
+ }
813
+ }
814
+
815
+ // UIView Animation does not implicitly set CAAnimation time or timing fuctions.
816
+ // If layout is changed in an animation we must get the current animation duration
817
+ // and timing function and then manually create a CAAnimation to match the UIView animation.
818
+ // If layout is changed without animation, explicitly set animation duration to 0.0
819
+ // inside CATransaction to avoid unwanted artifacts.
820
+ /// Check if any animation exist on the view's layer, and match it.
821
+ if let key = viewLayer?.animationKeys()?.first, let animation = viewLayer?.animation(forKey: key) {
822
+ // The layout is happening within an animation block. Grab the animation data.
823
+
824
+ let positionKey = "LayoutPositionAnimation"
825
+ let transformKey = "LayoutTransformAnimation"
826
+ animationLayer.removeAnimation(forKey: positionKey)
827
+ animationLayer.removeAnimation(forKey: transformKey)
828
+
829
+ let positionAnimation = animation.copy() as? CABasicAnimation ?? CABasicAnimation(keyPath: "position")
830
+ positionAnimation.keyPath = "position"
831
+ positionAnimation.isAdditive = false
832
+ positionAnimation.fromValue = (animationLayer.presentation() ?? animationLayer).position
833
+ positionAnimation.toValue = position
834
+ positionAnimation.isRemovedOnCompletion = true
835
+
836
+ let xformAnimation = animation.copy() as? CABasicAnimation ?? CABasicAnimation(keyPath: "transform")
837
+ xformAnimation.keyPath = "transform"
838
+ xformAnimation.isAdditive = false
839
+ xformAnimation.fromValue = (animationLayer.presentation() ?? animationLayer).transform
840
+ xformAnimation.toValue = xform
841
+ xformAnimation.isRemovedOnCompletion = true
842
+
843
+ animationLayer.position = position
844
+ animationLayer.transform = xform
845
+ #if os(OSX)
846
+ animationLayer.anchorPoint = layer?.anchorPoint ?? CGPoint.zero
847
+ #else
848
+ animationLayer.anchorPoint = layer.anchorPoint
849
+ #endif
850
+ animationLayer.add(positionAnimation, forKey: positionKey)
851
+ animationLayer.add(xformAnimation, forKey: transformKey)
852
+ } else {
853
+ // In performance tests, we have to wrap the animation view setup
854
+ // in a `CATransaction` in order for the layers to be deallocated at
855
+ // the correct time. The `CATransaction`s in this method interfere
856
+ // with the ones managed by the performance test, and aren't actually
857
+ // necessary in a headless environment, so we disable them.
858
+ if TestHelpers.performanceTestsAreRunning {
859
+ animationLayer.position = position
860
+ animationLayer.transform = xform
861
+ } else {
862
+ CATransaction.begin()
863
+ CATransaction.setAnimationDuration(0.0)
864
+ CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: .linear))
865
+ animationLayer.position = position
866
+ animationLayer.transform = xform
867
+ CATransaction.commit()
868
+ }
869
+ }
870
+
871
+ if shouldForceUpdates {
872
+ animationLayer.forceDisplayUpdate()
873
+ }
874
+ }
875
+
876
+ func updateRasterizationState() {
877
+ if isAnimationPlaying {
878
+ animationLayer?.shouldRasterize = false
879
+ } else {
880
+ animationLayer?.shouldRasterize = shouldRasterizeWhenIdle
881
+ }
882
+ }
883
+
884
+ /// Updates the animation frame. Does not affect any current animations
885
+ func updateAnimationFrame(_ newFrame: CGFloat) {
886
+ // In performance tests, we have to wrap the animation view setup
887
+ // in a `CATransaction` in order for the layers to be deallocated at
888
+ // the correct time. The `CATransaction`s in this method interfere
889
+ // with the ones managed by the performance test, and aren't actually
890
+ // necessary in a headless environment, so we disable them.
891
+ if TestHelpers.performanceTestsAreRunning {
892
+ animationLayer?.currentFrame = newFrame
893
+ animationLayer?.forceDisplayUpdate()
894
+ return
895
+ }
896
+
897
+ CATransaction.begin()
898
+ CATransaction.setCompletionBlock {
899
+ self.animationLayer?.forceDisplayUpdate()
900
+ }
901
+ CATransaction.setDisableActions(true)
902
+ animationLayer?.currentFrame = newFrame
903
+ CATransaction.commit()
904
+ }
905
+
906
+ @objc
907
+ override func animationWillMoveToBackground() {
908
+ updateAnimationForBackgroundState()
909
+ }
910
+
911
+ @objc
912
+ override func animationWillEnterForeground() {
913
+ updateAnimationForForegroundState()
914
+ }
915
+
916
+ override func animationMovedToWindow() {
917
+ /// Don't update any state if the `superview` is `nil`
918
+ /// When A viewA owns superViewB, it removes the superViewB from the window. At this point, viewA still owns superViewB and triggers the viewA method: -didmovetowindow
919
+ guard superview != nil else { return }
920
+
921
+ if window != nil {
922
+ updateAnimationForForegroundState()
923
+ } else {
924
+ updateAnimationForBackgroundState()
925
+ }
926
+ }
927
+
928
+ // MARK: Fileprivate
929
+
930
+ fileprivate var animationContext: AnimationContext?
931
+ fileprivate var _activeAnimationName: String = AnimationView.animationName
932
+ fileprivate var animationID = 0
933
+
934
+ fileprivate var waitingToPlayAnimation = false
935
+
936
+ fileprivate var activeAnimationName: String {
937
+ switch animationLayer?.primaryAnimationKey {
938
+ case .specific(let animationKey):
939
+ return animationKey
940
+ case .managed, nil:
941
+ return _activeAnimationName
942
+ }
943
+ }
944
+
945
+ fileprivate func makeAnimationLayer(usingEngine renderingEngine: RenderingEngineOption) {
946
+
947
+ /// Remove current animation if any
948
+ removeCurrentAnimation()
949
+
950
+ if let oldAnimation = animationLayer {
951
+ oldAnimation.removeFromSuperlayer()
952
+ }
953
+
954
+ invalidateIntrinsicContentSize()
955
+
956
+ guard let animation = animation else {
957
+ return
958
+ }
959
+
960
+ let rootAnimationLayer: RootAnimationLayer?
961
+ switch renderingEngine {
962
+ case .automatic:
963
+ rootAnimationLayer = makeAutomaticEngineLayer(for: animation)
964
+ case .specific(.coreAnimation):
965
+ rootAnimationLayer = makeCoreAnimationLayer(for: animation)
966
+ case .specific(.mainThread):
967
+ rootAnimationLayer = makeMainThreadAnimationLayer(for: animation)
968
+ }
969
+
970
+ guard let animationLayer = rootAnimationLayer else {
971
+ return
972
+ }
973
+
974
+ animationLayer.renderScale = screenScale
975
+
976
+ viewLayer?.addSublayer(animationLayer)
977
+ self.animationLayer = animationLayer
978
+ reloadImages()
979
+ animationLayer.setNeedsDisplay()
980
+ setNeedsLayout()
981
+ currentFrame = CGFloat(animation.startFrame)
982
+ }
983
+
984
+ fileprivate func makeMainThreadAnimationLayer(for animation: Animation) -> MainThreadAnimationLayer {
985
+ MainThreadAnimationLayer(
986
+ animation: animation,
987
+ imageProvider: imageProvider.cachedImageProvider,
988
+ textProvider: textProvider,
989
+ fontProvider: fontProvider,
990
+ logger: logger)
991
+ }
992
+
993
+ fileprivate func makeCoreAnimationLayer(for animation: Animation) -> CoreAnimationLayer? {
994
+ do {
995
+ let coreAnimationLayer = try CoreAnimationLayer(
996
+ animation: animation,
997
+ imageProvider: imageProvider.cachedImageProvider,
998
+ fontProvider: fontProvider,
999
+ compatibilityTrackerMode: .track,
1000
+ logger: logger)
1001
+
1002
+ coreAnimationLayer.didSetUpAnimation = { [logger] compatibilityIssues in
1003
+ logger.assert(
1004
+ compatibilityIssues.isEmpty,
1005
+ "Encountered Core Animation compatibility issues while setting up animation:\n"
1006
+ + compatibilityIssues.map { $0.description }.joined(separator: "\n") + "\n\n"
1007
+ + """
1008
+ This animation cannot be rendered correctly by the Core Animation engine.
1009
+ To resolve this issue, you can use `RenderingEngineOption.automatic`, which automatically falls back
1010
+ to the Main Thread rendering engine when necessary, or just use `RenderingEngineOption.mainThread`.
1011
+
1012
+ """)
1013
+ }
1014
+
1015
+ return coreAnimationLayer
1016
+ } catch {
1017
+ // This should never happen, because we initialize the `CoreAnimationLayer` with
1018
+ // `CompatibilityTracker.Mode.track` (which reports errors in `didSetUpAnimation`,
1019
+ // not by throwing).
1020
+ logger.assertionFailure("Encountered unexpected error \(error)")
1021
+ return nil
1022
+ }
1023
+ }
1024
+
1025
+ fileprivate func makeAutomaticEngineLayer(for animation: Animation) -> CoreAnimationLayer? {
1026
+ do {
1027
+ // Attempt to set up the Core Animation layer. This can either throw immediately in `init`,
1028
+ // or throw an error later in `CALayer.display()` that will be reported in `didSetUpAnimation`.
1029
+ let coreAnimationLayer = try CoreAnimationLayer(
1030
+ animation: animation,
1031
+ imageProvider: imageProvider.cachedImageProvider,
1032
+ fontProvider: fontProvider,
1033
+ compatibilityTrackerMode: .abort,
1034
+ logger: logger)
1035
+
1036
+ coreAnimationLayer.didSetUpAnimation = { [weak self] issues in
1037
+ self?.automaticEngineLayerDidSetUpAnimation(issues)
1038
+ }
1039
+
1040
+ return coreAnimationLayer
1041
+ } catch {
1042
+ if case CompatibilityTracker.Error.encounteredCompatibilityIssue(let compatibilityIssue) = error {
1043
+ automaticEngineLayerDidSetUpAnimation([compatibilityIssue])
1044
+ } else {
1045
+ // This should never happen, because we expect `CoreAnimationLayer` to only throw
1046
+ // `CompatibilityTracker.Error.encounteredCompatibilityIssue` errors.
1047
+ logger.assertionFailure("Encountered unexpected error \(error)")
1048
+ automaticEngineLayerDidSetUpAnimation([])
1049
+ }
1050
+
1051
+ return nil
1052
+ }
1053
+ }
1054
+
1055
+ // Handles any compatibility issues with the Core Animation engine
1056
+ // by falling back to the Main Thread engine
1057
+ fileprivate func automaticEngineLayerDidSetUpAnimation(_ compatibilityIssues: [CompatibilityIssue]) {
1058
+ // If there weren't any compatibility issues, then there's nothing else to do
1059
+ if compatibilityIssues.isEmpty {
1060
+ return
1061
+ }
1062
+
1063
+ logger.warn(
1064
+ "Encountered Core Animation compatibility issue while setting up animation:\n"
1065
+ + compatibilityIssues.map { $0.description }.joined(separator: "\n") + "\n"
1066
+ + """
1067
+ This animation may have additional compatibility issues, but animation setup was cancelled early to avoid wasted work.
1068
+
1069
+ Automatically falling back to Main Thread rendering engine. This fallback comes with some additional performance
1070
+ overhead, which can be reduced by manually specifying that this animation should always use the Main Thread engine.
1071
+
1072
+ """)
1073
+
1074
+ let animationContext = self.animationContext
1075
+ let currentFrame = self.currentFrame
1076
+
1077
+ makeAnimationLayer(usingEngine: .mainThread)
1078
+
1079
+ // Set up the Main Thread animation layer using the same configuration that
1080
+ // was being used by the previous Core Animation layer
1081
+ self.currentFrame = currentFrame
1082
+
1083
+ if let animationContext = animationContext {
1084
+ // `AnimationContext.closure` (`AnimationCompletionDelegate`) is a reference type
1085
+ // that is the animation layer's `CAAnimationDelegate`, and holds a reference to
1086
+ // the animation layer. Reusing a single instance across different animation layers
1087
+ // can cause the animation setup to fail, so we create a copy of the `animationContext`:
1088
+ addNewAnimationForContext(AnimationContext(
1089
+ playFrom: animationContext.playFrom,
1090
+ playTo: animationContext.playTo,
1091
+ closure: animationContext.closure.completionBlock))
1092
+ }
1093
+ }
1094
+
1095
+ fileprivate func updateAnimationForBackgroundState() {
1096
+ if let currentContext = animationContext {
1097
+ switch backgroundBehavior {
1098
+ case .stop:
1099
+ removeCurrentAnimation()
1100
+ updateAnimationFrame(currentContext.playFrom)
1101
+ case .pause:
1102
+ removeCurrentAnimation()
1103
+ case .pauseAndRestore:
1104
+ currentContext.closure.ignoreDelegate = true
1105
+ removeCurrentAnimation()
1106
+ /// Keep the stale context around for when the app enters the foreground.
1107
+ animationContext = currentContext
1108
+ case .forceFinish:
1109
+ removeCurrentAnimation()
1110
+ updateAnimationFrame(currentContext.playTo)
1111
+ case .continuePlaying:
1112
+ break
1113
+ }
1114
+ }
1115
+ }
1116
+
1117
+ fileprivate func updateAnimationForForegroundState() {
1118
+ if let currentContext = animationContext {
1119
+ if waitingToPlayAnimation {
1120
+ waitingToPlayAnimation = false
1121
+ addNewAnimationForContext(currentContext)
1122
+ } else if backgroundBehavior == .pauseAndRestore {
1123
+ /// Restore animation from saved state
1124
+ updateInFlightAnimation()
1125
+ }
1126
+ }
1127
+ }
1128
+
1129
+ /// Removes the current animation and pauses the animation at the current frame
1130
+ /// if necessary before setting up a new animation.
1131
+ /// - This is not necessary with the Core Animation engine, and skipping
1132
+ /// this step lets us avoid building the animations twice (once paused
1133
+ /// and once again playing)
1134
+ fileprivate func removeCurrentAnimationIfNecessary() {
1135
+ switch currentRenderingEngine {
1136
+ case .mainThread:
1137
+ removeCurrentAnimation()
1138
+ case .coreAnimation, nil:
1139
+ break
1140
+ }
1141
+ }
1142
+
1143
+ /// Stops the current in flight animation and freezes the animation in its current state.
1144
+ fileprivate func removeCurrentAnimation() {
1145
+ guard animationContext != nil else { return }
1146
+ let pauseFrame = realtimeAnimationFrame
1147
+ animationLayer?.removeAnimation(forKey: activeAnimationName)
1148
+ updateAnimationFrame(pauseFrame)
1149
+ animationContext = nil
1150
+ }
1151
+
1152
+ /// Updates an in flight animation.
1153
+ fileprivate func updateInFlightAnimation() {
1154
+ guard let animationContext = animationContext else { return }
1155
+
1156
+ guard animationContext.closure.animationState != .complete else {
1157
+ // Tried to re-add an already completed animation. Cancel.
1158
+ self.animationContext = nil
1159
+ return
1160
+ }
1161
+
1162
+ /// Tell existing context to ignore its closure
1163
+ animationContext.closure.ignoreDelegate = true
1164
+
1165
+ /// Make a new context, stealing the completion block from the previous.
1166
+ let newContext = AnimationContext(
1167
+ playFrom: animationContext.playFrom,
1168
+ playTo: animationContext.playTo,
1169
+ closure: animationContext.closure.completionBlock)
1170
+
1171
+ /// Remove current animation, and freeze the current frame.
1172
+ let pauseFrame = realtimeAnimationFrame
1173
+ animationLayer?.removeAnimation(forKey: activeAnimationName)
1174
+ animationLayer?.currentFrame = pauseFrame
1175
+
1176
+ addNewAnimationForContext(newContext)
1177
+ }
1178
+
1179
+ /// Adds animation to animation layer and sets the delegate. If animation layer or animation are nil, exits.
1180
+ fileprivate func addNewAnimationForContext(_ animationContext: AnimationContext) {
1181
+ guard let animationlayer = animationLayer, let animation = animation else {
1182
+ return
1183
+ }
1184
+
1185
+ self.animationContext = animationContext
1186
+
1187
+ switch currentRenderingEngine {
1188
+ case .mainThread:
1189
+ guard window != nil else {
1190
+ waitingToPlayAnimation = true
1191
+ return
1192
+ }
1193
+
1194
+ case .coreAnimation, nil:
1195
+ // The Core Animation engine automatically batches animation setup to happen
1196
+ // in `CALayer.display()`, which won't be called until the layer is on-screen,
1197
+ // so we don't need to defer animation setup at this layer.
1198
+ break
1199
+ }
1200
+
1201
+ animationID = animationID + 1
1202
+ _activeAnimationName = AnimationView.animationName + String(animationID)
1203
+
1204
+ if let coreAnimationLayer = animationlayer as? CoreAnimationLayer {
1205
+ var animationContext = animationContext
1206
+ var timingConfiguration = CoreAnimationLayer.CAMediaTimingConfiguration(
1207
+ autoreverses: loopMode.caAnimationConfiguration.autoreverses,
1208
+ repeatCount: loopMode.caAnimationConfiguration.repeatCount,
1209
+ speed: Float(animationSpeed))
1210
+
1211
+ // The animation should start playing from the `currentFrame`,
1212
+ // if `currentFrame` is included in the time range being played.
1213
+ let lowerBoundTime = min(animationContext.playFrom, animationContext.playTo)
1214
+ let upperBoundTime = max(animationContext.playFrom, animationContext.playTo)
1215
+ if (lowerBoundTime ..< upperBoundTime).contains(round(currentFrame)) {
1216
+ // We have to configure this differently depending on the loop mode:
1217
+ switch loopMode {
1218
+ // When playing exactly once (and not looping), we can just set the
1219
+ // `playFrom` time to be the `currentFrame`. Since the animation duration
1220
+ // is based on `playFrom` and `playTo`, this automatically truncates the
1221
+ // duration (so the animation stops playing at `playFrom`).
1222
+ case .playOnce:
1223
+ animationContext.playFrom = currentFrame
1224
+
1225
+ // When looping, we specifically _don't_ want to affect the duration of the animation,
1226
+ // since that would affect the duration of all subsequent loops. We just want to adjust
1227
+ // the duration of the _first_ loop. Instead of setting `playFrom`, we just add a `timeOffset`
1228
+ // so the first loop begins at `currentTime` but all subsequent loops are the standard duration.
1229
+ default:
1230
+ timingConfiguration.timeOffset = currentTime - animation.time(forFrame: animationContext.playFrom)
1231
+ }
1232
+ }
1233
+
1234
+ coreAnimationLayer.playAnimation(configuration: .init(
1235
+ animationContext: animationContext,
1236
+ timingConfiguration: timingConfiguration))
1237
+
1238
+ return
1239
+ }
1240
+
1241
+ /// At this point there is no animation on animationLayer and its state is set.
1242
+
1243
+ let framerate = animation.framerate
1244
+
1245
+ let playFrom = animationContext.playFrom.clamp(animation.startFrame, animation.endFrame)
1246
+ let playTo = animationContext.playTo.clamp(animation.startFrame, animation.endFrame)
1247
+
1248
+ let duration = ((max(playFrom, playTo) - min(playFrom, playTo)) / CGFloat(framerate))
1249
+
1250
+ let playingForward: Bool =
1251
+ (
1252
+ (animationSpeed > 0 && playFrom < playTo) ||
1253
+ (animationSpeed < 0 && playTo < playFrom))
1254
+
1255
+ var startFrame = currentFrame.clamp(min(playFrom, playTo), max(playFrom, playTo))
1256
+ if startFrame == playTo {
1257
+ startFrame = playFrom
1258
+ }
1259
+
1260
+ let timeOffset: TimeInterval = playingForward
1261
+ ? Double(startFrame - min(playFrom, playTo)) / framerate
1262
+ : Double(max(playFrom, playTo) - startFrame) / framerate
1263
+
1264
+ let layerAnimation = CABasicAnimation(keyPath: "currentFrame")
1265
+ layerAnimation.fromValue = playFrom
1266
+ layerAnimation.toValue = playTo
1267
+ layerAnimation.speed = Float(animationSpeed)
1268
+ layerAnimation.duration = TimeInterval(duration)
1269
+ layerAnimation.fillMode = CAMediaTimingFillMode.both
1270
+ layerAnimation.repeatCount = loopMode.caAnimationConfiguration.repeatCount
1271
+ layerAnimation.autoreverses = loopMode.caAnimationConfiguration.autoreverses
1272
+
1273
+ layerAnimation.isRemovedOnCompletion = false
1274
+ if timeOffset != 0 {
1275
+ let currentLayerTime = viewLayer?.convertTime(CACurrentMediaTime(), from: nil) ?? 0
1276
+ layerAnimation.beginTime = currentLayerTime - (timeOffset * 1 / Double(abs(animationSpeed)))
1277
+ }
1278
+ layerAnimation.delegate = animationContext.closure
1279
+ animationContext.closure.animationLayer = animationlayer
1280
+ animationContext.closure.animationKey = activeAnimationName
1281
+
1282
+ animationlayer.add(layerAnimation, forKey: activeAnimationName)
1283
+ updateRasterizationState()
1284
+ }
1285
+
1286
+ // MARK: Private
1287
+
1288
+ static private let animationName = "Lottie"
1289
+
1290
+ private let logger: LottieLogger
1291
+
1292
+ /// The `LottieBackgroundBehavior` that was specified manually by setting `self.backgroundBehavior`
1293
+ private var _backgroundBehavior: LottieBackgroundBehavior?
1294
+
1295
+ }
1296
+
1297
+ // MARK: - LottieLoopMode + caAnimationConfiguration
1298
+
1299
+ extension LottieLoopMode {
1300
+ /// The `CAAnimation` configuration that reflects this mode
1301
+ var caAnimationConfiguration: (repeatCount: Float, autoreverses: Bool) {
1302
+ switch self {
1303
+ case .playOnce:
1304
+ return (repeatCount: 1, autoreverses: false)
1305
+ case .loop:
1306
+ return (repeatCount: .greatestFiniteMagnitude, autoreverses: false)
1307
+ case .autoReverse:
1308
+ return (repeatCount: .greatestFiniteMagnitude, autoreverses: true)
1309
+ case .repeat(let amount):
1310
+ return (repeatCount: amount, autoreverses: false)
1311
+ case .repeatBackwards(let amount):
1312
+ return (repeatCount: amount, autoreverses: true)
1313
+ }
1314
+ }
1315
+ }