lottie-ios 3.4.0 → 3.4.3

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 (394) hide show
  1. package/.github/workflows/main.yml +10 -7
  2. package/.github/workflows/stale_issues.yml +17 -0
  3. package/.swiftpm/xcode/package.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  4. package/Lottie.xcodeproj/project.pbxproj +33 -21
  5. package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (macOS).xcscheme +2 -2
  6. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  7. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +5 -6
  8. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +114 -1
  9. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +30 -0
  10. package/Package.swift +1 -1
  11. package/README.md +5 -6
  12. package/Rakefile +52 -17
  13. package/Sources/Private/CoreAnimation/Animations/CAAnimation+TimingConfiguration.swift +7 -2
  14. package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +192 -67
  15. package/Sources/Private/CoreAnimation/Animations/CombinedShapeAnimation.swift +28 -0
  16. package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +31 -4
  17. package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +98 -43
  18. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +19 -19
  19. package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +34 -7
  20. package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +25 -14
  21. package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +61 -32
  22. package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +6 -2
  23. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +29 -11
  24. package/Sources/Private/CoreAnimation/Extensions/KeyframeGroup+exactlyOneKeyframe.swift +2 -2
  25. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combinedIfPossible.swift +116 -23
  26. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +9 -0
  27. package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +2 -1
  28. package/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift +48 -12
  29. package/Sources/Private/CoreAnimation/Layers/GradientRenderLayer.swift +10 -3
  30. package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +5 -0
  31. package/Sources/Private/CoreAnimation/Layers/MaskCompositionLayer.swift +1 -1
  32. package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +2 -2
  33. package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +85 -0
  34. package/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +94 -38
  35. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +131 -46
  36. package/Sources/Private/CoreAnimation/Layers/TextLayer.swift +16 -2
  37. package/Sources/Private/MainThread/LayerContainers/CompLayers/CompositionLayer.swift +1 -1
  38. package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +0 -2
  39. package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +2 -2
  40. package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +1 -2
  41. package/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift +30 -1
  42. package/Sources/Private/MainThread/LayerContainers/Utility/InvertedMatteLayer.swift +1 -0
  43. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +0 -1
  44. package/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift +5 -2
  45. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +4 -7
  46. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +5 -0
  47. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientStrokeRenderer.swift +1 -2
  48. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift +1 -1
  49. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +1 -1
  50. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +1 -1
  51. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +3 -3
  52. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +3 -0
  53. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +1 -1
  54. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +28 -1
  55. package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +1 -1
  56. package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeRenderLayer.swift +0 -1
  57. package/Sources/Private/Model/Animation.swift +4 -4
  58. package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +25 -0
  59. package/Sources/Private/Model/ShapeItems/Ellipse.swift +0 -1
  60. package/Sources/Private/Model/ShapeItems/Fill.swift +1 -1
  61. package/Sources/Private/Model/ShapeItems/GradientFill.swift +14 -1
  62. package/Sources/Private/Model/ShapeItems/GradientStroke.swift +0 -1
  63. package/Sources/Private/Model/ShapeItems/Group.swift +6 -1
  64. package/Sources/Private/Model/ShapeItems/Merge.swift +0 -1
  65. package/Sources/Private/Model/ShapeItems/Rectangle.swift +0 -1
  66. package/Sources/Private/Model/ShapeItems/Repeater.swift +0 -1
  67. package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +0 -1
  68. package/Sources/Private/Model/ShapeItems/Star.swift +0 -1
  69. package/Sources/Private/Model/ShapeItems/Stroke.swift +0 -1
  70. package/Sources/Private/Model/ShapeItems/Trim.swift +0 -1
  71. package/Sources/Private/Model/Text/TextAnimator.swift +0 -1
  72. package/Sources/Private/Utility/Debugging/LayerDebugging.swift +1 -2
  73. package/Sources/Private/Utility/Extensions/MathKit.swift +1 -2
  74. package/Sources/Private/Utility/Extensions/StringExtensions.swift +0 -1
  75. package/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift +0 -1
  76. package/Sources/Private/{MainThread/NodeRenderSystem/NodeProperties/ValueProviders → Utility/Interpolatable}/KeyframeInterpolator.swift +1 -4
  77. package/Sources/Private/Utility/Primitives/BezierPath.swift +1 -2
  78. package/Sources/Private/Utility/Primitives/CurveVertex.swift +2 -4
  79. package/Sources/Public/Animation/AnimationPublic.swift +2 -4
  80. package/Sources/Public/Animation/AnimationView.swift +29 -7
  81. package/Sources/Public/Animation/AnimationViewInitializers.swift +13 -11
  82. package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +0 -2
  83. package/Sources/Public/FontProvider/AnimationFontProvider.swift +1 -1
  84. package/Sources/Public/Logging/LottieLogger.swift +15 -2
  85. package/Sources/Public/TextProvider/AnimationTextProvider.swift +1 -1
  86. package/Sources/Public/iOS/AnimatedButton.swift +10 -4
  87. package/Sources/Public/iOS/AnimatedControl.swift +3 -5
  88. package/Sources/Public/iOS/AnimatedSwitch.swift +9 -6
  89. package/Sources/Public/iOS/BundleImageProvider.swift +2 -3
  90. package/Sources/Public/iOS/FilepathImageProvider.swift +1 -2
  91. package/Sources/Public/macOS/BundleImageProvider.macOS.swift +1 -2
  92. package/Sources/Public/macOS/FilepathImageProvider.macOS.swift +1 -3
  93. package/Tests/AnimationKeypathTests.swift +10 -1
  94. package/Tests/AutomaticEngineTests.swift +1 -0
  95. package/Tests/ParsingTests.swift +2 -1
  96. package/Tests/PerformanceTests.swift +28 -29
  97. package/Tests/SnapshotConfiguration.swift +19 -0
  98. package/Tests/SnapshotTests.swift +4 -0
  99. package/Tests/Utils/HardcodedTextProvider.swift +27 -0
  100. package/lottie-ios.podspec +2 -2
  101. package/package.json +1 -1
  102. package/script/test-carthage/CarthageTest/AppDelegate.swift +6 -7
  103. package/script/test-carthage/CarthageTest/ViewController.swift +1 -1
  104. package/script/test-carthage/CarthageTest-macOS/AppDelegate.swift +7 -0
  105. package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  106. package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json +58 -0
  107. package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/Contents.json +6 -0
  108. package/script/test-carthage/CarthageTest-macOS/Base.lproj/Main.storyboard +717 -0
  109. package/script/test-carthage/CarthageTest-macOS/CarthageTest_macOS.entitlements +10 -0
  110. package/script/test-carthage/CarthageTest-macOS/ViewController.swift +15 -0
  111. package/script/test-carthage/CarthageTest.xcodeproj/project.pbxproj +159 -5
  112. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  113. package/script/test-carthage/CarthageTest.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +19 -0
  114. package/Lottie.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +0 -23
  115. package/Mintfile +0 -3
  116. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~-7Vi1RszY1XYnR2CCkEwIpKG8NwwA9zsZEz_WD7Dv6kKh4RC7N7ob8NIRVHGUJKp7eXxlpeI_gzD87Pcs_2u0g== +0 -0
  117. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~-SKV2drO-SFlrlh-wrzECDMkUSr-aF1lV9h-5onOy94zSTsD-oI45s0-KpOK45L-kq3hRY7v9vm-xmh00_eheg== +0 -0
  118. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~-_CU_vuaiFfObSeDFfmp7GuB20ThMSAL-P_RUMowiQLbdu-y0bU9upIm3q8g6XmXUG5hP6J1az0Ma5Hi_rhhRg== +0 -0
  119. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~03aPYP6VHJjZj5DlphGarj0xdw43qu09Onx5SReZoPvg9zh5uL212E-KWfGct9jf6JG0JFV2tdbBi7X_8bH9aw== +0 -0
  120. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~1Z82GPBBPc1VLvn4O7V5glb6lgyXteNlDREUzV_TPymM4ra4UkBMklzV90lEqoYRCDuRVzaQHaDYbmYp3-8CFw== +0 -0
  121. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~1mFDCboXpUu9pSHAiVGr1O_QgqEEtvJp_LUhickxLZo0Z5pj3fvadn1l2MzEOd4bFsVBZifUvcyPa7dzlMWF-A== +0 -0
  122. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~2_L9PUjv2JDKu1n8bDLb4XLB-yex6ZVjDDMwfuKAr7teDw-SKgLgkW6H-m_gjWChIVdB4vW6yvHP7XJxvXtRNA== +0 -0
  123. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw== +0 -1
  124. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~4krT4ZMzDOu34msFUq0Xod142kw4pAeSWX4JSxlsjOI0Wanu3343qeespgFi61MTWq1DdH9XXspVKqGlGm_fyw== +0 -0
  125. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~5_aJsdP-e3dRTAUnH-y1U2plaCuUi1vyHriaZuNK0xFe8wGl9Qft6uLCX2Qt6CRBKJQluEe9o0uRWw1eb42FHQ== +0 -0
  126. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~8b0bSqV7eND54zvHvu1v2Htpm7yn-BOEFw5d3mITJrXWNykJ5BTR9WbrD80JEctNcT-rDqO2xfrQk1tFWeY6Sw== +0 -0
  127. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~9u8KAGpgtSm-mQ12Py8RZUbYbDlBhM3w1I2MQO53K2CSn6IePp7g65DBcdXTYMfG1bgoJ-6x30fjnGe-2UYsDQ== +0 -0
  128. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Bw7uMs4wqB9ahfEqGii2FkQ9pvZmG6HGe2hmbAT2wyM5hpn8Xh5dELysMcEz6hEsqmn6HdRdLOLZhC_fNaXzgA== +0 -0
  129. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~BwUq2xXQYuE8ya6HT6lfNsdtEjz5AKGf8GvLY6VBxQyIY1vgj_Gov-3NeM69OS66BQRDK0PG9H4Oyg0R48E4vg== +0 -0
  130. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~EkDVUR6dcnzxV_lYjkrJ5QGMVTCvb_upAoBF6DBu61sQkGvZN3fSRTsJ1XfJIZO-JUzdNoVA3D_CcvokL0gnQg== +0 -0
  131. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~FUkcLSJ8RAuPenM4HFG1R-sN5-cDBGcTxgR2jaVCna7xV0ZTyBHriB1Nn59mariNlJDiCoBtMUQEmauGxWtfBA== +0 -0
  132. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~FqsuZe4RVLOOVUYLTL-GTIohZ8TdSfxx7m2KJtLYFPGOdE4XorTX7Oc7kXbhghPRppXT3jW-slI37M34YNEvLQ== +0 -0
  133. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~G4F_NtyTj3i46fmKm0NorHAeq8tYWWYf6uv5yC1DwzdpWVoYbOPufmFNvdEbxZt4AMdV0gKx3HI46EAXNOQVFg== +0 -0
  134. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~GxetzGUNDgaBBXcTmLK6p9JBDX3I3QPshshbui1IaEWvJbQko-E36tCKwaJYHbleAWz9FqkAM_Tqx3YOmSVkVg== +0 -0
  135. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~H1Wjd5kKWDW4t3SDodxiHV72V8WT0xwPubw5cJTNLkPRLgaILFPh-dpy8EOUNgy1KzrDujFsm9EcTsbuqtMPLA== +0 -0
  136. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~JpI5MH4zCgebUHFpXVn4zjtsGtMNnO7BQZWfNARAB5UWa9gqz6YXHR3uLCJ_AvJ3lh53BUVkavsx9TY2FMmxbA== +0 -0
  137. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~JujNYkJtcux0Ni4QnR64zu4Wz_zYjyKvYaYZm5ypxTLPSzF3_jNE_NO4sdbDamF8wEqWoky1uf4ZE0JT3L607A== +0 -0
  138. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~KJSEA6DKnb2_FRPSqKZGh41eo-C8x448J9kEBrH012bUrZfOSDvrgmIrU0Vz7Ri3gaS9aKKmSaVMvXsHSlTJVA== +0 -0
  139. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~MStOwu3jBlJtcRnxrseVOuhI4kCj--ggFPG7sqrq5w1hjrI3bVyD-bm1Jwyx0noY3wT1rHDEvaGWnV2qsGjGwg== +0 -0
  140. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~McsJ8kFVf3IjhgXIRdw8Xx-EXgbV071bmlj2BBnk52xrWl3sEeiIyxwUsF7mIWvMRWfcFfu4VGHYyqfk2BeHXw== +0 -0
  141. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~NHt9fVe4kDdbxnglKcEwXaRK-WsYEOaD23Kbl8SJPRMYHr_Z6SJd_HmG3BROHHR_M6TgSmucONpDJdTj5tjuFw== +0 -0
  142. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Nfo2iwCPcfAcOBIVyoUAK0-PIfr5qYxIKZt-uaSaTBdrTNxAuJ1ItmeDPZ3VdJJmxD_c22No7x482bdd3_yYtw== +0 -0
  143. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~S2Qlu11xBhEd5aGSzWsnw1TR8u8PiOF93GO0j5bfNoAFCVzxKOwhRFoIXba2EpQnLQqFdIKyhWN3l70A4GPHmg== +0 -0
  144. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~W7a7M37RO9jgck2zeR0471Pm7e8K0Kqj5tXEouDjvqKZXSrWxMaWD28oqkKKYAiU4608R4S9mM11KyphljdMSw== +0 -0
  145. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~XUo1oyPCrlL7CA74wG-OzQ06VOWJYWvHGFHU7keZN1SKaIXjHX5qi_kBzjG_rBCi89-S8GVmCy7S3PHSjG8SbQ== +0 -0
  146. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Xh0VmDvFNMELHu08-vrs54pegVyUwwDRxx_nXkwyD0NjnYozyqcGAKAr_QWHmw6F8XyuWg51M9KGpJJIFzzGuw== +0 -0
  147. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Xve-wMBp_lxVUgD9qH5GwieGP9cAWtm0xULZvdGjBRUMvaevmpCB5gnbMBuIXAO6a1c9v6WUq0jNVX7ut5HvOw== +0 -0
  148. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~ZU1XkZFgnEE22CXEF-pOlcj5f10x-KM1Vw9d4IOLu-NiTZcz7koYPixhdrB1PJr8J-h9NpJmfqEastfxamA1jQ== +0 -0
  149. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~_YkNYEHTsbbtFILJpzH3HenH0t4ShI25dIMdve541CF5bl-jPF3X3F7tq-t5dvP0TEkATsOJdLQdBp1xv4Q-ag== +0 -0
  150. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~boy6mpn2jkwm60jjgQ0TG25UqRdN46LzmgTVCrpy6nBOgkLCGkGHcbceiwjU1itS_vj3-iQX0ZnrWOQrPyfHNA== +0 -0
  151. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~bwzpVZ9hAqGDHhXs2FRA82dfGfLmc7-m0uQhZDDfHHO7hQ17M_Np341BZX4WDLhYYS4cdUgaDodlNpdfpG3nXw== +0 -0
  152. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~cBxe-9PpAGFdAsYkmdN3lJVqEliLcRYlyoAov0aPZfJGwUr_cOm3XpjO7nmf_2eLf8UAx-rycjnJzw07xLrNCA== +0 -1
  153. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~dirWk6W4Pav1oyciuflfJlRu0iuxbYOmrpQapOJ0mV9C1SQ-jvDRv_7h753Cy18-SwULARUdWsyUy3yNNvxF7w== +0 -0
  154. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~ebwZVjSEHroc9jtIm4jd_h_YAqEBcOkAZ4HPNJT8pLCldjRcTq-obQLakxXOhfuoOBlYBoZLuO-Y0lskeZRYKw== +0 -0
  155. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~gfcRcmRIr0h09d0jiZsA7nUeQv2XtapxuYEXZy1Z9um0tTJQvz-O5ef5f7zhLenLvjnDtDtlY_aY4Hvpce6e1Q== +0 -0
  156. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~hgOgiVCyv2R0W-f0qKw5xYPeUwj8_ccCM9vKH_7vAQcCO9t8BwR1APGRBv20AONmp-PYMXmtgsBlQkNBRBpdQA== +0 -0
  157. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~hrhCl-YRAAr8ByNB_LCgEBsVNHMp92gTIUknetpUHMjcXl4Hpn_uY-h6C45oga0ZALnfGCo6iKTmiPLa4Qvnpg== +0 -0
  158. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~n2yoR7JsyL4DSUwmjnpE4Iq9Qi_eeZrmpPU8cdehDFKfESK7nwxXxfrSMQbk0BQ2lgGPadoRcd1-qr1xVz97jA== +0 -0
  159. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~nMCcZm8WvPogyO_nuJ926Q3Q2dqVMN2LdjEL1Kq2wJ_RG-rH-e_6v41l1xZbCsQTa3XykQdEiXNc0HtAvT6IRA== +0 -0
  160. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~oc3C7xkUt-OWDL6rrsxs-seS4Fu1bqBWAAXCHalgShaGg9MUrOiRbHT2DcAnhyQFKx6x5FRbvjmYoQWrQiXJZA== +0 -0
  161. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~p-ihj7SEgkDXpMu9hvKE_wiX9cvtwyXrdIn964BfedXHKGpC6o7mMPxEyC0kRPVi_EZs_MRV5bAPEpl5h5we0g== +0 -0
  162. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~qlhO_D9oE8uSKH-mZqyRF9pp4Zv1Tv0dIYcqrH4hb1VWlIxcdxmg2j0M8496cQeFXC5bn_JMXdBlD-d6cnFF8w== +0 -0
  163. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~tjpiyIxJR_boTdUNrtFDuKIZoY84fI4lA1oMJbq9e2ZmYKIK5FeRN2O8cV_yMOYJGr4lbv03kTmT70mCjUc2_Q== +0 -0
  164. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~wULeoj18eEKJWAKx1uFQVwS48cUGFcYPRJQj1Ro5XNJsWCwppGSCdIPhwifD6Z2f_j3zfI2SmC2Gg81sBXXW7g== +0 -0
  165. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~zrEihMys4NVV5rx6FmuzEGO2TjloI3OiC7yzIhvqYoRo43ibb2F-Km6Jf4NX-ac62pOLBYZRcjQTvYMpn75_oA== +0 -0
  166. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~-7Vi1RszY1XYnR2CCkEwIpKG8NwwA9zsZEz_WD7Dv6kKh4RC7N7ob8NIRVHGUJKp7eXxlpeI_gzD87Pcs_2u0g== +0 -0
  167. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~-SKV2drO-SFlrlh-wrzECDMkUSr-aF1lV9h-5onOy94zSTsD-oI45s0-KpOK45L-kq3hRY7v9vm-xmh00_eheg== +0 -0
  168. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~-_CU_vuaiFfObSeDFfmp7GuB20ThMSAL-P_RUMowiQLbdu-y0bU9upIm3q8g6XmXUG5hP6J1az0Ma5Hi_rhhRg== +0 -0
  169. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~03aPYP6VHJjZj5DlphGarj0xdw43qu09Onx5SReZoPvg9zh5uL212E-KWfGct9jf6JG0JFV2tdbBi7X_8bH9aw== +0 -0
  170. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~1Z82GPBBPc1VLvn4O7V5glb6lgyXteNlDREUzV_TPymM4ra4UkBMklzV90lEqoYRCDuRVzaQHaDYbmYp3-8CFw== +0 -0
  171. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~1mFDCboXpUu9pSHAiVGr1O_QgqEEtvJp_LUhickxLZo0Z5pj3fvadn1l2MzEOd4bFsVBZifUvcyPa7dzlMWF-A== +0 -0
  172. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~2_L9PUjv2JDKu1n8bDLb4XLB-yex6ZVjDDMwfuKAr7teDw-SKgLgkW6H-m_gjWChIVdB4vW6yvHP7XJxvXtRNA== +0 -0
  173. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw== +0 -0
  174. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~4krT4ZMzDOu34msFUq0Xod142kw4pAeSWX4JSxlsjOI0Wanu3343qeespgFi61MTWq1DdH9XXspVKqGlGm_fyw== +0 -0
  175. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~5_aJsdP-e3dRTAUnH-y1U2plaCuUi1vyHriaZuNK0xFe8wGl9Qft6uLCX2Qt6CRBKJQluEe9o0uRWw1eb42FHQ== +0 -0
  176. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~8b0bSqV7eND54zvHvu1v2Htpm7yn-BOEFw5d3mITJrXWNykJ5BTR9WbrD80JEctNcT-rDqO2xfrQk1tFWeY6Sw== +0 -0
  177. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~9u8KAGpgtSm-mQ12Py8RZUbYbDlBhM3w1I2MQO53K2CSn6IePp7g65DBcdXTYMfG1bgoJ-6x30fjnGe-2UYsDQ== +0 -0
  178. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Bw7uMs4wqB9ahfEqGii2FkQ9pvZmG6HGe2hmbAT2wyM5hpn8Xh5dELysMcEz6hEsqmn6HdRdLOLZhC_fNaXzgA== +0 -0
  179. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~BwUq2xXQYuE8ya6HT6lfNsdtEjz5AKGf8GvLY6VBxQyIY1vgj_Gov-3NeM69OS66BQRDK0PG9H4Oyg0R48E4vg== +0 -0
  180. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~EkDVUR6dcnzxV_lYjkrJ5QGMVTCvb_upAoBF6DBu61sQkGvZN3fSRTsJ1XfJIZO-JUzdNoVA3D_CcvokL0gnQg== +0 -0
  181. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~FUkcLSJ8RAuPenM4HFG1R-sN5-cDBGcTxgR2jaVCna7xV0ZTyBHriB1Nn59mariNlJDiCoBtMUQEmauGxWtfBA== +0 -0
  182. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~FqsuZe4RVLOOVUYLTL-GTIohZ8TdSfxx7m2KJtLYFPGOdE4XorTX7Oc7kXbhghPRppXT3jW-slI37M34YNEvLQ== +0 -0
  183. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~G4F_NtyTj3i46fmKm0NorHAeq8tYWWYf6uv5yC1DwzdpWVoYbOPufmFNvdEbxZt4AMdV0gKx3HI46EAXNOQVFg== +0 -0
  184. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~GxetzGUNDgaBBXcTmLK6p9JBDX3I3QPshshbui1IaEWvJbQko-E36tCKwaJYHbleAWz9FqkAM_Tqx3YOmSVkVg== +0 -0
  185. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~H1Wjd5kKWDW4t3SDodxiHV72V8WT0xwPubw5cJTNLkPRLgaILFPh-dpy8EOUNgy1KzrDujFsm9EcTsbuqtMPLA== +0 -0
  186. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~JpI5MH4zCgebUHFpXVn4zjtsGtMNnO7BQZWfNARAB5UWa9gqz6YXHR3uLCJ_AvJ3lh53BUVkavsx9TY2FMmxbA== +0 -0
  187. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~JujNYkJtcux0Ni4QnR64zu4Wz_zYjyKvYaYZm5ypxTLPSzF3_jNE_NO4sdbDamF8wEqWoky1uf4ZE0JT3L607A== +0 -0
  188. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~KJSEA6DKnb2_FRPSqKZGh41eo-C8x448J9kEBrH012bUrZfOSDvrgmIrU0Vz7Ri3gaS9aKKmSaVMvXsHSlTJVA== +0 -0
  189. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~MStOwu3jBlJtcRnxrseVOuhI4kCj--ggFPG7sqrq5w1hjrI3bVyD-bm1Jwyx0noY3wT1rHDEvaGWnV2qsGjGwg== +0 -0
  190. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~McsJ8kFVf3IjhgXIRdw8Xx-EXgbV071bmlj2BBnk52xrWl3sEeiIyxwUsF7mIWvMRWfcFfu4VGHYyqfk2BeHXw== +0 -0
  191. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~NHt9fVe4kDdbxnglKcEwXaRK-WsYEOaD23Kbl8SJPRMYHr_Z6SJd_HmG3BROHHR_M6TgSmucONpDJdTj5tjuFw== +0 -0
  192. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Nfo2iwCPcfAcOBIVyoUAK0-PIfr5qYxIKZt-uaSaTBdrTNxAuJ1ItmeDPZ3VdJJmxD_c22No7x482bdd3_yYtw== +0 -0
  193. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~S2Qlu11xBhEd5aGSzWsnw1TR8u8PiOF93GO0j5bfNoAFCVzxKOwhRFoIXba2EpQnLQqFdIKyhWN3l70A4GPHmg== +0 -0
  194. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~W7a7M37RO9jgck2zeR0471Pm7e8K0Kqj5tXEouDjvqKZXSrWxMaWD28oqkKKYAiU4608R4S9mM11KyphljdMSw== +0 -0
  195. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~XUo1oyPCrlL7CA74wG-OzQ06VOWJYWvHGFHU7keZN1SKaIXjHX5qi_kBzjG_rBCi89-S8GVmCy7S3PHSjG8SbQ== +0 -0
  196. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Xh0VmDvFNMELHu08-vrs54pegVyUwwDRxx_nXkwyD0NjnYozyqcGAKAr_QWHmw6F8XyuWg51M9KGpJJIFzzGuw== +0 -0
  197. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Xve-wMBp_lxVUgD9qH5GwieGP9cAWtm0xULZvdGjBRUMvaevmpCB5gnbMBuIXAO6a1c9v6WUq0jNVX7ut5HvOw== +0 -0
  198. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~ZU1XkZFgnEE22CXEF-pOlcj5f10x-KM1Vw9d4IOLu-NiTZcz7koYPixhdrB1PJr8J-h9NpJmfqEastfxamA1jQ== +0 -0
  199. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~_YkNYEHTsbbtFILJpzH3HenH0t4ShI25dIMdve541CF5bl-jPF3X3F7tq-t5dvP0TEkATsOJdLQdBp1xv4Q-ag== +0 -0
  200. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~boy6mpn2jkwm60jjgQ0TG25UqRdN46LzmgTVCrpy6nBOgkLCGkGHcbceiwjU1itS_vj3-iQX0ZnrWOQrPyfHNA== +0 -0
  201. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~bwzpVZ9hAqGDHhXs2FRA82dfGfLmc7-m0uQhZDDfHHO7hQ17M_Np341BZX4WDLhYYS4cdUgaDodlNpdfpG3nXw== +0 -0
  202. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~cBxe-9PpAGFdAsYkmdN3lJVqEliLcRYlyoAov0aPZfJGwUr_cOm3XpjO7nmf_2eLf8UAx-rycjnJzw07xLrNCA== +0 -0
  203. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~dirWk6W4Pav1oyciuflfJlRu0iuxbYOmrpQapOJ0mV9C1SQ-jvDRv_7h753Cy18-SwULARUdWsyUy3yNNvxF7w== +0 -0
  204. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~ebwZVjSEHroc9jtIm4jd_h_YAqEBcOkAZ4HPNJT8pLCldjRcTq-obQLakxXOhfuoOBlYBoZLuO-Y0lskeZRYKw== +0 -0
  205. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~gfcRcmRIr0h09d0jiZsA7nUeQv2XtapxuYEXZy1Z9um0tTJQvz-O5ef5f7zhLenLvjnDtDtlY_aY4Hvpce6e1Q== +0 -0
  206. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~hgOgiVCyv2R0W-f0qKw5xYPeUwj8_ccCM9vKH_7vAQcCO9t8BwR1APGRBv20AONmp-PYMXmtgsBlQkNBRBpdQA== +0 -0
  207. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~hrhCl-YRAAr8ByNB_LCgEBsVNHMp92gTIUknetpUHMjcXl4Hpn_uY-h6C45oga0ZALnfGCo6iKTmiPLa4Qvnpg== +0 -0
  208. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~n2yoR7JsyL4DSUwmjnpE4Iq9Qi_eeZrmpPU8cdehDFKfESK7nwxXxfrSMQbk0BQ2lgGPadoRcd1-qr1xVz97jA== +0 -0
  209. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~nMCcZm8WvPogyO_nuJ926Q3Q2dqVMN2LdjEL1Kq2wJ_RG-rH-e_6v41l1xZbCsQTa3XykQdEiXNc0HtAvT6IRA== +0 -0
  210. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~oc3C7xkUt-OWDL6rrsxs-seS4Fu1bqBWAAXCHalgShaGg9MUrOiRbHT2DcAnhyQFKx6x5FRbvjmYoQWrQiXJZA== +0 -0
  211. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~p-ihj7SEgkDXpMu9hvKE_wiX9cvtwyXrdIn964BfedXHKGpC6o7mMPxEyC0kRPVi_EZs_MRV5bAPEpl5h5we0g== +0 -0
  212. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~qlhO_D9oE8uSKH-mZqyRF9pp4Zv1Tv0dIYcqrH4hb1VWlIxcdxmg2j0M8496cQeFXC5bn_JMXdBlD-d6cnFF8w== +0 -0
  213. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~tjpiyIxJR_boTdUNrtFDuKIZoY84fI4lA1oMJbq9e2ZmYKIK5FeRN2O8cV_yMOYJGr4lbv03kTmT70mCjUc2_Q== +0 -0
  214. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~wULeoj18eEKJWAKx1uFQVwS48cUGFcYPRJQj1Ro5XNJsWCwppGSCdIPhwifD6Z2f_j3zfI2SmC2Gg81sBXXW7g== +0 -0
  215. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~zrEihMys4NVV5rx6FmuzEGO2TjloI3OiC7yzIhvqYoRo43ibb2F-Km6Jf4NX-ac62pOLBYZRcjQTvYMpn75_oA== +0 -0
  216. package/Tests/Artifacts/LottieTests.xcresult/Info.plist +0 -29
  217. package/Tests/Samples/9squares_AlBoardman.json +0 -1
  218. package/Tests/Samples/Boat_Loader.json +0 -1
  219. package/Tests/Samples/HamburgerArrow.json +0 -1
  220. package/Tests/Samples/IconTransitions.json +0 -1
  221. package/Tests/Samples/Images/dog.png +0 -0
  222. package/Tests/Samples/Issues/issue_1403.json +0 -1
  223. package/Tests/Samples/Issues/issue_1407.json +0 -1
  224. package/Tests/Samples/Issues/issue_1488.json +0 -1
  225. package/Tests/Samples/Issues/issue_1505.json +0 -1
  226. package/Tests/Samples/Issues/issue_1628.json +0 -1
  227. package/Tests/Samples/Issues/pr_1536.json +0 -1
  228. package/Tests/Samples/Issues/pr_1563.json +0 -8439
  229. package/Tests/Samples/Issues/pr_1592.json +0 -5527
  230. package/Tests/Samples/Issues/pr_1599.json +0 -738
  231. package/Tests/Samples/Issues/pr_1604_1.json +0 -1
  232. package/Tests/Samples/Issues/pr_1604_2.json +0 -1
  233. package/Tests/Samples/LottieFiles/LICENSE.md +0 -14
  234. package/Tests/Samples/LottieFiles/bounce_strokes.json +0 -1
  235. package/Tests/Samples/LottieFiles/cactus.json +0 -1
  236. package/Tests/Samples/LottieFiles/dog_car_ride.json +0 -1
  237. package/Tests/Samples/LottieFiles/draft_icon.json +0 -1
  238. package/Tests/Samples/LottieFiles/gradient_1.json +0 -1
  239. package/Tests/Samples/LottieFiles/gradient_2.json +0 -1
  240. package/Tests/Samples/LottieFiles/gradient_pill.json +0 -1
  241. package/Tests/Samples/LottieFiles/gradient_shapes.json +0 -1
  242. package/Tests/Samples/LottieFiles/gradient_square.json +0 -1
  243. package/Tests/Samples/LottieFiles/growth.json +0 -1
  244. package/Tests/Samples/LottieFiles/infinity_loader.json +0 -1
  245. package/Tests/Samples/LottieFiles/loading_dots_1.json +0 -1
  246. package/Tests/Samples/LottieFiles/loading_dots_2.json +0 -1
  247. package/Tests/Samples/LottieFiles/loading_dots_3.json +0 -1
  248. package/Tests/Samples/LottieFiles/loading_gradient_strokes.json +0 -1
  249. package/Tests/Samples/LottieFiles/settings_slider.json +0 -1
  250. package/Tests/Samples/LottieFiles/shop.json +0 -1
  251. package/Tests/Samples/LottieFiles/step_loader.json +0 -1
  252. package/Tests/Samples/LottieLogo1.json +0 -1
  253. package/Tests/Samples/LottieLogo1_masked.json +0 -1
  254. package/Tests/Samples/LottieLogo2.json +0 -1
  255. package/Tests/Samples/MotionCorpse_Jrcanest.json +0 -1
  256. package/Tests/Samples/Nonanimating/BasicLayers.json +0 -1
  257. package/Tests/Samples/Nonanimating/DisableNodesTest.json +0 -1
  258. package/Tests/Samples/Nonanimating/FirstText.json +0 -1
  259. package/Tests/Samples/Nonanimating/GeometryTransformTest.json +0 -1
  260. package/Tests/Samples/Nonanimating/Text_AnimatedProperties.json +0 -1
  261. package/Tests/Samples/Nonanimating/Text_Glyph.json +0 -1
  262. package/Tests/Samples/Nonanimating/Text_NoAnimation.json +0 -1
  263. package/Tests/Samples/Nonanimating/Text_NoGlyph.json +0 -1
  264. package/Tests/Samples/Nonanimating/Zoom.json +0 -1
  265. package/Tests/Samples/Nonanimating/_dog.json +0 -1
  266. package/Tests/Samples/Nonanimating/base64Test.json +0 -1
  267. package/Tests/Samples/Nonanimating/blend_mode_test.json +0 -1
  268. package/Tests/Samples/Nonanimating/keypathTest.json +0 -1
  269. package/Tests/Samples/Nonanimating/verifyLineHeight.json +0 -1
  270. package/Tests/Samples/PinJump.json +0 -1
  271. package/Tests/Samples/Private/BrokenLottieFiles/growth_man.json +0 -874
  272. package/Tests/Samples/Private/BrokenLottieFiles/rocket.json +0 -1
  273. package/Tests/Samples/Private/China_EmptyState_Itinerary.json +0 -1
  274. package/Tests/Samples/Private/LoaderHourglass.json +0 -12070
  275. package/Tests/Samples/Private/README.md +0 -7
  276. package/Tests/Samples/Private/Urgency/alarm_animated.json +0 -1
  277. package/Tests/Samples/Private/Urgency/diamond_animated.json +0 -1
  278. package/Tests/Samples/Private/Urgency/eye_animated.json +0 -1
  279. package/Tests/Samples/Private/Urgency/light_bulb_animated.json +0 -1
  280. package/Tests/Samples/Private/Urgency/light_bulb_static.json +0 -1
  281. package/Tests/Samples/Private/Urgency/piggy_bank_static.json +0 -1
  282. package/Tests/Samples/Private/Urgency/price_tag_legacy.json +0 -1
  283. package/Tests/Samples/Private/Urgency/rausch_alarm.json +0 -1
  284. package/Tests/Samples/Private/Urgency/rausch_alert.json +0 -1
  285. package/Tests/Samples/Private/Urgency/rausch_clock.json +0 -1
  286. package/Tests/Samples/Private/Urgency/rausch_diamond.json +0 -1
  287. package/Tests/Samples/Private/Urgency/rausch_money.json +0 -1
  288. package/Tests/Samples/Private/Urgency/rausch_piggy_bank.json +0 -1
  289. package/Tests/Samples/Private/Urgency/rausch_tag.json +0 -1
  290. package/Tests/Samples/Private/Urgency/red_envelope_animated.json +0 -1
  291. package/Tests/Samples/Private/Urgency/tag_animated.json +0 -1
  292. package/Tests/Samples/Private/Urgency/trophy_animated.json +0 -1
  293. package/Tests/Samples/Private/Urgency/wings_key_animated.json +0 -1
  294. package/Tests/Samples/Private/_flexible.json +0 -1
  295. package/Tests/Samples/Private/aircover.json +0 -1
  296. package/Tests/Samples/Private/belo_spin_rausch.json +0 -1
  297. package/Tests/Samples/Private/celebration.json +0 -2821
  298. package/Tests/Samples/Private/checkbox.json +0 -1
  299. package/Tests/Samples/Private/checkbox_small.json +0 -1
  300. package/Tests/Samples/Private/getting_your_trip_ready.json +0 -3540
  301. package/Tests/Samples/Private/gradient_afternoon.json +0 -1
  302. package/Tests/Samples/Private/gradient_brand.json +0 -1
  303. package/Tests/Samples/Private/gradient_evening.json +0 -1
  304. package/Tests/Samples/Private/gradient_morning.json +0 -1
  305. package/Tests/Samples/Private/issue_1467.json +0 -1
  306. package/Tests/Samples/Private/loading_dots.json +0 -1
  307. package/Tests/Samples/Private/loading_dots_small.json +0 -1
  308. package/Tests/Samples/Private/payment_loader.json +0 -1
  309. package/Tests/Samples/Private/radio_button.json +0 -1
  310. package/Tests/Samples/Private/selfie_intro.json +0 -1
  311. package/Tests/Samples/Private/stepper_add.json +0 -1
  312. package/Tests/Samples/Private/stepper_subtract.json +0 -1
  313. package/Tests/Samples/Private/switch.json +0 -1
  314. package/Tests/Samples/Private/thumb.json +0 -1
  315. package/Tests/Samples/Private/toggle_no.json +0 -1
  316. package/Tests/Samples/Private/toggle_yes.json +0 -1
  317. package/Tests/Samples/Private/user_error_black_and_white.json +0 -1
  318. package/Tests/Samples/Private/user_error_cut_off.json +0 -1
  319. package/Tests/Samples/Switch.json +0 -1
  320. package/Tests/Samples/Switch_States.json +0 -1
  321. package/Tests/Samples/TwitterHeart.json +0 -1
  322. package/Tests/Samples/TwitterHeartButton.json +0 -1
  323. package/Tests/Samples/TypeFace/A.json +0 -1
  324. package/Tests/Samples/TypeFace/Apostrophe.json +0 -1
  325. package/Tests/Samples/TypeFace/B.json +0 -1
  326. package/Tests/Samples/TypeFace/BlinkingCursor.json +0 -1
  327. package/Tests/Samples/TypeFace/C.json +0 -1
  328. package/Tests/Samples/TypeFace/Colon.json +0 -1
  329. package/Tests/Samples/TypeFace/Comma.json +0 -1
  330. package/Tests/Samples/TypeFace/D.json +0 -1
  331. package/Tests/Samples/TypeFace/E.json +0 -1
  332. package/Tests/Samples/TypeFace/F.json +0 -1
  333. package/Tests/Samples/TypeFace/G.json +0 -1
  334. package/Tests/Samples/TypeFace/H.json +0 -1
  335. package/Tests/Samples/TypeFace/I.json +0 -1
  336. package/Tests/Samples/TypeFace/J.json +0 -1
  337. package/Tests/Samples/TypeFace/K.json +0 -1
  338. package/Tests/Samples/TypeFace/L.json +0 -1
  339. package/Tests/Samples/TypeFace/M.json +0 -1
  340. package/Tests/Samples/TypeFace/N.json +0 -1
  341. package/Tests/Samples/TypeFace/O.json +0 -1
  342. package/Tests/Samples/TypeFace/P.json +0 -1
  343. package/Tests/Samples/TypeFace/Q.json +0 -1
  344. package/Tests/Samples/TypeFace/R.json +0 -1
  345. package/Tests/Samples/TypeFace/S.json +0 -1
  346. package/Tests/Samples/TypeFace/T.json +0 -1
  347. package/Tests/Samples/TypeFace/U.json +0 -1
  348. package/Tests/Samples/TypeFace/V.json +0 -1
  349. package/Tests/Samples/TypeFace/W.json +0 -1
  350. package/Tests/Samples/TypeFace/X.json +0 -1
  351. package/Tests/Samples/TypeFace/Y.json +0 -1
  352. package/Tests/Samples/TypeFace/Z.json +0 -1
  353. package/Tests/Samples/Watermelon.json +0 -1
  354. package/Tests/Samples/setValueTest.json +0 -1
  355. package/Tests/Samples/timeremap.json +0 -1
  356. package/Tests/Samples/vcTransition1.json +0 -1
  357. package/Tests/Samples/vcTransition2.json +0 -1
  358. package/script/lint/airbnb.swiftformat +0 -68
  359. package/script/lint/swiftlint.yml +0 -38
  360. package/script/test-carthage/Carthage/Build/.lottie-ios.version +0 -19
  361. package/script/test-carthage/Carthage/Build/Lottie.xcframework/Info.plist +0 -46
  362. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/BCSymbolMaps/BF971162-BE99-3507-B5B3-11947DC6B176.bcsymbolmap +0 -14778
  363. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Headers/Lottie-Swift.h +0 -673
  364. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Info.plist +0 -0
  365. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Lottie +0 -0
  366. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Modules/Lottie.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  367. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Modules/Lottie.swiftmodule/arm64-apple-ios.swiftmodule +0 -0
  368. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Modules/Lottie.swiftmodule/arm64.swiftdoc +0 -0
  369. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Modules/Lottie.swiftmodule/arm64.swiftmodule +0 -0
  370. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/Lottie.framework/Modules/module.modulemap +0 -4
  371. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/dSYMs/Lottie.framework.dSYM/Contents/Info.plist +0 -20
  372. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64/dSYMs/Lottie.framework.dSYM/Contents/Resources/DWARF/Lottie +0 -0
  373. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Headers/Lottie-Swift.h +0 -1352
  374. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Info.plist +0 -0
  375. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Lottie +0 -0
  376. 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
  377. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/Project/arm64.swiftsourceinfo +0 -0
  378. 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
  379. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/Project/x86_64.swiftsourceinfo +0 -0
  380. 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
  381. 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
  382. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/arm64.swiftdoc +0 -0
  383. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/arm64.swiftmodule +0 -0
  384. 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
  385. 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
  386. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/x86_64.swiftdoc +0 -0
  387. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/Lottie.swiftmodule/x86_64.swiftmodule +0 -0
  388. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/Modules/module.modulemap +0 -4
  389. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/Lottie.framework/_CodeSignature/CodeResources +0 -256
  390. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/dSYMs/Lottie.framework.dSYM/Contents/Info.plist +0 -20
  391. package/script/test-carthage/Carthage/Build/Lottie.xcframework/ios-arm64_x86_64-simulator/dSYMs/Lottie.framework.dSYM/Contents/Resources/DWARF/Lottie +0 -0
  392. package/script/test-carthage/Carthage/Checkouts/lottie-ios/Lottie.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  393. package/script/test-carthage/Carthage/Checkouts/lottie-ios/Lottie.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +0 -37
  394. package/script/test-carthage/Carthage/Checkouts/lottie-ios/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
