lottie-ios 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/.github/workflows/main.yml +117 -11
  2. package/Gemfile +1 -0
  3. package/Gemfile.lock +5 -0
  4. package/Lottie.xcodeproj/project.pbxproj +1542 -194
  5. package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  6. package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (iOS).xcscheme +1 -1
  7. package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (macOS).xcscheme +1 -1
  8. package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (tvOS).xcscheme +4 -5
  9. package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (visionOS).xcscheme +66 -0
  10. package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +18 -0
  11. package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +2 -11
  12. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  13. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +346 -102
  14. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +16 -5
  15. package/Package.resolved +2 -2
  16. package/Package.swift +16 -9
  17. package/README.md +2 -2
  18. package/Rakefile +122 -25
  19. package/Sources/Private/CoreAnimation/Animations/DropShadowAnimation.swift +160 -0
  20. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +83 -10
  21. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +85 -79
  22. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +7 -7
  23. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +67 -6
  24. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +2 -2
  25. package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +9 -0
  26. package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +1 -0
  27. package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +1 -1
  28. package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +2 -0
  29. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +11 -13
  30. package/Sources/Private/CoreAnimation/Layers/SolidLayer.swift +20 -5
  31. package/Sources/Private/CoreAnimation/Layers/TextLayer.swift +13 -3
  32. package/Sources/Private/CoreAnimation/ValueProviderStore.swift +6 -4
  33. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/Collection+Diff.swift +263 -0
  34. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/Diffable.swift +18 -0
  35. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/DiffableSection.swift +16 -0
  36. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/IndexChangeset.swift +187 -0
  37. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/SectionedChangeset.swift +32 -0
  38. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Logging/EpoxyLogger.swift +99 -0
  39. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/CallbackContextEpoxyModeled.swift +8 -0
  40. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelArrayBuilder.swift +48 -0
  41. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelProperty.swift +158 -0
  42. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelStorage.swift +88 -0
  43. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModeled.swift +54 -0
  44. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Internal/AnyEpoxyModelProperty.swift +29 -0
  45. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Internal/ClassReference.swift +39 -0
  46. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/AnimatedProviding.swift +10 -0
  47. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DataIDProviding.swift +57 -0
  48. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidDisplayProviding.swift +41 -0
  49. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidEndDisplayingProviding.swift +41 -0
  50. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidSelectProviding.swift +36 -0
  51. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ErasedContentProviding.swift +49 -0
  52. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/MakeViewProviding.swift +60 -0
  53. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/SetBehaviorsProviding.swift +38 -0
  54. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/SetContentProviding.swift +38 -0
  55. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/StyleIDProviding.swift +37 -0
  56. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/TraitCollectionProviding.swift +14 -0
  57. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ViewDifferentiatorProviding.swift +34 -0
  58. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ViewProviding.swift +13 -0
  59. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/WillDisplayProviding.swift +41 -0
  60. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/ViewEpoxyModeled.swift +10 -0
  61. package/Sources/Private/EmbeddedLibraries/EpoxyCore/README.md +31 -0
  62. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingController.swift +46 -0
  63. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingView.swift +391 -0
  64. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIIntrinsicContentSizeInvalidator.swift +44 -0
  65. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUILayoutMargins.swift +51 -0
  66. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxyableView+SwiftUIView.swift +172 -0
  67. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/MeasuringViewRepresentable.swift +128 -0
  68. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift +452 -0
  69. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/SwiftUIView.swift +148 -0
  70. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIView+SwiftUIView.swift +40 -0
  71. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIViewConfiguringSwiftUIView.swift +43 -0
  72. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/BehaviorsConfigurableView.swift +45 -0
  73. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ContentConfigurableView.swift +36 -0
  74. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/EpoxyableView.swift +5 -0
  75. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/StyledView.swift +42 -0
  76. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ViewType.swift +51 -0
  77. package/Sources/Private/EmbeddedLibraries/README.md +27 -0
  78. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+BackingConfiguration.swift +4 -4
  79. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+MemoryFile.swift +2 -2
  80. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Writing.swift +4 -4
  81. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive.swift +8 -7
  82. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+Compression.swift +5 -5
  83. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/FileManager+ZIP.swift +4 -4
  84. package/Sources/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift +6 -0
  85. package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +3 -1
  86. package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +18 -5
  87. package/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift +31 -3
  88. package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +33 -8
  89. package/Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift +8 -1
  90. package/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift +13 -4
  91. package/Sources/Private/MainThread/LayerContainers/Utility/LayerFontProvider.swift +2 -2
  92. package/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift +1 -0
  93. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTextProvider.swift +4 -4
  94. package/Sources/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift +1 -1
  95. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +3 -1
  96. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +2 -1
  97. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift +2 -1
  98. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +1 -1
  99. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +2 -2
  100. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +1 -1
  101. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +1 -1
  102. package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +6 -2
  103. package/Sources/Private/Model/Assets/Asset.swift +8 -0
  104. package/Sources/Private/Model/Assets/AssetLibrary.swift +2 -2
  105. package/Sources/Private/Model/Assets/ImageAsset.swift +3 -3
  106. package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +16 -2
  107. package/Sources/Private/Model/DotLottie/DotLottieImageProvider.swift +20 -7
  108. package/Sources/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift +26 -0
  109. package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +8 -5
  110. package/Sources/Private/Model/LayerEffects/DropShadowEffect.swift +45 -0
  111. package/Sources/Private/Model/LayerEffects/EffectValues/ColorEffectValue.swift +38 -0
  112. package/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift +98 -0
  113. package/Sources/Private/Model/LayerEffects/EffectValues/Vector1DEffectValue.swift +38 -0
  114. package/Sources/Private/Model/LayerEffects/LayerEffect.swift +103 -0
  115. package/Sources/Private/Model/LayerStyles/DropShadowStyle.swift +72 -0
  116. package/Sources/Private/Model/LayerStyles/LayerStyle.swift +85 -0
  117. package/Sources/Private/Model/Layers/LayerModel.swift +27 -0
  118. package/Sources/Private/Model/Objects/Marker.swift +1 -1
  119. package/Sources/Private/Model/Objects/Transform.swift +1 -2
  120. package/Sources/Private/Model/ShapeItems/GradientFill.swift +1 -1
  121. package/Sources/Private/Model/ShapeItems/GradientStroke.swift +2 -2
  122. package/Sources/Private/Model/ShapeItems/Merge.swift +1 -1
  123. package/Sources/Private/Model/ShapeItems/ShapeItem.swift +31 -26
  124. package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +0 -9
  125. package/Sources/Private/Model/ShapeItems/Star.swift +1 -1
  126. package/Sources/Private/Model/Text/Font.swift +2 -2
  127. package/Sources/Private/Model/Text/Glyph.swift +1 -1
  128. package/Sources/Private/RootAnimationLayer.swift +2 -2
  129. package/Sources/Private/Utility/Debugging/LayerDebugging.swift +3 -1
  130. package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +32 -2
  131. package/Sources/Private/Utility/Helpers/AnimationContext.swift +4 -2
  132. package/Sources/Private/Utility/Helpers/AnyEquatable.swift +24 -0
  133. package/Sources/Private/Utility/Helpers/Binding+Map.swift +18 -0
  134. package/Sources/Private/Utility/Helpers/View+ValueChanged.swift +20 -0
  135. package/Sources/Private/Utility/LottieAnimationSource.swift +41 -0
  136. package/Sources/Private/Utility/Primitives/BezierPath.swift +2 -2
  137. package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +2 -2
  138. package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +1 -1
  139. package/Sources/Public/Animation/LottieAnimation.swift +21 -2
  140. package/Sources/Public/Animation/LottieAnimationLayer.swift +1464 -0
  141. package/Sources/Public/Animation/LottieAnimationView.swift +258 -735
  142. package/Sources/Public/Animation/LottiePlaybackMode.swift +117 -0
  143. package/Sources/Public/Animation/LottieView.swift +462 -0
  144. package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +2 -1
  145. package/Sources/Public/AnimationCache/DefaultAnimationCache.swift +5 -6
  146. package/Sources/Public/Configuration/DecodingStrategy.swift +15 -0
  147. package/Sources/Public/Configuration/LottieConfiguration.swift +47 -0
  148. package/Sources/Public/Configuration/ReducedMotionOption.swift +114 -0
  149. package/Sources/Public/{LottieConfiguration.swift → Configuration/RenderingEngineOption.swift} +2 -57
  150. package/Sources/Public/{iOS → Controls}/AnimatedButton.swift +56 -13
  151. package/Sources/Public/{iOS → Controls}/AnimatedControl.swift +80 -8
  152. package/Sources/Public/{iOS → Controls}/AnimatedSwitch.swift +71 -31
  153. package/Sources/Public/Controls/LottieButton.swift +122 -0
  154. package/Sources/Public/Controls/LottieSwitch.swift +144 -0
  155. package/Sources/Public/Controls/LottieViewType.swift +79 -0
  156. package/Sources/Public/DotLottie/DotLottieConfiguration.swift +24 -0
  157. package/Sources/Public/DotLottie/DotLottieFile.swift +21 -6
  158. package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +79 -0
  159. package/Sources/Public/DynamicProperties/AnimationKeypath.swift +11 -1
  160. package/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +14 -0
  161. package/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +13 -0
  162. package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +22 -5
  163. package/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +14 -0
  164. package/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +13 -0
  165. package/Sources/Public/FontProvider/AnimationFontProvider.swift +8 -0
  166. package/Sources/Public/ImageProvider/AnimationImageProvider.swift +24 -0
  167. package/Sources/Public/Keyframes/Keyframe.swift +6 -0
  168. package/Sources/Public/Primitives/Vectors.swift +2 -2
  169. package/Sources/Public/TextProvider/AnimationTextProvider.swift +79 -6
  170. package/Sources/Public/iOS/AnimationSubview.swift +1 -1
  171. package/Sources/Public/iOS/BundleImageProvider.swift +16 -2
  172. package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +2 -2
  173. package/Sources/Public/iOS/FilepathImageProvider.swift +22 -3
  174. package/Sources/Public/iOS/LottieAnimationViewBase.swift +7 -1
  175. package/Sources/Public/macOS/BundleImageProvider.macOS.swift +15 -1
  176. package/Sources/Public/macOS/FilepathImageProvider.macOS.swift +21 -2
  177. package/lottie-ios.podspec +2 -1
  178. package/package.json +1 -1
  179. package/Sources/Private/Model/DotLottie/DotLottieConfiguration.swift +0 -15
  180. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Helpers.swift +0 -0
  181. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Progress.swift +0 -0
  182. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Reading.swift +0 -0
  183. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+ReadingDeprecated.swift +0 -0
  184. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+WritingDeprecated.swift +0 -0
  185. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+ZIP64.swift +0 -0
  186. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+CompressionDeprecated.swift +0 -0
  187. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+Serialization.swift +0 -0
  188. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry+Serialization.swift +0 -0
  189. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry+ZIP64.swift +0 -0
  190. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry.swift +0 -0
  191. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/README.md +0 -0
  192. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/URL+ZIP.swift +0 -0
