lottie-ios 3.2.2 → 3.4.1

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 (316) hide show
  1. package/.github/actions/setup/action.yml +32 -0
  2. package/.github/issue_template.md +6 -23
  3. package/.github/workflows/main.yml +98 -0
  4. package/.spi.yml +6 -0
  5. package/.swift-version +1 -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 +2003 -1972
  13. package/Lottie.xcodeproj/project.xcworkspace/contents.xcworkspacedata +1 -1
  14. package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  15. package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_iOS.xcscheme → Lottie (iOS).xcscheme } +15 -18
  16. package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_macOS.xcscheme → Lottie (macOS).xcscheme } +7 -20
  17. package/Lottie.xcodeproj/xcshareddata/xcschemes/{Lottie_tvOS.xcscheme → Lottie (tvOS).xcscheme } +5 -18
  18. package/Lottie.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +37 -0
  19. package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +24 -0
  20. package/Lottie.xcworkspace/contents.xcworkspacedata +10 -0
  21. package/Lottie.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  22. package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +115 -0
  23. package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  24. package/{Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad → Lottie.xcworkspace/xcuserdata/cal.xcuserdatad}/xcdebugger/Breakpoints_v2.xcbkptlist +2 -2
  25. package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/xcdebugger/Expressions.xcexplist +153 -0
  26. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  27. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +39 -0
  28. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +25 -0
  29. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +30 -0
  30. package/Package.resolved +88 -0
  31. package/Package.swift +10 -15
  32. package/README.md +40 -60
  33. package/Rakefile +121 -0
  34. package/Sources/Private/CoreAnimation/Animations/CAAnimation+TimingConfiguration.swift +81 -0
  35. package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +448 -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 +210 -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 +73 -0
  53. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +83 -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 +94 -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 +302 -0
  63. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +319 -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 +93 -85
  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 +75 -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 +61 -44
  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 +42 -36
  76. package/{lottie-swift/src/Private/LayerContainers/AnimationContainer.swift → Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift} +200 -140
  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} +120 -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 +82 -67
  85. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Extensions/ItemsExtension.swift +4 -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 +6 -6
  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 +125 -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 +110 -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 +30 -24
  102. package/{lottie-swift/src/Private/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift → Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift} +93 -66
  103. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +23 -19
  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 +95 -58
  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 +108 -69
  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 +80 -79
  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 +27 -24
  119. package/{lottie-swift/src/Private → Sources/Private/MainThread}/NodeRenderSystem/RenderLayers/ShapeRenderLayer.swift +34 -25
  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/Sources/Private/Model/ShapeItems/Group.swift +48 -0
  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 +164 -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 -48
  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 +450 -0
  168. package/Sources/Private/Utility/Extensions/StringExtensions.swift +38 -0
  169. package/{lottie-swift/src → Sources}/Private/Utility/Helpers/AnimationContext.swift +42 -16
  170. package/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift +134 -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 -143
  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 +184 -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 +266 -0
  182. package/Sources/Public/Animation/AnimationView.swift +1335 -0
  183. package/Sources/Public/Animation/AnimationViewInitializers.swift +109 -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 +123 -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 +137 -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 +42 -26
  204. package/{lottie-swift/src → Sources}/Public/iOS/AnimatedControl.swift +100 -91
  205. package/{lottie-swift/src → Sources}/Public/iOS/AnimatedSwitch.swift +128 -94
  206. package/{lottie-swift/src → Sources}/Public/iOS/AnimationSubview.swift +3 -3
  207. package/Sources/Public/iOS/AnimationViewBase.swift +78 -0
  208. package/{lottie-swift/src → Sources}/Public/iOS/BundleImageProvider.swift +36 -34
  209. package/{lottie-swift/src → Sources}/Public/iOS/Compatibility/CompatibleAnimationKeypath.swift +4 -0
  210. package/{lottie-swift/src → Sources}/Public/iOS/Compatibility/CompatibleAnimationView.swift +38 -29
  211. package/{lottie-swift/src → Sources}/Public/iOS/FilepathImageProvider.swift +24 -21
  212. package/{lottie-swift/src → Sources}/Public/iOS/UIColorExtension.swift +4 -4
  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} +31 -32
  216. package/Sources/Public/macOS/FilepathImageProvider.macOS.swift +67 -0
  217. package/Tests/AnimationKeypathTests.swift +94 -0
  218. package/Tests/AutomaticEngineTests.swift +57 -0
  219. package/Tests/BundleTests.swift +25 -0
  220. package/Tests/DataURLTests.swift +64 -0
  221. package/Tests/ParsingTests.swift +43 -0
  222. package/Tests/PerformanceTests.swift +215 -0
  223. package/Tests/SnapshotConfiguration.swift +153 -0
  224. package/Tests/SnapshotTests.swift +265 -0
  225. package/Tests/Utils/Bundle+Module.swift +30 -0
  226. package/Tests/Utils/HardcodedFontProvider.swift +19 -0
  227. package/Tests/Utils/HardcodedImageProvider.swift +23 -0
  228. package/Tests/Utils/Snapshotting+presentationLayer.swift +47 -0
  229. package/Tests/ValueProvidersTests.swift +27 -0
  230. package/lottie-ios.podspec +11 -12
  231. package/package.json +1 -1
  232. package/script/test-carthage/Cartfile +1 -0
  233. package/script/test-carthage/Cartfile.resolved +1 -0
  234. package/script/test-carthage/CarthageTest/AppDelegate.swift +26 -0
  235. package/script/test-carthage/CarthageTest/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  236. package/script/test-carthage/CarthageTest/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
  237. package/script/test-carthage/CarthageTest/Assets.xcassets/Contents.json +6 -0
  238. package/script/test-carthage/CarthageTest/Base.lproj/LaunchScreen.storyboard +25 -0
  239. package/script/test-carthage/CarthageTest/Base.lproj/Main.storyboard +24 -0
  240. package/script/test-carthage/CarthageTest/Info.plist +66 -0
  241. package/script/test-carthage/CarthageTest/SceneDelegate.swift +10 -0
  242. package/script/test-carthage/CarthageTest/ViewController.swift +15 -0
  243. package/script/test-carthage/CarthageTest-macOS/AppDelegate.swift +7 -0
  244. package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  245. package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json +58 -0
  246. package/script/test-carthage/CarthageTest-macOS/Assets.xcassets/Contents.json +6 -0
  247. package/script/test-carthage/CarthageTest-macOS/Base.lproj/Main.storyboard +717 -0
  248. package/script/test-carthage/CarthageTest-macOS/CarthageTest_macOS.entitlements +10 -0
  249. package/script/test-carthage/CarthageTest-macOS/ViewController.swift +15 -0
  250. package/script/test-carthage/CarthageTest.xcodeproj/project.pbxproj +532 -0
  251. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  252. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  253. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  254. package/script/test-carthage/CarthageTest.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  255. package/script/test-carthage/CarthageTest.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  256. package/script/test-carthage/CarthageTest.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +19 -0
  257. package/script/test-carthage/Mintfile +1 -0
  258. package/script/test-spm/LottieSPM.xcworkspace/contents.xcworkspacedata +7 -0
  259. package/script/test-spm/LottieSPM.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  260. package/script/test-spm/Mintfile +1 -0
  261. package/.swiftpm/xcode/package.xcworkspace/xcuserdata/brandonwithrow.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  262. package/Lottie/Info.plist +0 -22
  263. package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/brandonwithrow.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  264. package/Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad/xcschemes/LottieLibraryMacOS.xcscheme +0 -80
  265. package/Lottie.xcodeproj/xcuserdata/brandonwithrow.xcuserdatad/xcschemes/xcschememanagement.plist +0 -57
  266. package/lottie-swift/Assets/.gitkeep +0 -0
  267. package/lottie-swift/src/Private/LayerContainers/Utility/LayerFontProvider.swift +0 -37
  268. package/lottie-swift/src/Private/LayerContainers/Utility/LayerTextProvider.swift +0 -36
  269. package/lottie-swift/src/Private/Model/Animation.swift +0 -107
  270. package/lottie-swift/src/Private/Model/Assets/Asset.swift +0 -27
  271. package/lottie-swift/src/Private/Model/Assets/ImageAsset.swift +0 -48
  272. package/lottie-swift/src/Private/Model/Keyframes/Keyframe.swift +0 -128
  273. package/lottie-swift/src/Private/Model/Keyframes/KeyframeGroup.swift +0 -108
  274. package/lottie-swift/src/Private/Model/Layers/LayerModel.swift +0 -150
  275. package/lottie-swift/src/Private/Model/Objects/DashPattern.swift +0 -24
  276. package/lottie-swift/src/Private/Model/Objects/Marker.swift +0 -23
  277. package/lottie-swift/src/Private/Model/Objects/Mask.swift +0 -48
  278. package/lottie-swift/src/Private/Model/Objects/Transform.swift +0 -105
  279. package/lottie-swift/src/Private/Model/ShapeItems/Ellipse.swift +0 -50
  280. package/lottie-swift/src/Private/Model/ShapeItems/FillI.swift +0 -49
  281. package/lottie-swift/src/Private/Model/ShapeItems/GradientFill.swift +0 -86
  282. package/lottie-swift/src/Private/Model/ShapeItems/GradientStroke.swift +0 -125
  283. package/lottie-swift/src/Private/Model/ShapeItems/Group.swift +0 -32
  284. package/lottie-swift/src/Private/Model/ShapeItems/Rectangle.swift +0 -50
  285. package/lottie-swift/src/Private/Model/ShapeItems/Repeater.swift +0 -80
  286. package/lottie-swift/src/Private/Model/ShapeItems/Shape.swift +0 -37
  287. package/lottie-swift/src/Private/Model/ShapeItems/ShapeItem.swift +0 -95
  288. package/lottie-swift/src/Private/Model/ShapeItems/ShapeTransform.swift +0 -68
  289. package/lottie-swift/src/Private/Model/ShapeItems/Star.swift +0 -86
  290. package/lottie-swift/src/Private/Model/ShapeItems/Stroke.swift +0 -67
  291. package/lottie-swift/src/Private/Model/ShapeItems/Trim.swift +0 -53
  292. package/lottie-swift/src/Private/Model/Text/Font.swift +0 -35
  293. package/lottie-swift/src/Private/Model/Text/TextAnimator.swift +0 -99
  294. package/lottie-swift/src/Private/Model/Text/TextDocument.swift +0 -70
  295. package/lottie-swift/src/Private/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +0 -109
  296. package/lottie-swift/src/Private/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +0 -132
  297. package/lottie-swift/src/Private/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +0 -141
  298. package/lottie-swift/src/Private/Utility/Extensions/MathKit.swift +0 -539
  299. package/lottie-swift/src/Private/Utility/Extensions/StringExtensions.swift +0 -32
  300. package/lottie-swift/src/Private/Utility/Interpolatable/Interpolatable.swift +0 -18
  301. package/lottie-swift/src/Private/Utility/Interpolatable/InterpolatableExtensions.swift +0 -170
  302. package/lottie-swift/src/Private/Utility/Primitives/CurveVertex.swift +0 -177
  303. package/lottie-swift/src/Private/Utility/Primitives/PathElement.swift +0 -68
  304. package/lottie-swift/src/Private/Utility/Primitives/VectorsExtensions.swift +0 -218
  305. package/lottie-swift/src/Public/Animation/AnimationPublic.swift +0 -196
  306. package/lottie-swift/src/Public/Animation/AnimationView.swift +0 -1006
  307. package/lottie-swift/src/Public/Animation/AnimationViewInitializers.swift +0 -83
  308. package/lottie-swift/src/Public/AnimationCache/AnimationCacheProvider.swift +0 -24
  309. package/lottie-swift/src/Public/DynamicProperties/AnimationKeypath.swift +0 -46
  310. package/lottie-swift/src/Public/DynamicProperties/AnyValueProvider.swift +0 -29
  311. package/lottie-swift/src/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +0 -114
  312. package/lottie-swift/src/Public/ImageProvider/AnimationImageProvider.swift +0 -23
  313. package/lottie-swift/src/Public/MacOS/FilepathImageProvider.swift +0 -67
  314. package/lottie-swift/src/Public/TextProvider/AnimationTextProvider.swift +0 -39
  315. package/lottie-swift/src/Public/iOS/LottieView.swift +0 -62
  316. package/lottie-swift-testing.podspec +0 -32