package/Rakefile CHANGED
@@ -75,6 +75,7 @@ namespace :test do
75
75
 
76
76
  # Build a test app that imports and uses the LottieCarthage framework
77
77
  xcodebuild('build -scheme CarthageTest -destination "platform=iOS Simulator,name=iPhone 8"')
78
+ xcodebuild('build -scheme CarthageTest-macOS')
78
79
  end
79
80
  end
80
81
 
@@ -91,19 +92,8 @@ end
91
92
 
92
93
  namespace :lint do
93
94
  desc 'Lints swift files'
94
- task swift: ['swift:swiftlint', 'swift:swiftformat']
95
-
96
- desc 'Lints swift files'
97
- namespace :swift do
98
- desc 'Lints swift files using SwiftLint'
99
- task :swiftlint do
100
- sh 'mint run SwiftLint lint Sources Tests Example Package.swift --config script/lint/swiftlint.yml --strict'
101
- end
102
-
103
- desc 'Lints swift files using SwiftLint'
104
- task :swiftformat do
105
- sh 'mint run SwiftFormat Sources Tests Example Package.swift --config script/lint/airbnb.swiftformat --lint'
106
- end
95
+ task :swift do
96
+ formatTool('format --lint')
107
97
  end
108
98
 
109
99
  desc 'Lints the CocoaPods podspec'