@@ -0,0 +1,117 @@
1
+ // Created by Cal Stephens on 8/3/23.
2
+ // Copyright © 2023 Airbnb Inc. All rights reserved.
3
+
4
+ import Foundation
5
+
6
+ // MARK: - LottiePlaybackMode
7
+
8
+ /// Configuration for how a Lottie animation should be played
9
+ public enum LottiePlaybackMode: Hashable {
10
+ /// The animation is paused at the given progress value,
11
+ /// a value between 0.0 (0% progress) and 1.0 (100% progress).
12
+ case progress(_ progress: AnimationProgressTime)
13
+
14
+ /// The animation is paused at the given frame of the animation.
15
+ case frame(_ frame: AnimationFrameTime)
16
+
17
+ /// The animation is paused at the given time value from the start of the animation.
18
+ case time(_ time: TimeInterval)
19
+
20
+ /// Any existing animation will be paused at the current frame.
21
+ case pause
22
+
23
+ /// Plays the animation from a progress (0-1) to a progress (0-1).
24
+ /// - Parameter fromProgress: The start progress of the animation. If `nil` the animation will start at the current progress.
25
+ /// - Parameter toProgress: The end progress of the animation.
26
+ /// - Parameter loopMode: The loop behavior of the animation.
27
+ case fromProgress(_ fromProgress: AnimationProgressTime?, toProgress: AnimationProgressTime, loopMode: LottieLoopMode)
28
+
29
+ /// The animation plays from the given `fromFrame` to the given `toFrame`.
30
+ /// - Parameter fromFrame: The start frame of the animation. If `nil` the animation will start at the current frame.
31
+ /// - Parameter toFrame: The end frame of the animation.
32
+ /// - Parameter loopMode: The loop behavior of the animation.
33
+ case fromFrame(_ fromFrame: AnimationFrameTime?, toFrame: AnimationFrameTime, loopMode: LottieLoopMode)
34
+
35
+ /// Plays the animation from a named marker to another marker.
36
+ ///
37
+ /// Markers are point in time that are encoded into the Animation data and assigned a name.
38
+ ///
39
+ /// NOTE: If markers are not found the play command will exit.
40
+ ///
41
+ /// - Parameter fromMarker: The start marker for the animation playback. If `nil` the
42
+ /// animation will start at the current progress.
43
+ /// - Parameter toMarker: The end marker for the animation playback.
44
+ /// - Parameter playEndMarkerFrame: A flag to determine whether or not to play the frame of the end marker. If the
45
+ /// end marker represents the end of the section to play, it should be to true. If the provided end marker
46
+ /// represents the beginning of the next section, it should be false.
47
+ /// - Parameter loopMode: The loop behavior of the animation.
48
+ case fromMarker(
49
+ _ fromMarker: String?,
50
+ toMarker: String,
51
+ playEndMarkerFrame: Bool = true,
52
+ loopMode: LottieLoopMode)
53
+
54
+ /// Plays the animation from a named marker to the end of the marker's duration.
55
+ ///
56
+ /// A marker is a point in time with an associated duration that is encoded into the
57
+ /// animation data and assigned a name.
58
+ ///
59
+ /// NOTE: If marker is not found the play command will exit.
60
+ ///
61
+ /// - Parameter marker: The start marker for the animation playback.
62
+ /// - Parameter loopMode: The loop behavior of the animation.
63
+ case marker(_ marker: String, loopMode: LottieLoopMode)
64
+
65
+ /// Plays the given markers sequentially in order.
66
+ ///
67
+ /// A marker is a point in time with an associated duration that is encoded into the
68
+ /// animation data and assigned a name. Multiple markers can be played sequentially
69
+ /// to create programmable animations.
70
+ ///
71
+ /// If a marker is not found, it will be skipped.
72
+ ///
73
+ /// If a marker doesn't have a duration value, it will play with a duration of 0
74
+ /// (effectively being skipped).
75
+ ///
76
+ /// If another animation is played (by calling any `play` method) while this
77
+ /// marker sequence is playing, the marker sequence will be cancelled.
78
+ ///
79
+ /// - Parameter markers: The list of markers to play sequentially.
80
+ case markers(_ markers: [String])
81
+ }
82
+
83
+ extension LottiePlaybackMode {
84
+ /// Plays the animation from the current progress to a progress value (0-1).
85
+ /// - Parameter toProgress: The end progress of the animation.
86
+ /// - Parameter loopMode: The loop behavior of the animation.
87
+ public static func toProgress(_ toProgress: AnimationProgressTime, loopMode: LottieLoopMode) -> LottiePlaybackMode {
88
+ .fromProgress(nil, toProgress: toProgress, loopMode: loopMode)
89
+ }
90
+
91
+ // Plays the animation from the current frame to the given frame.
92
+ /// - Parameter toFrame: The end frame of the animation.
93
+ /// - Parameter loopMode: The loop behavior of the animation.
94
+ public static func toFrame(_ toFrame: AnimationFrameTime, loopMode: LottieLoopMode) -> LottiePlaybackMode {
95
+ .fromFrame(nil, toFrame: toFrame, loopMode: loopMode)
96
+ }
97
+
98
+ /// Plays the animation from the current frame to some marker.
99
+ ///
100
+ /// Markers are point in time that are encoded into the Animation data and assigned a name.
101
+ ///
102
+ /// NOTE: If the marker isn't found the play command will exit.
103
+ ///
104
+ /// - Parameter toMarker: The end marker for the animation playback.
105
+ /// - Parameter playEndMarkerFrame: A flag to determine whether or not to play the frame of the end marker. If the
106
+ /// end marker represents the end of the section to play, it should be to true. If the provided end marker
107
+ /// represents the beginning of the next section, it should be false.
108
+ /// - Parameter loopMode: The loop behavior of the animation.
109
+ public static func toMarker(
110
+ _ toMarker: String,
111
+ playEndMarkerFrame: Bool = true,
112
+ loopMode: LottieLoopMode)
113
+ -> LottiePlaybackMode
114
+ {
115
+ .fromMarker(nil, toMarker: toMarker, playEndMarkerFrame: playEndMarkerFrame, loopMode: loopMode)
116
+ }
117
+ }
@@ -0,0 +1,462 @@
1
+ // Created by Bryn Bodayle on 1/20/22.
2
+ // Copyright © 2022 Airbnb Inc. All rights reserved.
3
+
4
+ import SwiftUI
5
+
6
+ // MARK: - LottieView
7
+
8
+ /// A wrapper which exposes Lottie's `LottieAnimationView` to SwiftUI
9
+ @available(iOS 13.0, tvOS 13.0, macOS 10.15, *)
10
+ public struct LottieView<Placeholder: View>: UIViewConfiguringSwiftUIView {
11
+
12
+ // MARK: Lifecycle
13
+
14
+ /// Creates a `LottieView` that displays the given animation
15
+ public init(animation: LottieAnimation?) where Placeholder == EmptyView {
16
+ _animationSource = State(initialValue: animation.map(LottieAnimationSource.lottieAnimation))
17
+ placeholder = nil
18
+ }
19
+
20
+ /// Initializes a `LottieView` with the provided `DotLottieFile` for display.
21
+ ///
22
+ /// - Important: Avoid using this initializer with the `SynchronouslyBlockingCurrentThread` APIs.
23
+ /// If decompression of a `.lottie` file is necessary, prefer using the `.init(_ loadAnimation:)`
24
+ /// initializer, which takes an asynchronous closure:
25
+ /// ```
26
+ /// LottieView {
27
+ /// try await DotLottieFile.named(name)
28
+ /// }
29
+ /// ```
30
+ public init(dotLottieFile: DotLottieFile?) where Placeholder == EmptyView {
31
+ _animationSource = State(initialValue: dotLottieFile.map(LottieAnimationSource.dotLottieFile))
32
+ placeholder = nil
33
+ }
34
+
35
+ /// Creates a `LottieView` that asynchronously loads and displays the given `LottieAnimation`.
36
+ /// The `loadAnimation` closure is called exactly once in `onAppear`.
37
+ /// If you wish to call `loadAnimation` again at a different time, you can use `.reloadAnimationTrigger(...)`.
38
+ public init(_ loadAnimation: @escaping () async throws -> LottieAnimation?) where Placeholder == EmptyView {
39
+ self.init(loadAnimation, placeholder: EmptyView.init)
40
+ }
41
+
42
+ /// Creates a `LottieView` that asynchronously loads and displays the given `LottieAnimation`.
43
+ /// The `loadAnimation` closure is called exactly once in `onAppear`.
44
+ /// If you wish to call `loadAnimation` again at a different time, you can use `.reloadAnimationTrigger(...)`.
45
+ /// While the animation is loading, the `placeholder` view is shown in place of the `LottieAnimationView`.
46
+ public init(
47
+ _ loadAnimation: @escaping () async throws -> LottieAnimation?,
48
+ @ViewBuilder placeholder: @escaping (() -> Placeholder))
49
+ {
50
+ self.init {
51
+ try await loadAnimation().map(LottieAnimationSource.lottieAnimation)
52
+ } placeholder: {
53
+ placeholder()
54
+ }
55
+ }
56
+
57
+ /// Creates a `LottieView` that asynchronously loads and displays the given `DotLottieFile`.
58
+ /// The `loadDotLottieFile` closure is called exactly once in `onAppear`.
59
+ /// If you wish to call `loadAnimation` again at a different time, you can use `.reloadAnimationTrigger(...)`.
60
+ /// You can use the `DotLottieFile` static methods API which use Swift concurrency to load your `.lottie` files:
61
+ /// ```
62
+ /// LottieView {
63
+ /// try await DotLottieFile.named(name)
64
+ /// }
65
+ /// ```
66
+ public init(_ loadDotLottieFile: @escaping () async throws -> DotLottieFile?) where Placeholder == EmptyView {
67
+ self.init(loadDotLottieFile, placeholder: EmptyView.init)
68
+ }
69
+
70
+ /// Creates a `LottieView` that asynchronously loads and displays the given `DotLottieFile`.
71
+ /// The `loadDotLottieFile` closure is called exactly once in `onAppear`.
72
+ /// If you wish to call `loadAnimation` again at a different time, you can use `.reloadAnimationTrigger(...)`.
73
+ /// While the animation is loading, the `placeholder` view is shown in place of the `LottieAnimationView`.
74
+ /// You can use the `DotLottieFile` static methods API which use Swift concurrency to load your `.lottie` files:
75
+ /// ```
76
+ /// LottieView {
77
+ /// try await DotLottieFile.named(name)
78
+ /// } placeholder: {
79
+ /// LoadingView()
80
+ /// }
81
+ /// ```
82
+ public init(
83
+ _ loadDotLottieFile: @escaping () async throws -> DotLottieFile?,
84
+ @ViewBuilder placeholder: @escaping (() -> Placeholder))
85
+ {
86
+ self.init {
87
+ try await loadDotLottieFile().map(LottieAnimationSource.dotLottieFile)
88
+ } placeholder: {
89
+ placeholder()
90
+ }
91
+ }
92
+
93
+ /// Creates a `LottieView` that asynchronously loads and displays the given `LottieAnimationSource`.
94
+ /// The `loadAnimation` closure is called exactly once in `onAppear`.
95
+ /// If you wish to call `loadAnimation` again at a different time, you can use `.reloadAnimationTrigger(...)`.
96
+ /// While the animation is loading, the `placeholder` view is shown in place of the `LottieAnimationView`.
97
+ public init(_ loadAnimation: @escaping () async throws -> LottieAnimationSource?) where Placeholder == EmptyView {
98
+ self.init(loadAnimation, placeholder: EmptyView.init)
99
+ }
100
+
101
+ /// Creates a `LottieView` that asynchronously loads and displays the given `LottieAnimationSource`.
102
+ /// The `loadAnimation` closure is called exactly once in `onAppear`.
103
+ /// If you wish to call `loadAnimation` again at a different time, you can use `.reloadAnimationTrigger(...)`.
104
+ /// While the animation is loading, the `placeholder` view is shown in place of the `LottieAnimationView`.
105
+ public init(
106
+ _ loadAnimation: @escaping () async throws -> LottieAnimationSource?,
107
+ @ViewBuilder placeholder: @escaping () -> Placeholder)
108
+ {
109
+ self.loadAnimation = loadAnimation
110
+ self.placeholder = placeholder
111
+ _animationSource = State(initialValue: nil)
112
+ }
113
+
114
+ // MARK: Public
115
+
116
+ public var body: some View {
117
+ ZStack {
118
+ if let animationSource = animationSource {
119
+ LottieAnimationView.swiftUIView {
120
+ defer { animationDidLoad?(animationSource) }
121
+ return LottieAnimationView(
122
+ animationSource: animationSource,
123
+ imageProvider: imageProvider,
124
+ textProvider: textProvider,
125
+ fontProvider: fontProvider,
126
+ configuration: configuration,
127
+ logger: logger)
128
+ }
129
+ .sizing(sizing)
130
+ .configure { context in
131
+ // We check referential equality of the animation before updating as updating the
132
+ // animation has a side-effect of rebuilding the animation layer, and it would be
133
+ // prohibitive to do so on every state update.
134
+ if animationSource.animation !== context.view.animation {
135
+ context.view.loadAnimation(animationSource)
136
+ animationDidLoad?(animationSource)
137
+ }
138
+
139
+ if
140
+ let playbackMode = playbackMode,
141
+ playbackMode != context.view.currentPlaybackMode
142
+ {
143
+ context.view.play(playbackMode, animationCompletionHandler: animationCompletionHandler)
144
+ }
145
+ }
146
+ .configurations(configurations)
147
+ } else {
148
+ placeholder?()
149
+ }
150
+ }
151
+ .onAppear {
152
+ loadAnimationIfNecessary()
153
+ }
154
+ .valueChanged(value: reloadAnimationTrigger) { _ in
155
+ reloadAnimationTriggerDidChange()
156
+ }
157
+ }
158
+
159
+ /// Returns a copy of this `LottieView` updated to have the given closure applied to its
160
+ /// represented `LottieAnimationView` whenever it is updated via the `updateUIView(…)`
161
+ /// or `updateNSView(…)` method.
162
+ public func configure(_ configure: @escaping (LottieAnimationView) -> Void) -> Self {
163
+ var copy = self
164
+ copy.configurations.append { context in
165
+ configure(context.view)
166
+ }
167
+ return copy
168
+ }
169
+
170
+ /// Returns a copy of this view that can be resized by scaling its animation to fit the size
171
+ /// offered by its parent.
172
+ public func resizable() -> Self {
173
+ var copy = self
174
+ copy.sizing = .proposed
175
+ return copy
176
+ }
177
+
178
+ // Returns a copy of this view playing once from the current frame to the end frame
179
+ public func play() -> Self {
180
+ play(loopMode: .playOnce)
181
+ }
182
+
183
+ /// Returns a copy of this view that loops its animation from the start to end whenever visible
184
+ public func looping() -> Self {
185
+ play(.fromProgress(0, toProgress: 1, loopMode: .loop))
186
+ }
187
+
188
+ /// Returns a copy of this view playing from the current frame to the end frame,
189
+ /// with the given `LottiePlaybackMode`.
190
+ public func play(loopMode: LottieLoopMode = .playOnce) -> Self {
191
+ play(.toProgress(1, loopMode: loopMode))
192
+ }
193
+
194
+ /// Returns a copy of this view playing with the given `LottiePlaybackMode`
195
+ public func play(_ playbackMode: LottiePlaybackMode) -> Self {
196
+ self.playbackMode(playbackMode)
197
+ }
198
+
199
+ /// Returns a copy of this view using the given `LottiePlaybackMode`
200
+ public func playbackMode(_ playbackMode: LottiePlaybackMode) -> Self {
201
+ var copy = self
202
+ copy.playbackMode = playbackMode
203
+ return copy
204
+ }
205
+
206
+ /// Returns a copy of this view with the given closure that is called whenever the
207
+ /// `LottieAnimationSource` provided via `init` is loaded and applied to the underlying `LottieAnimationView`.
208
+ public func animationDidLoad(_ animationDidLoad: @escaping (LottieAnimationSource) -> Void) -> Self {
209
+ var copy = self
210
+ copy.animationDidLoad = animationDidLoad
211
+ return copy
212
+ }
213
+
214
+ /// Returns a copy of this view with the given `LottieCompletionBlock` that is called
215
+ /// when an animation finishes playing.
216
+ public func animationDidFinish(_ animationCompletionHandler: LottieCompletionBlock?) -> Self {
217
+ var copy = self
218
+ copy.animationCompletionHandler = { [previousCompletionHandler = self.animationCompletionHandler] completed in
219
+ previousCompletionHandler?(completed)
220
+ animationCompletionHandler?(completed)
221
+ }
222
+ return copy
223
+ }
224
+
225
+ /// Returns a copy of this view updated to have the provided background behavior.
226
+ public func backgroundBehavior(_ value: LottieBackgroundBehavior) -> Self {
227
+ configure { view in
228
+ view.backgroundBehavior = value
229
+ }
230
+ }
231
+
232
+ /// Returns a copy of this view with its accessibility label updated to the given value.
233
+ public func accessibilityLabel(_ accessibilityLabel: String?) -> Self {
234
+ configure { view in
235
+ #if os(macOS)
236
+ view.setAccessibilityElement(accessibilityLabel != nil)
237
+ view.setAccessibilityLabel(accessibilityLabel)
238
+ #else
239
+ view.isAccessibilityElement = accessibilityLabel != nil
240
+ view.accessibilityLabel = accessibilityLabel
241
+ #endif
242
+ }
243
+ }
244
+
245
+ /// Returns a copy of this view with its `LottieConfiguration` updated to the given value.
246
+ public func configuration(_ configuration: LottieConfiguration) -> Self {
247
+ var copy = self
248
+ copy.configuration = configuration
249
+
250
+ copy = copy.configure { view in
251
+ if view.configuration != configuration {
252
+ view.configuration = configuration
253
+ }
254
+ }
255
+
256
+ return copy
257
+ }
258
+
259
+ /// Returns a copy of this view with its `LottieLogger` updated to the given value.
260
+ /// - The underlying `LottieAnimationView`'s `LottieLogger` is immutable after configured,
261
+ /// so this value is only used when initializing the `LottieAnimationView` for the first time.
262
+ public func logger(_ logger: LottieLogger) -> Self {
263
+ var copy = self
264
+ copy.logger = logger
265
+ return copy
266
+ }
267
+
268
+ /// Returns a copy of this view with its image provider updated to the given value.
269
+ /// The image provider must be `Equatable` to avoid unnecessary state updates / re-renders.
270
+ public func imageProvider<ImageProvider: AnimationImageProvider & Equatable>(_ imageProvider: ImageProvider) -> Self {
271
+ var copy = self
272
+ copy.imageProvider = imageProvider
273
+
274
+ copy = copy.configure { view in
275
+ if (view.imageProvider as? ImageProvider) != imageProvider {
276
+ view.imageProvider = imageProvider
277
+ }
278
+ }
279
+
280
+ return copy
281
+ }
282
+
283
+ /// Returns a copy of this view with its text provider updated to the given value.
284
+ /// The image provider must be `Equatable` to avoid unnecessary state updates / re-renders.
285
+ public func textProvider<TextProvider: AnimationKeypathTextProvider & Equatable>(_ textProvider: TextProvider) -> Self {
286
+ var copy = self
287
+ copy.textProvider = textProvider
288
+
289
+ copy = copy.configure { view in
290
+ if (view.textProvider as? TextProvider) != textProvider {
291
+ view.textProvider = textProvider
292
+ }
293
+ }
294
+
295
+ return copy
296
+ }
297
+
298
+ /// Returns a copy of this view with its image provider updated to the given value.
299
+ /// The image provider must be `Equatable` to avoid unnecessary state updates / re-renders.
300
+ public func fontProvider<FontProvider: AnimationFontProvider & Equatable>(_ fontProvider: FontProvider) -> Self {
301
+ var copy = self
302
+ copy.fontProvider = fontProvider
303
+
304
+ copy = configure { view in
305
+ if (view.fontProvider as? FontProvider) != fontProvider {
306
+ view.fontProvider = fontProvider
307
+ }
308
+ }
309
+
310
+ return copy
311
+ }
312
+
313
+ /// Returns a copy of this view using the given value provider for the given keypath.
314
+ /// The value provider must be `Equatable` to avoid unnecessary state updates / re-renders.
315
+ public func valueProvider<ValueProvider: AnyValueProvider & Equatable>(
316
+ _ valueProvider: ValueProvider,
317
+ for keypath: AnimationKeypath)
318
+ -> Self
319
+ {
320
+ configure { view in
321
+ if (view.valueProviders[keypath] as? ValueProvider) != valueProvider {
322
+ view.setValueProvider(valueProvider, keypath: keypath)
323
+ }
324
+ }
325
+ }
326
+
327
+ /// Returns a copy of this view updated to display the given `AnimationProgressTime`.
328
+ /// - If the `currentProgress` value is provided, the `currentProgress` of the
329
+ /// underlying `LottieAnimationView` is updated. This will pause any existing animations.
330
+ /// - If the `animationProgress` is `nil`, no changes will be made and any existing animations
331
+ /// will continue playing uninterrupted.
332
+ public func currentProgress(_ currentProgress: AnimationProgressTime?) -> Self {
333
+ guard let currentProgress = currentProgress else { return self }
334
+ var copy = self
335
+ copy.playbackMode = .progress(currentProgress)
336
+ return copy
337
+ }
338
+
339
+ /// Returns a copy of this view updated to display the given `AnimationFrameTime`.
340
+ /// - If the `currentFrame` value is provided, the `currentFrame` of the
341
+ /// underlying `LottieAnimationView` is updated. This will pause any existing animations.
342
+ /// - If the `currentFrame` is `nil`, no changes will be made and any existing animations
343
+ /// will continue playing uninterrupted.
344
+ public func currentFrame(_ currentFrame: AnimationFrameTime?) -> Self {
345
+ guard let currentFrame = currentFrame else { return self }
346
+ var copy = self
347
+ copy.playbackMode = .frame(currentFrame)
348
+ return copy
349
+ }
350
+
351
+ /// Returns a copy of this view updated to display the given time value.
352
+ /// - If the `currentTime` value is provided, the `currentTime` of the
353
+ /// underlying `LottieAnimationView` is updated. This will pause any existing animations.
354
+ /// - If the `currentTime` is `nil`, no changes will be made and any existing animations
355
+ /// will continue playing uninterrupted.
356
+ public func currentTime(_ currentTime: TimeInterval?) -> Self {
357
+ guard let currentTime = currentTime else { return self }
358
+ var copy = self
359
+ copy.playbackMode = .time(currentTime)
360
+ return copy
361
+ }
362
+
363
+ /// Returns a new instance of this view, which will invoke the provided `loadAnimation` closure
364
+ /// whenever the `binding` value is updated.
365
+ ///
366
+ /// - Note: This function requires a valid `loadAnimation` closure provided during view initialization,
367
+ /// otherwise `reloadAnimationTrigger` will have no effect.
368
+ /// - Parameters:
369
+ /// - binding: The binding that triggers the reloading when its value changes.
370
+ /// - showPlaceholder: When `true`, the current animation will be removed before invoking `loadAnimation`,
371
+ /// displaying the `Placeholder` until the new animation loads.
372
+ /// When `false`, the previous animation remains visible while the new one loads.
373
+ public func reloadAnimationTrigger<Value: Equatable>(_ value: Value, showPlaceholder: Bool = true) -> Self {
374
+ var copy = self
375
+ copy.reloadAnimationTrigger = AnyEquatable(value)
376
+ copy.showPlaceholderWhileReloading = showPlaceholder
377
+ return copy
378
+ }
379
+
380
+ /// Returns a view that updates the given binding each frame with the animation's `realtimeAnimationProgress`.
381
+ /// The `LottieView` is wrapped in a `TimelineView` with the `.animation` schedule.
382
+ /// - This is a one-way binding. Its value is updated but never read.
383
+ /// - If provided, the binding will be updated each frame with the `realtimeAnimationProgress`
384
+ /// of the underlying `LottieAnimationView`. This is potentially expensive since it triggers
385
+ /// a state update every frame.
386
+ /// - If the binding is `nil`, the `TimelineView` will be paused and no updates will occur to the binding.
387
+ @available(iOS 15.0, tvOS 15.0, macOS 12.0, *)
388
+ public func getRealtimeAnimationProgress(_ realtimeAnimationProgress: Binding<AnimationProgressTime>?) -> some View {
389
+ TimelineView(.animation(paused: realtimeAnimationProgress == nil)) { _ in
390
+ configure { view in
391
+ if let realtimeAnimationProgress = realtimeAnimationProgress {
392
+ DispatchQueue.main.async {
393
+ realtimeAnimationProgress.wrappedValue = view.realtimeAnimationProgress
394
+ }
395
+ }
396
+ }
397
+ }
398
+ }
399
+
400
+ /// Returns a view that updates the given binding each frame with the animation's `realtimeAnimationProgress`.
401
+ /// The `LottieView` is wrapped in a `TimelineView` with the `.animation` schedule.
402
+ /// - This is a one-way binding. Its value is updated but never read.
403
+ /// - If provided, the binding will be updated each frame with the `realtimeAnimationProgress`
404
+ /// of the underlying `LottieAnimationView`. This is potentially expensive since it triggers
405
+ /// a state update every frame.
406
+ /// - If the binding is `nil`, the `TimelineView` will be paused and no updates will occur to the binding.
407
+ @available(iOS 15.0, tvOS 15.0, macOS 12.0, *)
408
+ public func getRealtimeAnimationFrame(_ realtimeAnimationFrame: Binding<AnimationProgressTime>?) -> some View {
409
+ TimelineView(.animation(paused: realtimeAnimationFrame == nil)) { _ in
410
+ configure { view in
411
+ if let realtimeAnimationFrame = realtimeAnimationFrame {
412
+ DispatchQueue.main.async {
413
+ realtimeAnimationFrame.wrappedValue = view.realtimeAnimationFrame
414
+ }
415
+ }
416
+ }
417
+ }
418
+ }
419
+
420
+ // MARK: Internal
421
+
422
+ var configurations = [SwiftUIView<LottieAnimationView, Void>.Configuration]()
423
+
424
+ // MARK: Private
425
+
426
+ @State private var animationSource: LottieAnimationSource?
427
+ private var playbackMode: LottiePlaybackMode?
428
+ private var reloadAnimationTrigger: AnyEquatable?
429
+ private var loadAnimation: (() async throws -> LottieAnimationSource?)?
430
+ private var animationDidLoad: ((LottieAnimationSource) -> Void)?
431
+ private var animationCompletionHandler: LottieCompletionBlock?
432
+ private var showPlaceholderWhileReloading = false
433
+ private var imageProvider: AnimationImageProvider?
434
+ private var textProvider: AnimationKeypathTextProvider = DefaultTextProvider()
435
+ private var fontProvider: AnimationFontProvider = DefaultFontProvider()
436
+ private var configuration: LottieConfiguration = .shared
437
+ private var logger: LottieLogger = .shared
438
+ private var sizing = SwiftUIMeasurementContainerStrategy.automatic
439
+ private let placeholder: (() -> Placeholder)?
440
+
441
+ private func loadAnimationIfNecessary() {
442
+ guard let loadAnimation = loadAnimation else { return }
443
+
444
+ Task {
445
+ do {
446
+ animationSource = try await loadAnimation()
447
+ } catch {
448
+ logger.warn("Failed to load asynchronous Lottie animation with error: \(error)")
449
+ }
450
+ }
451
+ }
452
+
453
+ private func reloadAnimationTriggerDidChange() {
454
+ guard loadAnimation != nil else { return }
455
+
456
+ if showPlaceholderWhileReloading {
457
+ animationSource = nil
458
+ }
459
+
460
+ loadAnimationIfNecessary()
461
+ }
462
+ }
@@ -6,12 +6,13 @@
6
6
  //