@@ -8,20 +8,30 @@
8
8
  import Foundation
9
9
 
10
10
  final class PrecompAsset: Asset {
11
-
12
- /// Layers of the precomp
13
- let layers: [LayerModel]
14
-
15
- enum CodingKeys : String, CodingKey {
16
- case layers = "layers"
17
- }
18
-
11
+
12
+ // MARK: Lifecycle
13
+
19
14
  required init(from decoder: Decoder) throws {
20
15
  let container = try decoder.container(keyedBy: PrecompAsset.CodingKeys.self)
21
- self.layers = try container.decode([LayerModel].self, ofFamily: LayerType.self, forKey: .layers)
16
+ layers = try container.decode([LayerModel].self, ofFamily: LayerType.self, forKey: .layers)
22
17
  try super.init(from: decoder)
23
18
  }
24
-
19
+
20
+ required init(dictionary: [String: Any]) throws {
21
+ let layerDictionaries: [[String: Any]] = try dictionary.value(for: CodingKeys.layers)
22
+ layers = try [LayerModel].fromDictionaries(layerDictionaries)
23
+ try super.init(dictionary: dictionary)
24
+ }
25
+
26
+ // MARK: Internal
27
+
28
+ enum CodingKeys: String, CodingKey {
29
+ case layers
30
+ }
31
+
32
+ /// Layers of the precomp
33
+ let layers: [LayerModel]
34
+
25
35
  override func encode(to encoder: Encoder) throws {
26
36
  try super.encode(to: encoder)
27
37
  var container = encoder.container(keyedBy: CodingKeys.self)
@@ -0,0 +1,67 @@
1
+ //
2
+ // DictionaryInitializable.swift
3
+ // Lottie
4
+ //
5
+ // Created by Marcelo Fabri on 5/5/22.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ // MARK: - InitializableError
11
+
12
+ enum InitializableError: Error {
13
+ case invalidInput
14
+ }
15
+
16
+ // MARK: - DictionaryInitializable
17
+
18
+ protocol DictionaryInitializable {
19
+
20
+ init(dictionary: [String: Any]) throws
21
+
22
+ }
23
+
24
+ // MARK: - AnyInitializable
25
+
26
+ protocol AnyInitializable {
27
+
28
+ init(value: Any) throws
29
+
30
+ }
31
+
32
+ extension Dictionary {
33
+
34
+ @_disfavoredOverload
35
+ func value<T, KeyType: RawRepresentable>(for key: KeyType) throws -> T where KeyType.RawValue == Key {
36
+ guard let value = self[key.rawValue] as? T else {
37
+ throw InitializableError.invalidInput
38
+ }
39
+ return value
40
+ }
41
+
42
+ func value<T: AnyInitializable, KeyType: RawRepresentable>(for key: KeyType) throws -> T where KeyType.RawValue == Key {
43
+ if let value = self[key.rawValue] as? T {
44
+ return value
45
+ }
46
+
47
+ if let value = self[key.rawValue] {
48
+ return try T(value: value)
49
+ }
50
+
51
+ throw InitializableError.invalidInput
52
+ }
53
+
54
+ }
55
+
56
+ // MARK: - Array + AnyInitializable
57
+
58
+ extension Array: AnyInitializable where Element == Double {
59
+
60
+ init(value: Any) throws {
61
+ guard let array = value as? [Double] else {
62
+ throw InitializableError.invalidInput
63
+ }
64
+ self = array
65
+ }
66
+
67
+ }
@@ -0,0 +1,34 @@
1
+ import Foundation
2
+ #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
3
+ import UIKit
4
+ #endif
5
+
6
+ extension Bundle {
7
+ func getAnimationData(_ name: String, subdirectory: String? = nil) throws -> Data? {
8
+ // Check for files in the bundle at the given path
9
+ let name = name.removingJSONSuffix()
10
+ if let url = url(forResource: name, withExtension: "json", subdirectory: subdirectory) {
11
+ return try Data(contentsOf: url)
12
+ }
13
+
14
+ // Check for data assets (not available on macOS)
15
+ #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
16
+ let assetKey = subdirectory != nil ? "\(subdirectory ?? "")/\(name)" : name
17
+ return NSDataAsset(name: assetKey, bundle: self)?.data
18
+ #else
19
+ return nil
20
+ #endif
21
+ }
22
+ }
23
+
24
+ extension String {
25
+ fileprivate func removingJSONSuffix() -> String {
26
+ // Allow filenames to be passed with a ".json" extension (but not other extensions)
27
+ // to keep the behavior from Lottie 2.x - instead of failing to load the animation
28
+ guard hasSuffix(".json") else {
29
+ return self
30
+ }
31
+
32
+ return (self as NSString).deletingPathExtension
33
+ }
34
+ }
@@ -2,30 +2,34 @@
2
2
 
3
3
  import Foundation
4
4
 
5
+ // MARK: - ClassFamily
6
+
5
7
  /// To support a new class family, create an enum that conforms to this protocol and contains the different types.
6
8
  protocol ClassFamily: Decodable {
7
9
  /// The discriminator key.
8
10
  static var discriminator: Discriminator { get }
9
-
11
+
10
12
  /// Returns the class type of the object corresponding to the value.
11
13
  func getType() -> AnyObject.Type
12
14
  }
13
15
 
16
+ // MARK: - Discriminator
17
+
14
18
  /// Discriminator key enum used to retrieve discriminator fields in JSON payloads.
15
19
  enum Discriminator: String, CodingKey {
16
20
  case type = "ty"
17
21
  }
18
22
 
19
23
  extension KeyedDecodingContainer {
20
-
24
+
21
25
  /// Decode a heterogeneous list of objects for a given family.
22
26
  /// - Parameters:
23
27
  /// - heterogeneousType: The decodable type of the list.
24
28
  /// - family: The ClassFamily enum for the type family.
25
29
  /// - key: The CodingKey to look up the list in the current container.
26
30
  /// - Returns: The resulting list of heterogeneousType elements.
27
- func decode<T : Decodable, U : ClassFamily>(_ heterogeneousType: [T].Type, ofFamily family: U.Type, forKey key: K) throws -> [T] {
28
- var container = try self.nestedUnkeyedContainer(forKey: key)
31
+ func decode<T: Decodable, U: ClassFamily>(_: [T].Type, ofFamily family: U.Type, forKey key: K) throws -> [T] {
32
+ var container = try nestedUnkeyedContainer(forKey: key)
29
33
  var list = [T]()
30
34
  var tmpContainer = container
31
35
  while !container.isAtEnd {
@@ -0,0 +1,113 @@
1
+ //
2
+ // Keyframe.swift
3
+ // lottie-swift
4
+ //
5
+ // Created by Brandon Withrow on 1/7/19.
6
+ //
7
+
8
+ import CoreGraphics
9
+ import Foundation
10
+
11
+ // MARK: - KeyframeData
12
+
13
+ /// A generic class used to parse and remap keyframe json.
14
+ ///
15
+ /// Keyframe json has a couple of different variations and formats depending on the
16
+ /// type of keyframea and also the version of the JSON. By parsing the raw data
17
+ /// we can reconfigure it into a constant format.
18
+ final class KeyframeData<T> {
19
+
20
+ // MARK: Lifecycle
21
+
22
+ init(
23
+ startValue: T?,
24
+ endValue: T?,
25
+ time: AnimationFrameTime?,
26
+ hold: Int?,
27
+ inTangent: Vector2D?,
28
+ outTangent: Vector2D?,
29
+ spatialInTangent: Vector3D?,
30
+ spatialOutTangent: Vector3D?)
31
+ {
32
+ self.startValue = startValue
33
+ self.endValue = endValue
34
+ self.time = time
35
+ self.hold = hold
36
+ self.inTangent = inTangent
37
+ self.outTangent = outTangent
38
+ self.spatialInTangent = spatialInTangent
39
+ self.spatialOutTangent = spatialOutTangent
40
+ }
41
+
42
+ // MARK: Internal
43
+
44
+ enum CodingKeys: String, CodingKey {
45
+ case startValue = "s"
46
+ case endValue = "e"
47
+ case time = "t"
48
+ case hold = "h"
49
+ case inTangent = "i"
50
+ case outTangent = "o"
51
+ case spatialInTangent = "ti"
52
+ case spatialOutTangent = "to"
53
+ }
54
+
55
+ /// The start value of the keyframe
56
+ let startValue: T?
57
+ /// The End value of the keyframe. Note: Newer versions animation json do not have this field.
58
+ let endValue: T?
59
+ /// The time in frames of the keyframe.
60
+ let time: AnimationFrameTime?
61
+ /// A hold keyframe freezes interpolation until the next keyframe that is not a hold.
62
+ let hold: Int?
63
+
64
+ /// The in tangent for the time interpolation curve.
65
+ let inTangent: Vector2D?
66
+ /// The out tangent for the time interpolation curve.
67
+ let outTangent: Vector2D?
68
+
69
+ /// The spacial in tangent of the vector.
70
+ let spatialInTangent: Vector3D?
71
+ /// The spacial out tangent of the vector.
72
+ let spatialOutTangent: Vector3D?
73
+
74
+ var isHold: Bool {
75
+ if let hold = hold {
76
+ return hold > 0
77
+ }
78
+ return false
79
+ }
80
+ }
81
+
82
+ // MARK: Encodable
83
+
84
+ extension KeyframeData: Encodable where T: Encodable { }
85
+
86
+ // MARK: Decodable
87
+
88
+ extension KeyframeData: Decodable where T: Decodable { }
89
+
90
+ // MARK: DictionaryInitializable
91
+
92
+ extension KeyframeData: DictionaryInitializable where T: AnyInitializable {
93
+ convenience init(dictionary: [String: Any]) throws {
94
+ let startValue = try? dictionary[CodingKeys.startValue.rawValue].flatMap(T.init)
95
+ let endValue = try? dictionary[CodingKeys.endValue.rawValue].flatMap(T.init)
96
+ let time: AnimationFrameTime? = try? dictionary.value(for: CodingKeys.time)
97
+ let hold: Int? = try? dictionary.value(for: CodingKeys.hold)
98
+ let inTangent: Vector2D? = try? dictionary.value(for: CodingKeys.inTangent)
99
+ let outTangent: Vector2D? = try? dictionary.value(for: CodingKeys.outTangent)
100
+ let spatialInTangent: Vector3D? = try? dictionary.value(for: CodingKeys.spatialInTangent)
101
+ let spatialOutTangent: Vector3D? = try? dictionary.value(for: CodingKeys.spatialOutTangent)
102
+
103
+ self.init(
104
+ startValue: startValue,
105
+ endValue: endValue,
106
+ time: time,
107
+ hold: hold,
108
+ inTangent: inTangent,
109
+ outTangent: outTangent,
110
+ spatialInTangent: spatialInTangent,
111
+ spatialOutTangent: spatialOutTangent)
112
+ }
113
+ }
@@ -0,0 +1,197 @@
1
+ //
2
+ // KeyframeGroup.swift
3
+ // lottie-swift
4
+ //
5
+ // Created by Brandon Withrow on 1/14/19.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ // MARK: - KeyframeGroup
11
+
12
+ /// Used for coding/decoding a group of Keyframes by type.
13
+ ///
14
+ /// Keyframe data is wrapped in a dictionary { "k" : KeyframeData }.
15
+ /// The keyframe data can either be an array of keyframes or, if no animation is present, the raw value.
16
+ /// This helper object is needed to properly decode the json.
17
+
18
+ final class KeyframeGroup<T> {
19
+
20
+ // MARK: Lifecycle
21
+
22
+ init(keyframes: ContiguousArray<Keyframe<T>>) {
23
+ self.keyframes = keyframes
24
+ }
25
+
26
+ init(_ value: T) {
27
+ keyframes = [Keyframe(value)]
28
+ }
29
+
30
+ // MARK: Internal
31
+
32
+ enum KeyframeWrapperKey: String, CodingKey {
33
+ case keyframeData = "k"
34
+ }
35
+
36
+ let keyframes: ContiguousArray<Keyframe<T>>
37
+
38
+ }
39
+
40
+ // MARK: Decodable
41
+
42
+ extension KeyframeGroup: Decodable where T: Decodable {
43
+ convenience init(from decoder: Decoder) throws {
44
+ let container = try decoder.container(keyedBy: KeyframeWrapperKey.self)
45
+
46
+ if let keyframeData: T = try? container.decode(T.self, forKey: .keyframeData) {
47
+ /// Try to decode raw value; No keyframe data.
48
+ self.init(keyframes: [Keyframe<T>(keyframeData)])
49
+ } else {
50
+ // Decode and array of keyframes.
51
+ //
52
+ // Body Movin and Lottie deal with keyframes in different ways.
53
+ //
54
+ // A keyframe object in Body movin defines a span of time with a START
55
+ // and an END, from the current keyframe time to the next keyframe time.
56
+ //
57
+ // A keyframe object in Lottie defines a singular point in time/space.
58
+ // This point has an in-tangent and an out-tangent.
59
+ //
60
+ // To properly decode this we must iterate through keyframes while holding
61
+ // reference to the previous keyframe.
62
+
63
+ var keyframesContainer = try container.nestedUnkeyedContainer(forKey: .keyframeData)
64
+ var keyframes = ContiguousArray<Keyframe<T>>()
65
+ var previousKeyframeData: KeyframeData<T>?
66
+ while !keyframesContainer.isAtEnd {
67
+ // Ensure that Time and Value are present.
68
+
69
+ let keyframeData = try keyframesContainer.decode(KeyframeData<T>.self)
70
+
71
+ guard
72
+ let value: T = keyframeData.startValue ?? previousKeyframeData?.endValue,
73
+ let time = keyframeData.time else
74
+ {
75
+ /// Missing keyframe data. JSON must be corrupt.
76
+ throw DecodingError.dataCorruptedError(
77
+ forKey: KeyframeWrapperKey.keyframeData,
78
+ in: container,
79
+ debugDescription: "Missing keyframe data.")
80
+ }
81
+
82
+ keyframes.append(Keyframe<T>(
83
+ value: value,
84
+ time: AnimationFrameTime(time),
85
+ isHold: keyframeData.isHold,
86
+ inTangent: previousKeyframeData?.inTangent,
87
+ outTangent: keyframeData.outTangent,
88
+ spatialInTangent: previousKeyframeData?.spatialInTangent,
89
+ spatialOutTangent: keyframeData.spatialOutTangent))
90
+ previousKeyframeData = keyframeData
91
+ }
92
+ self.init(keyframes: keyframes)
93
+ }
94
+ }
95
+ }
96
+
97
+ // MARK: Encodable
98
+
99
+ extension KeyframeGroup: Encodable where T: Encodable {
100
+ func encode(to encoder: Encoder) throws {
101
+ var container = encoder.container(keyedBy: KeyframeWrapperKey.self)
102
+
103
+ if keyframes.count == 1 {
104
+ let keyframe = keyframes[0]
105
+ try container.encode(keyframe.value, forKey: .keyframeData)
106
+ } else {
107
+ var keyframeContainer = container.nestedUnkeyedContainer(forKey: .keyframeData)
108
+
109
+ for i in 1..<keyframes.endIndex {
110
+ let keyframe = keyframes[i - 1]
111
+ let nextKeyframe = keyframes[i]
112
+ let keyframeData = KeyframeData<T>(
113
+ startValue: keyframe.value,
114
+ endValue: nextKeyframe.value,
115
+ time: keyframe.time,
116
+ hold: keyframe.isHold ? 1 : nil,
117
+ inTangent: nextKeyframe.inTangent,
118
+ outTangent: keyframe.outTangent,
119
+ spatialInTangent: nil,
120
+ spatialOutTangent: nil)
121
+ try keyframeContainer.encode(keyframeData)
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ // MARK: DictionaryInitializable
128
+
129
+ extension KeyframeGroup: DictionaryInitializable where T: AnyInitializable {
130
+ convenience init(dictionary: [String: Any]) throws {
131
+ var keyframes = ContiguousArray<Keyframe<T>>()
132
+ if
133
+ let rawValue = dictionary[KeyframeWrapperKey.keyframeData.rawValue],
134
+ let value = try? T(value: rawValue)
135
+ {
136
+ keyframes = [Keyframe<T>(value)]
137
+ } else {
138
+ var frameDictionaries: [[String: Any]]
139
+ if let singleFrameDictionary = dictionary[KeyframeWrapperKey.keyframeData.rawValue] as? [String: Any] {
140
+ frameDictionaries = [singleFrameDictionary]
141
+ } else {
142
+ frameDictionaries = try dictionary.value(for: KeyframeWrapperKey.keyframeData)
143
+ }
144
+ var previousKeyframeData: KeyframeData<T>?
145
+ for frameDictionary in frameDictionaries {
146
+ let data = try KeyframeData<T>(dictionary: frameDictionary)
147
+ guard
148
+ let value: T = data.startValue ?? previousKeyframeData?.endValue,
149
+ let time = data.time else
150
+ {
151
+ throw InitializableError.invalidInput
152
+ }
153
+ keyframes.append(Keyframe<T>(
154
+ value: value,
155
+ time: time,
156
+ isHold: data.isHold,
157
+ inTangent: previousKeyframeData?.inTangent,
158
+ outTangent: data.outTangent,
159
+ spatialInTangent: previousKeyframeData?.spatialInTangent,
160
+ spatialOutTangent: data.spatialOutTangent))
161
+ previousKeyframeData = data
162
+ }
163
+ }
164
+
165
+ self.init(keyframes: keyframes)
166
+ }
167
+ }
168
+
169
+ // MARK: Equatable
170
+
171
+ extension KeyframeGroup: Equatable where T: Equatable {
172
+ static func == (_ lhs: KeyframeGroup<T>, _ rhs: KeyframeGroup<T>) -> Bool {
173
+ lhs.keyframes == rhs.keyframes
174
+ }
175
+ }
176
+
177
+ // MARK: Hashable
178
+
179
+ extension KeyframeGroup: Hashable where T: Hashable {
180
+ func hash(into hasher: inout Hasher) {
181
+ hasher.combine(keyframes)
182
+ }
183
+ }
184
+
185
+ extension Keyframe {
186
+ /// Creates a copy of this `Keyframe` with the same timing data, but a different value
187
+ func withValue<Value>(_ newValue: Value) -> Keyframe<Value> {
188
+ Keyframe<Value>(
189
+ value: newValue,
190
+ time: time,
191
+ isHold: isHold,
192
+ inTangent: inTangent,
193
+ outTangent: outTangent,
194
+ spatialInTangent: spatialInTangent,
195
+ spatialOutTangent: spatialOutTangent)
196
+ }
197
+ }
@@ -9,24 +9,34 @@ import Foundation
9
9
 
10
10
  /// A layer that holds an image.
11
11
  final class ImageLayerModel: LayerModel {
12
-
13
- /// The reference ID of the image.
14
- let referenceID: String
15
-
16
- private enum CodingKeys : String, CodingKey {
17
- case referenceID = "refId"
18
- }
19
-
12
+
13
+ // MARK: Lifecycle
14
+
20
15
  required init(from decoder: Decoder) throws {
21
16
  let container = try decoder.container(keyedBy: ImageLayerModel.CodingKeys.self)
22
- self.referenceID = try container.decode(String.self, forKey: .referenceID)
17
+ referenceID = try container.decode(String.self, forKey: .referenceID)
23
18
  try super.init(from: decoder)
24
19
  }
25
-
20
+
21
+ required init(dictionary: [String: Any]) throws {
22
+ referenceID = try dictionary.value(for: CodingKeys.referenceID)
23
+ try super.init(dictionary: dictionary)
24
+ }
25
+
26
+ // MARK: Internal
27
+
28
+ /// The reference ID of the image.
29
+ let referenceID: String
30
+
26
31
  override func encode(to encoder: Encoder) throws {
27
32
  try super.encode(to: encoder)
28
33
  var container = encoder.container(keyedBy: CodingKeys.self)
29
34
  try container.encode(referenceID, forKey: .referenceID)
30
35
  }
31
-
36
+
37
+ // MARK: Private
38
+
39
+ private enum CodingKeys: String, CodingKey {
40
+ case referenceID = "refId"
41
+ }
32
42
  }