@@ -113,13 +103,58 @@ namespace :lint do
113
103
  end
114
104
 
115
105
  namespace :format do
116
- desc 'Runs SwiftFormat'
106
+ desc 'Formats swift files'
117
107
  task :swift do
118
- sh 'mint run SwiftLint autocorrect Sources Tests Example Package.swift --config script/lint/swiftlint.yml'
119
- sh 'mint run SwiftFormat Sources Tests Example Package.swift --config script/lint/airbnb.swiftformat'
108
+ formatTool('format')
120
109
  end
121
110
  end
122
111
 
123
112
  def xcodebuild(command)
124
- sh "set -o pipefail && xcodebuild #{command} | mint run xcbeautify"
113
+ # Check if the mint tool is installed -- if so, pipe the xcodebuild output through xcbeautify
114
+ `which mint`
115
+
116
+ if $?.success?
117
+ sh "set -o pipefail && xcodebuild #{command} | mint run thii/xcbeautify@0.10.2"
118
+ else
119
+ sh "xcodebuild #{command}"
120
+ end
125
121
  end
122
+
123
+ def formatTool(command)
124
+ # As of Xcode 13.4 / Xcode 14 beta 4, including airbnb/swift as a dependency
125
+ # causes Xcode to spin indefinitely at 100% CPU (due to the remote binary dependencies
126
+ # used by that package). As a workaround, we can specifically add that dependency
127
+ # to our Package.swift file when linting / formatting and remove it afterwards.
128
+ packageDefinition = File.read('Package.swift')
129
+ packageDefinitionWithFormatDependency = packageDefinition +
130
+ <<~EOC
131
+
132
+ #if swift(>=5.6)
133
+ // Add the Airbnb Swift formatting plugin if possible
134
+ package.dependencies.append(
135
+ .package(
136
+ url: "https://github.com/airbnb/swift",
137
+ // Since we don't have a Package.resolved for this, we need to reference a specific commit
138
+ // so changes to the style guide don't cause this repo's checks to start failing.
139
+ .revision("cec29280c35dd6eccba415fa3bfc24c819eae887")))
140
+ #endif
141
+ EOC
142
+
143
+ # Add the format tool dependency to our Package.swift
144
+ File.write('Package.swift', packageDefinitionWithFormatDependency)
145
+
146
+ exitCode = 0
147
+
148
+ # Run the given command
149
+ begin
150
+ sh "swift package --allow-writing-to-package-directory #{command}"
151
+ rescue
152
+ exitCode = $?.exitstatus
153
+ ensure
154
+ # Revert the changes to Package.swift
155
+ File.write('Package.swift', packageDefinition)
156
+ File.delete('Package.resolved')
157
+ end
158
+
159
+ exit exitCode
160
+ end
@@ -5,10 +5,12 @@ import QuartzCore
5
5
 