7
7
 
8
8
  import Foundation
9
+
9
10
  /// `AnimationCacheProvider` is a protocol that describes an Animation Cache.
10
11
  /// Animation Cache is used when loading `LottieAnimation` models. Using an Animation Cache
11
12
  /// can increase performance when loading an animation multiple times.
12
13
  ///
13
14
  /// Lottie comes with a prebuilt LRU Animation Cache.
14
- public protocol AnimationCacheProvider: AnyObject {
15
+ public protocol AnimationCacheProvider: AnyObject, Sendable {
15
16
 
16
17
  func animation(forKey: String) -> LottieAnimation?
17
18
 
@@ -13,7 +13,7 @@ import Foundation
13
13
  /// The default size of the cache is 100.
14
14
  ///
15
15
  /// This cache implementation also responds to memory pressure, as it's backed by `NSCache`.
16
- public class DefaultAnimationCache: AnimationCacheProvider {
16
+ public class DefaultAnimationCache: AnimationCacheProvider, @unchecked Sendable {
17
17
 
18
18
  // MARK: Lifecycle
19
19
 
@@ -27,10 +27,9 @@ public class DefaultAnimationCache: AnimationCacheProvider {
27
27
  public static let sharedCache = DefaultAnimationCache()
28
28
 
29
29
  /// The size of the cache.
30
- public var cacheSize = defaultCacheCountLimit {
31
- didSet {
32
- cache.countLimit = cacheSize
33
- }
30
+ public var cacheSize: Int {
31
+ get { cache.countLimit }
32
+ set { cache.countLimit = newValue }
34
33
  }
35
34
 
36
35
  /// Clears the Cache.
@@ -50,5 +49,5 @@ public class DefaultAnimationCache: AnimationCacheProvider {
50
49
 
51
50
  private static let defaultCacheCountLimit = 100
52
51
 
53
- private var cache = NSCache<NSString, LottieAnimation>()
52
+ private let cache = NSCache<NSString, LottieAnimation>()
54
53
  }
@@ -0,0 +1,15 @@
1
+ // Created by Cal Stephens on 7/14/23.
2
+ // Copyright © 2023 Airbnb Inc. All rights reserved.
3
+
4
+ /// How animation files should be decoded
5
+ public enum DecodingStrategy: Hashable {
6
+ /// Use Codable. This is was the default strategy introduced on Lottie 3, but should be rarely
7
+ /// used as it's slower than `dictionaryBased`. Kept here for any possible compatibility issues
8
+ /// that may come up, but consider it soft-deprecated.
9
+ case legacyCodable
10
+
11
+ /// Manually deserialize a dictionary into an Animation.
12
+ /// This should be at least 2-3x faster than using Codable and due to that
13
+ /// it's the default as of Lottie 4.x.
14
+ case dictionaryBased
15
+ }