6
6
  extension CAAnimation {
7
7
  /// Creates a `CAAnimation` that wraps this animation,
8
- /// applying timing-related configuration from the given `LayerAnimationContext`
8
+ /// applying timing-related configuration from the given `LayerAnimationContext`.
9
+ /// - This animation should start at the beginning of the animation and
10
+ /// last the entire duration of the animation. It will be trimmed and retimed
11
+ /// to match the current playback state / looping configuration of the animation view.
9
12
  @nonobjc
10
13
  func timed(with context: LayerAnimationContext, for layer: CALayer) -> CAAnimation {
11
-
12
14
  // The base animation always has the duration of the full animation,
13
15
  // since that's the time space where keyframing and interpolating happens.
14
16
  // So we start with a simple animation timeline from 0% to 100%:
@@ -69,6 +71,9 @@ extension CAAnimation {
69
71
 
70
72
  extension CALayer {
71
73
  /// Adds the given animation to this layer, timed with the given timing configuration
74
+ /// - The given animation should start at the beginning of the animation and
75
+ /// last the entire duration of the animation. It will be trimmed and retimed
76
+ /// to match the current playback state / looping configuration of the animation view.
72
77
  @nonobjc
73
78
  func add(_ animation: CAPropertyAnimation, timedWith context: LayerAnimationContext) {
74
79
  add(animation.timed(with: context, for: self), forKey: animation.keyPath)
@@ -28,7 +28,8 @@ extension CALayer {
28
28
  value: keyframeValueMapping,
29
29
  context: context)
30
30
  {
31
- add(defaultAnimation, timedWith: context)
31
+ let timedAnimation = defaultAnimation.timed(with: context, for: self)
32
+ add(timedAnimation, forKey: property.caLayerKeypath)
32
33
  }
33
34
  }
34
35
 
@@ -44,7 +45,7 @@ extension CALayer {
44
45
  value keyframeValueMapping: (KeyframeValue) throws -> ValueRepresentation,
45
46
  context: LayerAnimationContext)
46
47
  throws
47
- -> CAPropertyAnimation?
48
+ -> CAAnimation?
48
49
  {
49
50
  guard !keyframes.isEmpty else { return nil }
50
51
 
@@ -52,39 +53,31 @@ extension CALayer {
52
53
  // by applying that value directly to the layer instead of creating
53
54
  // a relatively expensive `CAKeyframeAnimation`.
54
55
  if keyframes.count == 1 {
55
- let keyframeValue = try keyframeValueMapping(keyframes[0].value)
56
-
57
- // If the keyframe value is the same as the layer's default value for this property,
58
- // then we can just ignore this set of keyframes.
59
- if keyframeValue == property.defaultValue {
60
- return nil
61
- }
56
+ return singleKeyframeAnimation(
57
+ for: property,
58
+ keyframeValue: try keyframeValueMapping(keyframes[0].value),
59
+ writeDirectlyToPropertyIfPossible: true)
60
+ }
62
61
 
63
- // If the property on the CALayer being animated hasn't been modified from the default yet,
64
- // then we can apply the keyframe value directly to the layer using KVC instead
65
- // of creating a `CAAnimation`.
66
- if
67
- let defaultValue = property.defaultValue,
68
- defaultValue == value(forKey: property.caLayerKeypath) as? ValueRepresentation
69
- {
70
- setValue(keyframeValue, forKeyPath: property.caLayerKeypath)
71
- return nil
72
- }
62
+ // Split the keyframes into segments with the same `CAAnimationCalculationMode` value
63
+ // - Each of these segments will become their own `CAKeyframeAnimation`
64
+ let animationSegments = keyframes.segmentsSplitByCalculationMode()
73
65
 
74
- // Otherwise, we still need to create a `CAAnimation`, but we can
75
- // create a simple `CABasicAnimation` that is still less expensive
76
- // than computing a `CAKeyframeAnimation`.
77
- let animation = CABasicAnimation(keyPath: property.caLayerKeypath)
78
- animation.fromValue = keyframeValue
79
- animation.toValue = keyframeValue
80
- return animation
66
+ // If we only have a single segment, we can just create a single `CAKeyframeAnimation`
67
+ // instead of wrapping it in a `CAAnimationGroup` -- this reduces allocation overhead a bit.
68
+ if animationSegments.count == 1 {
69
+ return try keyframeAnimation(
70
+ for: property,
71
+ keyframes: animationSegments[0],
72
+ value: keyframeValueMapping,
73
+ context: context)
74
+ } else {
75
+ return try animationGroup(
76
+ for: property,
77
+ animationSegments: animationSegments,
78
+ value: keyframeValueMapping,
79
+ context: context)
81
80
  }
82
-
83
- return try keyframeAnimation(
84
- for: property,
85
- keyframes: keyframes,
86
- value: keyframeValueMapping,
87
- context: context)
88
81
  }
89
82
 
90
83
  /// A `CAAnimation` that applies the custom value from the `AnyValueProvider`
@@ -106,32 +99,142 @@ extension CALayer {
106
99
  else { return nil }
107
100
 
108
101
  // Since custom animations are overriding an existing animation,
109
- // we always have to create a CAKeyframeAnimation for these instead of
110
- // letting `defaultAnimation(...)` try to apply the value using KVC.
102
+ // we always have to create a CAAnimation and can't write directly
103
+ // to the layer property
104
+ if
105
+ customKeyframes.keyframes.count == 1,
106
+ let singleKeyframeAnimation = singleKeyframeAnimation(
107
+ for: property,
108
+ keyframeValue: customKeyframes.keyframes[0].value,
109
+ writeDirectlyToPropertyIfPossible: false)
110
+ {
111
+ return singleKeyframeAnimation
112
+ }
113
+
111
114
  return try keyframeAnimation(
112
115
  for: property,
113
- keyframes: customKeyframes.keyframes,
116
+ keyframes: Array(customKeyframes.keyframes),
114
117
  value: { $0 },
115
118
  context: context)
116
119
  }
117
120
 
118
- /// Creates a `CAKeyframeAnimation` for the given keyframes
121
+ /// Creates an animation that applies a single keyframe to this layer property
122
+ /// - In many cases this animation can be omitted entirely, and the underlying
123
+ /// property can be set directly. In that case, no animation will be created.
124
+ private func singleKeyframeAnimation<ValueRepresentation>(
125
+ for property: LayerProperty<ValueRepresentation>,
126
+ keyframeValue: ValueRepresentation,
127
+ writeDirectlyToPropertyIfPossible: Bool)
128
+ -> CABasicAnimation?
129
+ {
130
+ if writeDirectlyToPropertyIfPossible {
131
+ // If the keyframe value is the same as the layer's default value for this property,
132
+ // then we can just ignore this set of keyframes.
133
+ if keyframeValue == property.defaultValue {
134
+ return nil
135
+ }
136
+
137
+ // If the property on the CALayer being animated hasn't been modified from the default yet,
138
+ // then we can apply the keyframe value directly to the layer using KVC instead
139
+ // of creating a `CAAnimation`.
140
+ if
141
+ let defaultValue = property.defaultValue,
142
+ defaultValue == value(forKey: property.caLayerKeypath) as? ValueRepresentation
143
+ {
144
+ setValue(keyframeValue, forKeyPath: property.caLayerKeypath)
145
+ return nil
146
+ }
147
+ }
148
+
149
+ // Otherwise, we still need to create a `CAAnimation`, but we can
150
+ // create a simple `CABasicAnimation` that is still less expensive
151
+ // than computing a `CAKeyframeAnimation`.
152
+ let animation = CABasicAnimation(keyPath: property.caLayerKeypath)
153
+ animation.fromValue = keyframeValue
154
+ animation.toValue = keyframeValue
155
+ return animation
156
+ }
157
+
158
+ /// Creates a `CAAnimationGroup` that wraps a `CAKeyframeAnimation` for each
159
+ /// of the given `animationSegments`
160
+ private func animationGroup<KeyframeValue, ValueRepresentation>(
161
+ for property: LayerProperty<ValueRepresentation>,
162
+ animationSegments: [[Keyframe<KeyframeValue>]],
163
+ value keyframeValueMapping: (KeyframeValue) throws -> ValueRepresentation,
164
+ context: LayerAnimationContext)
165
+ throws
166
+ -> CAAnimationGroup
167
+ {
168
+ // Build the `CAKeyframeAnimation` for each segment of keyframes
169
+ // with the same `CAAnimationCalculationMode`.
170
+ // - Here we have a non-zero number of animation segments,
171
+ // all of which have a non-zero number of keyframes.
172
+ let segmentAnimations: [CAKeyframeAnimation] = try animationSegments.indices.map { index in
173
+ let animationSegment = animationSegments[index]
174
+ var segmentStartTime = context.time(for: animationSegment.first!.time)
175
+ var segmentEndTime = context.time(for: animationSegment.last!.time)
176
+
177
+ // Every portion of the animation timeline has to be covered by a `CAKeyframeAnimation`,
178
+ // so if this is the first or last segment then the start/end time should be exactly
179
+ // the start/end time of the animation itself.
180
+ let isFirstSegment = (index == animationSegments.indices.first!)
181
+ let isLastSegment = (index == animationSegments.indices.last!)
182
+
183
+ if isFirstSegment {
184
+ segmentStartTime = context.time(for: context.animation.startFrame)
185
+ }
186
+
187
+ if isLastSegment {
188
+ segmentEndTime = context.time(for: context.animation.endFrame)
189
+ }
190
+
191
+ let segmentDuration = segmentEndTime - segmentStartTime
192
+
193
+ // We're building `CAKeyframeAnimation`s, so the `keyTimes` are expressed
194
+ // relative to 0 (`segmentStartTime`) and 1 (`segmentEndTime`). This is different
195
+ // from the default behavior of the `keyframeAnimation` method, where times
196
+ // are expressed relative to the entire animation duration.
197
+ let customKeyTimes = animationSegment.map { keyframeModel -> NSNumber in
198
+ let keyframeTime = context.time(for: keyframeModel.time)
199
+ let segmentProgressTime = ((keyframeTime - segmentStartTime) / segmentDuration)
200
+ return segmentProgressTime as NSNumber
201
+ }
202
+
203
+ let animation = try keyframeAnimation(
204
+ for: property,
205
+ keyframes: animationSegment,
206
+ value: keyframeValueMapping,
207
+ customKeyTimes: customKeyTimes,
208
+ context: context)
209
+
210
+ animation.duration = segmentDuration
211
+ animation.beginTime = segmentStartTime
212
+ return animation
213
+ }
214
+
215
+ let fullAnimation = CAAnimationGroup()
216
+ fullAnimation.animations = segmentAnimations
217
+ return fullAnimation
218
+ }
219
+
220
+ /// Creates and validates a `CAKeyframeAnimation` for the given keyframes
119
221
  private func keyframeAnimation<KeyframeValue, ValueRepresentation>(
120
222
  for property: LayerProperty<ValueRepresentation>,
121
- keyframes: ContiguousArray<Keyframe<KeyframeValue>>,
223
+ keyframes: [Keyframe<KeyframeValue>],
122
224
  value keyframeValueMapping: (KeyframeValue) throws -> ValueRepresentation,
225
+ customKeyTimes: [NSNumber]? = nil,
123
226
  context: LayerAnimationContext)
124
227
  throws
125
228
  -> CAKeyframeAnimation
126
229
  {
127
230
  // Convert the list of `Keyframe<T>` into
128
231
  // the representation used by `CAKeyframeAnimation`
129
- var keyTimes = keyframes.map { keyframeModel -> NSNumber in
232
+ var keyTimes = customKeyTimes ?? keyframes.map { keyframeModel -> NSNumber in
130
233
  NSNumber(value: Float(context.progressTime(for: keyframeModel.time)))
131
234
  }
132
235
 
133
236
  var timingFunctions = self.timingFunctions(for: keyframes)
134
- let calculationMode = try self.calculationMode(for: keyframes, context: context)
237
+ let calculationMode = self.calculationMode(for: keyframes)
135
238
 
136
239
  let animation = CAKeyframeAnimation(keyPath: property.caLayerKeypath)
137
240
 
@@ -173,37 +276,22 @@ extension CALayer {
173
276
  /// The `CAAnimationCalculationMode` that should be used for a `CAKeyframeAnimation`
174
277
  /// animating the given keyframes
175
278
  private func calculationMode<KeyframeValue>(
176
- for keyframes: ContiguousArray<Keyframe<KeyframeValue>>,
177
- context: LayerAnimationContext)
178
- throws
279
+ for keyframes: [Keyframe<KeyframeValue>])
179
280
  -> CAAnimationCalculationMode
180
281
  {
181
- // Animations using `isHold` should use `CAAnimationCalculationMode.discrete`
182
- //
183
- // - Since we currently only create a single `CAKeyframeAnimation`,
184
- // we can currently only correctly support animations where
185
- // `isHold` is either always `true` or always `false`
186
- // (this requirement doesn't apply to the first/last keyframes).
187
- //
188
- // - We should be able to support this in the future by creating multiple
189
- // `CAKeyframeAnimation`s with different `calculationMode`s and
190
- // playing them sequentially.
191
- //
192
- let intermediateKeyframes = keyframes.dropFirst().dropLast()
193
- if intermediateKeyframes.contains(where: \.isHold) {
194
- if intermediateKeyframes.allSatisfy(\.isHold) {
195
- return .discrete
196
- } else {
197
- try context.logCompatibilityIssue("Mixed `isHold` / `!isHold` keyframes are currently unsupported")
198
- }
282
+ // At this point we expect all of the animations to have been split in
283
+ // to segments based on the `CAAnimationCalculationMode`, so we can just
284
+ // check the first keyframe.
285
+ if keyframes[0].isHold {
286
+ return .discrete
287
+ } else {
288
+ return .linear
199
289
  }
200
-
201
- return .linear
202
290
  }
203
291
 
204
292
  /// `timingFunctions` to apply to a `CAKeyframeAnimation` animating the given keyframes
205
293
  private func timingFunctions<KeyframeValue>(
206
- for keyframes: ContiguousArray<Keyframe<KeyframeValue>>)
294
+ for keyframes: [Keyframe<KeyframeValue>])
207
295
  -> [CAMediaTimingFunction]
208
296
  {
209
297
  // Compute the timing function between each keyframe and the subsequent keyframe
@@ -231,9 +319,10 @@ extension CALayer {
231
319
  /// Creates a `CGPath` for the given `position` keyframes,
232
320
  /// which accounts for `spatialInTangent`s and `spatialOutTangents`
233
321
  private func path<KeyframeValue>(
234
- keyframes positionKeyframes: ContiguousArray<Keyframe<KeyframeValue>>,
322
+ keyframes positionKeyframes: [Keyframe<KeyframeValue>],
235
323
  value keyframeValueMapping: (KeyframeValue) throws -> CGPoint) rethrows
236
- -> CGPath {
324
+ -> CGPath
325
+ {
237
326
  let path = CGMutablePath()
238
327
 
239
328
  for (index, keyframe) in positionKeyframes.enumerated() {
@@ -247,8 +336,7 @@ extension CALayer {
247
336
  if
248
337
  let controlPoint1 = keyframe.spatialOutTangent?.pointValue,
249
338
  let controlPoint2 = nextKeyframe.spatialInTangent?.pointValue,
250
- controlPoint1 != .zero,
251
- controlPoint2 != .zero
339
+ !(controlPoint1 == .zero && controlPoint2 == .zero)
252
340
  {
253
341
  path.addCurve(
254
342
  to: try keyframeValueMapping(nextKeyframe.value),
@@ -320,3 +408,40 @@ extension CALayer {
320
408
  }
321
409
 
322
410
  }
411
+
412
+ extension RandomAccessCollection {
413
+ /// Splits this array of `Keyframe`s into segments with the same `CAAnimationCalculationMode`
414
+ /// - Keyframes with `isHold=true` become `discrete`, and keyframes with `isHold=false`
415
+ /// become linear. Each `CAKeyframeAnimation` can only be one or the other, so each
416
+ /// `calculationModeSegment` becomes its own `CAKeyframeAnimation`.
417
+ func segmentsSplitByCalculationMode<KeyframeValue>() -> [[Element]]
418
+ where Element == Keyframe<KeyframeValue>, Index == Int
419
+ {
420
+ var segments: [[Element]] = []
421
+ var currentSegment: [Element] = []
422
+
423
+ for keyframe in self {
424
+ guard let mostRecentKeyframe = currentSegment.last else {
425
+ currentSegment.append(keyframe)
426
+ continue
427
+ }
428
+
429
+ // When `isHold` changes between any two given keyframes, we have to create a new segment
430
+ if keyframe.isHold != mostRecentKeyframe.isHold {
431
+ // Add this keyframe to both the existing segment that is ending,
432
+ // so we know how long that segment is, and the new segment,
433
+ // so we know when that segment starts.
434
+ currentSegment.append(keyframe)
435
+ segments.append(currentSegment)
436
+ currentSegment = [keyframe]
437
+ }
438
+
439
+ else {
440
+ currentSegment.append(keyframe)
441
+ }
442
+ }
443
+
444
+ segments.append(currentSegment)
445
+ return segments
446
+ }
447
+ }
@@ -51,3 +51,31 @@ final class CombinedShapeItem: ShapeItem {
51
51
  let shapes: KeyframeGroup<[BezierPath]>
52
52
 
53
53
  }
54
+
55
+ extension CombinedShapeItem {
56
+ /// Manually combines the given shape keyframes by manually interpolating at each frame
57
+ static func manuallyInterpolating(
58
+ shapes: [KeyframeGroup<BezierPath>],
59
+ name: String,
60
+ context: LayerContext)
61
+ -> CombinedShapeItem
62
+ {
63
+ let animationTimeRange = Int(context.animation.startFrame)...Int(context.animation.endFrame)
64
+
65
+ let interpolators = shapes.map { shape in
66
+ KeyframeInterpolator(keyframes: shape.keyframes)
67
+ }
68
+
69
+ let interpolatedKeyframes = animationTimeRange.map { frame in
70
+ Keyframe(
71
+ value: interpolators.compactMap { interpolator in
72
+ interpolator.value(frame: AnimationFrameTime(frame)) as? BezierPath
73
+ },
74
+ time: AnimationFrameTime(frame))
75
+ }
76
+
77
+ return CombinedShapeItem(
78
+ shapes: KeyframeGroup(keyframes: ContiguousArray(interpolatedKeyframes)),
79
+ name: name)
80
+ }
81
+ }
@@ -14,11 +14,11 @@ extension CAShapeLayer {
14
14
  {
15
15
  try addAnimation(
16
16
  for: .path,
17
- keyframes: ellipse.size.keyframes,
18
- value: { sizeKeyframe in
17
+ keyframes: ellipse.combinedKeyframes(context: context).keyframes,
18
+ value: { keyframe in
19
19
  BezierPath.ellipse(
20
- size: sizeKeyframe.sizeValue,
21
- center: try ellipse.position.exactlyOneKeyframe(context: context, description: "ellipse position").value.pointValue,
20
+ size: keyframe.size.sizeValue,
21
+ center: keyframe.position.pointValue,
22
22
  direction: ellipse.direction)
23
23
  .cgPath()
24
24
  .duplicated(times: pathMultiplier)
@@ -26,3 +26,30 @@ extension CAShapeLayer {
26
26
  context: context)
27
27
  }
28
28
  }
29
+
30
+ extension Ellipse {
31
+ /// Data that represents how to render an ellipse at a specific point in time
32
+ struct Keyframe {
33
+ let size: Vector3D
34
+ let position: Vector3D
35
+ }
36
+
37
+ /// Creates a single array of animatable keyframes from the separate arrays of keyframes in this Ellipse
38
+ func combinedKeyframes(context: LayerAnimationContext) throws-> KeyframeGroup<Ellipse.Keyframe> {
39
+ let combinedKeyframes = Keyframes.combinedIfPossible(
40
+ size, position,
41
+ makeCombinedResult: Ellipse.Keyframe.init)
42
+
43
+ if let combinedKeyframes = combinedKeyframes {
44
+ return combinedKeyframes
45
+ } else {
46
+ // If we weren't able to combine all of the keyframes, we have to take the timing values
47
+ // from one property and use a fixed value for the other properties.
48
+ return try size.map { sizeValue in
49
+ Keyframe(
50
+ size: sizeValue,
51
+ position: try position.exactlyOneKeyframe(context: context, description: "ellipse position"))
52
+ }
53
+ }
54
+ }
55
+ }