lottie-ios 4.3.3 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/.github/workflows/main.yml +51 -58
  2. package/Lottie.xcodeproj/project.pbxproj +40 -0
  3. package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +4 -17
  4. package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +37 -40
  5. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  6. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +9 -666
  7. package/Package.resolved +20 -22
  8. package/Package.swift +4 -2
  9. package/README.md +21 -3
  10. package/Rakefile +52 -28
  11. package/Sources/PrivacyInfo.xcprivacy +23 -0
  12. package/Sources/Private/CoreAnimation/Animations/CAAnimation+TimingConfiguration.swift +1 -1
  13. package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +23 -13
  14. package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +8 -2
  15. package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +7 -1
  16. package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +15 -2
  17. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +8 -1
  18. package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +8 -1
  19. package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +12 -1
  20. package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +0 -1
  21. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +19 -11
  22. package/Sources/Private/CoreAnimation/Animations/VisibilityAnimation.swift +45 -19
  23. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +38 -3
  24. package/Sources/Private/CoreAnimation/Extensions/CALayer+fillBounds.swift +1 -1
  25. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +9 -2
  26. package/Sources/Private/CoreAnimation/Extensions/Keyframes+timeRemapping.swift +46 -0
  27. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +77 -13
  28. package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +1 -1
  29. package/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift +2 -2
  30. package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +1 -1
  31. package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +1 -7
  32. package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +19 -53
  33. package/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +2 -2
  34. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +97 -31
  35. package/Sources/Private/CoreAnimation/Layers/SolidLayer.swift +5 -2
  36. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelArrayBuilder.swift +1 -1
  37. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelProperty.swift +10 -10
  38. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingController.swift +1 -1
  39. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingView.swift +1 -3
  40. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIIntrinsicContentSizeInvalidator.swift +2 -0
  41. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUILayoutMargins.swift +2 -0
  42. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxyableView+SwiftUIView.swift +2 -0
  43. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/MeasuringViewRepresentable.swift +2 -0
  44. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift +2 -0
  45. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/SwiftUIView.swift +2 -0
  46. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIView+SwiftUIView.swift +2 -0
  47. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIViewConfiguringSwiftUIView.swift +2 -0
  48. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ViewType.swift +2 -1
  49. package/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift +256 -0
  50. package/Sources/Private/EmbeddedLibraries/LRUCache/README.md +24 -0
  51. package/Sources/Private/EmbeddedLibraries/README.md +16 -0
  52. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift +2 -2
  53. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+MemoryFile.swift +7 -7
  54. package/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift +2 -2
  55. package/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift +5 -5
  56. package/Sources/Private/MainThread/LayerContainers/CompLayers/CompositionLayer.swift +1 -2
  57. package/Sources/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift +1 -3
  58. package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +1 -2
  59. package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +2 -3
  60. package/Sources/Private/MainThread/LayerContainers/CompLayers/SolidCompositionLayer.swift +2 -3
  61. package/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift +5 -12
  62. package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +0 -1
  63. package/Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift +11 -7
  64. package/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift +3 -3
  65. package/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift +12 -12
  66. package/Sources/Private/MainThread/LayerContainers/Utility/InvertedMatteLayer.swift +1 -3
  67. package/Sources/Private/MainThread/LayerContainers/Utility/LayerFontProvider.swift +0 -2
  68. package/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift +1 -3
  69. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTextProvider.swift +0 -2
  70. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +0 -2
  71. package/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift +1 -3
  72. package/Sources/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/KeypathSearchable.swift +0 -1
  73. package/Sources/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift +0 -1
  74. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift +1 -3
  75. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift +1 -2
  76. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/PathOutputNode.swift +0 -1
  77. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift +0 -2
  78. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +0 -1
  79. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientStrokeRenderer.swift +0 -1
  80. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift +0 -1
  81. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +2 -3
  82. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +1 -3
  83. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +2 -2
  84. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +0 -2
  85. package/Sources/Private/MainThread/NodeRenderSystem/Protocols/AnimatorNode.swift +0 -1
  86. package/Sources/Private/MainThread/NodeRenderSystem/Protocols/PathNode.swift +0 -2
  87. package/Sources/Private/MainThread/NodeRenderSystem/Protocols/RenderNode.swift +0 -2
  88. package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +0 -1
  89. package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeRenderLayer.swift +0 -1
  90. package/Sources/Private/Model/Assets/Asset.swift +2 -3
  91. package/Sources/Private/Model/Assets/AssetLibrary.swift +11 -11
  92. package/Sources/Private/Model/Assets/ImageAsset.swift +20 -0
  93. package/Sources/Private/Model/Assets/PrecompAsset.swift +0 -2
  94. package/Sources/Private/Model/DictionaryInitializable.swift +18 -10
  95. package/Sources/Private/Model/DotLottie/DotLottieImageProvider.swift +9 -6
  96. package/Sources/Private/Model/DotLottie/DotLottieUtils.swift +1 -1
  97. package/Sources/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift +5 -4
  98. package/Sources/Private/Model/Keyframes/KeyframeData.swift +1 -4
  99. package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +1 -3
  100. package/Sources/Private/Model/LayerEffects/DropShadowEffect.swift +0 -2
  101. package/Sources/Private/Model/LayerEffects/EffectValues/ColorEffectValue.swift +0 -2
  102. package/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift +4 -5
  103. package/Sources/Private/Model/LayerEffects/EffectValues/Vector1DEffectValue.swift +0 -2
  104. package/Sources/Private/Model/LayerEffects/LayerEffect.swift +2 -3
  105. package/Sources/Private/Model/LayerStyles/DropShadowStyle.swift +0 -2
  106. package/Sources/Private/Model/LayerStyles/LayerStyle.swift +2 -3
  107. package/Sources/Private/Model/Layers/ImageLayerModel.swift +0 -2
  108. package/Sources/Private/Model/Layers/LayerModel.swift +16 -5
  109. package/Sources/Private/Model/Layers/PreCompLayerModel.swift +0 -2
  110. package/Sources/Private/Model/Layers/ShapeLayerModel.swift +0 -2
  111. package/Sources/Private/Model/Layers/SolidLayerModel.swift +0 -2
  112. package/Sources/Private/Model/Layers/TextLayerModel.swift +0 -2
  113. package/Sources/Private/Model/Objects/DashPattern.swift +1 -3
  114. package/Sources/Private/Model/Objects/Marker.swift +0 -2
  115. package/Sources/Private/Model/Objects/Mask.swift +0 -2
  116. package/Sources/Private/Model/Objects/Transform.swift +46 -9
  117. package/Sources/Private/Model/ShapeItems/Ellipse.swift +0 -2
  118. package/Sources/Private/Model/ShapeItems/Fill.swift +0 -2
  119. package/Sources/Private/Model/ShapeItems/GradientFill.swift +1 -3
  120. package/Sources/Private/Model/ShapeItems/GradientStroke.swift +1 -3
  121. package/Sources/Private/Model/ShapeItems/Group.swift +0 -2
  122. package/Sources/Private/Model/ShapeItems/Merge.swift +1 -3
  123. package/Sources/Private/Model/ShapeItems/Rectangle.swift +0 -2
  124. package/Sources/Private/Model/ShapeItems/Repeater.swift +0 -2
  125. package/Sources/Private/Model/ShapeItems/RoundedCorners.swift +0 -2
  126. package/Sources/Private/Model/ShapeItems/Shape.swift +0 -2
  127. package/Sources/Private/Model/ShapeItems/ShapeItem.swift +2 -3
  128. package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +0 -2
  129. package/Sources/Private/Model/ShapeItems/Star.swift +1 -3
  130. package/Sources/Private/Model/ShapeItems/Stroke.swift +0 -2
  131. package/Sources/Private/Model/ShapeItems/Trim.swift +1 -3
  132. package/Sources/Private/Model/Text/Font.swift +0 -2
  133. package/Sources/Private/Model/Text/Glyph.swift +0 -2
  134. package/Sources/Private/Model/Text/TextAnimator.swift +0 -2
  135. package/Sources/Private/Model/Text/TextDocument.swift +2 -4
  136. package/Sources/Private/Utility/Debugging/AnimatorNodeDebugging.swift +0 -2
  137. package/Sources/Private/Utility/Debugging/LayerDebugging.swift +4 -5
  138. package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +2 -3
  139. package/Sources/Private/Utility/Extensions/DataExtension.swift +0 -1
  140. package/Sources/Private/Utility/Extensions/StringExtensions.swift +5 -0
  141. package/Sources/Private/Utility/Helpers/AnimationContext.swift +2 -3
  142. package/Sources/Private/Utility/Helpers/AnyEquatable.swift +0 -2
  143. package/Sources/Private/Utility/Helpers/Binding+Map.swift +2 -0
  144. package/Sources/Private/Utility/Helpers/View+ValueChanged.swift +2 -0
  145. package/Sources/Private/Utility/LottieAnimationSource.swift +11 -1
  146. package/Sources/Private/Utility/Primitives/BezierPath.swift +2 -3
  147. package/Sources/Private/Utility/Primitives/CGPointExtension.swift +1 -1
  148. package/Sources/Private/Utility/Primitives/ColorExtension.swift +1 -2
  149. package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +6 -6
  150. package/Sources/Public/Animation/LottieAnimation.swift +2 -2
  151. package/Sources/Public/Animation/LottieAnimationHelpers.swift +7 -5
  152. package/Sources/Public/Animation/LottieAnimationLayer.swift +30 -43
  153. package/Sources/Public/Animation/LottieAnimationView.swift +18 -8
  154. package/Sources/Public/Animation/LottieAnimationViewInitializers.swift +3 -3
  155. package/Sources/Public/Animation/LottiePlaybackMode.swift +53 -0
  156. package/Sources/Public/Animation/LottieView.swift +145 -48
  157. package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +0 -2
  158. package/Sources/Public/AnimationCache/DefaultAnimationCache.swift +21 -7
  159. package/Sources/Public/AnimationCache/LRUAnimationCache.swift +0 -2
  160. package/Sources/Public/Controls/AnimatedButton.swift +4 -6
  161. package/Sources/Public/Controls/AnimatedControl.swift +1 -3
  162. package/Sources/Public/Controls/AnimatedSwitch.swift +1 -3
  163. package/Sources/Public/Controls/LottieButton.swift +2 -1
  164. package/Sources/Public/Controls/LottieSwitch.swift +2 -0
  165. package/Sources/Public/DotLottie/Cache/DotLottieCache.swift +17 -4
  166. package/Sources/Public/DotLottie/Cache/DotLottieCacheProvider.swift +1 -3
  167. package/Sources/Public/DotLottie/DotLottieConfiguration.swift +53 -5
  168. package/Sources/Public/DotLottie/DotLottieFile.swift +4 -3
  169. package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +18 -11
  170. package/Sources/Public/DynamicProperties/AnimationKeypath.swift +0 -2
  171. package/Sources/Public/DynamicProperties/AnyValueProvider.swift +0 -1
  172. package/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +2 -2
  173. package/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +1 -1
  174. package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +1 -1
  175. package/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +1 -1
  176. package/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +1 -1
  177. package/Sources/Public/FontProvider/AnimationFontProvider.swift +0 -2
  178. package/Sources/Public/ImageProvider/AnimationImageProvider.swift +0 -2
  179. package/Sources/Public/Keyframes/Interpolatable.swift +26 -0
  180. package/Sources/Public/Primitives/LottieColor.swift +0 -2
  181. package/Sources/Public/Primitives/Vectors.swift +0 -2
  182. package/Sources/Public/TextProvider/AnimationTextProvider.swift +0 -2
  183. package/Sources/Public/iOS/AnimationSubview.swift +0 -1
  184. package/Sources/Public/iOS/BundleImageProvider.swift +3 -8
  185. package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +4 -8
  186. package/Sources/Public/iOS/LottieAnimationViewBase.swift +5 -2
  187. package/Sources/Public/iOS/UIColorExtension.swift +1 -2
  188. package/Sources/Public/macOS/BundleImageProvider.macOS.swift +3 -6
  189. package/lottie-ios.podspec +6 -2
  190. package/package.json +1 -1
  191. package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  192. package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  193. package/Lottie.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +0 -37
  194. package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  195. package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
  196. package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/xcdebugger/Expressions.xcexplist +0 -153
  197. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/IDEFindNavigatorScopes.plist +0 -5
  198. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +0 -231
  199. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +0 -37
@@ -36,27 +36,8 @@ final class ShapeLayer: BaseCompositionLayer {
36
36
  private let shapeLayer: ShapeLayerModel
37
37
 
38
38
  private func setUpGroups(context: LayerContext) throws {
39
- // If the layer has a `Repeater`, the `Group`s are duplicated and offset
40
- // based on the copy count of the repeater.
41
- if let repeater = shapeLayer.items.first(where: { $0 is Repeater }) as? Repeater {
42
- try setUpRepeater(repeater, context: context)
43
- } else {
44
- let shapeItems = shapeLayer.items.map { ShapeItemLayer.Item(item: $0, groupPath: []) }
45
- try setupGroups(from: shapeItems, parentGroup: nil, parentGroupPath: [], context: context)
46
- }
47
- }
48
-
49
- private func setUpRepeater(_ repeater: Repeater, context: LayerContext) throws {
50
- let items = shapeLayer.items.filter { !($0 is Repeater) }
51
- let copyCount = Int(try repeater.copies.exactlyOneKeyframe(context: context, description: "repeater copies").value)
52
-
53
- for index in 0..<copyCount {
54
- let shapeItems = items.map { ShapeItemLayer.Item(item: $0, groupPath: []) }
55
- for groupLayer in try makeGroupLayers(from: shapeItems, parentGroup: nil, parentGroupPath: [], context: context) {
56
- let repeatedLayer = RepeaterLayer(repeater: repeater, childLayer: groupLayer, index: index)
57
- addSublayer(repeatedLayer)
58
- }
59
- }
39
+ let shapeItems = shapeLayer.items.map { ShapeItemLayer.Item(item: $0, groupPath: []) }
40
+ try setupGroups(from: shapeItems, parentGroup: nil, parentGroupPath: [], context: context)
60
41
  }
61
42
 
62
43
  }
@@ -181,6 +162,9 @@ final class GroupLayer: BaseAnimationLayer {
181
162
  }
182
163
 
183
164
  extension CALayer {
165
+
166
+ // MARK: Fileprivate
167
+
184
168
  /// Sets up `GroupLayer`s for each `Group` in the given list of `ShapeItem`s
185
169
  /// - Each `Group` item becomes its own `GroupLayer` sublayer.
186
170
  /// - Other `ShapeItem` are applied to all sublayers
@@ -191,21 +175,77 @@ extension CALayer {
191
175
  context: LayerContext)
192
176
  throws
193
177
  {
194
- let groupLayers = try makeGroupLayers(
195
- from: items,
196
- parentGroup: parentGroup,
197
- parentGroupPath: parentGroupPath,
198
- context: context)
199
-
200
- for groupLayer in groupLayers {
201
- addSublayer(groupLayer)
178
+ // If the layer has any `Repeater`s, set up each repeater
179
+ // and then handle any remaining groups like normal.
180
+ if items.contains(where: { $0.item is Repeater }) {
181
+ let repeaterGroupings = items.split(whereSeparator: { $0.item is Repeater })
182
+
183
+ // Iterate through the groupings backwards to preserve the expected rendering order
184
+ for repeaterGrouping in repeaterGroupings.reversed() {
185
+ // Each repeater applies to the previous items in the list
186
+ if let repeater = repeaterGrouping.trailingSeparator?.item as? Repeater {
187
+ try setUpRepeater(
188
+ repeater,
189
+ items: repeaterGrouping.grouping,
190
+ parentGroupPath: parentGroupPath,
191
+ context: context)
192
+ }
193
+
194
+ // Any remaining items after the last repeater are handled like normal
195
+ else {
196
+ try setupGroups(
197
+ from: repeaterGrouping.grouping,
198
+ parentGroup: parentGroup,
199
+ parentGroupPath: parentGroupPath,
200
+ context: context)
201
+ }
202
+ }
203
+ }
204
+
205
+ else {
206
+ let groupLayers = try makeGroupLayers(
207
+ from: items,
208
+ parentGroup: parentGroup,
209
+ parentGroupPath: parentGroupPath,
210
+ context: context)
211
+
212
+ for groupLayer in groupLayers {
213
+ addSublayer(groupLayer)
214
+ }
215
+ }
216
+ }
217
+
218
+ // MARK: Private
219
+
220
+ /// Sets up this layer using the given `Repeater`
221
+ private func setUpRepeater(
222
+ _ repeater: Repeater,
223
+ items allItems: [ShapeItemLayer.Item],
224
+ parentGroupPath: [String],
225
+ context: LayerContext)
226
+ throws
227
+ {
228
+ let items = allItems.filter { !($0.item is Repeater) }
229
+ let copyCount = Int(try repeater.copies.exactlyOneKeyframe(context: context, description: "repeater copies").value)
230
+
231
+ for index in 0..<copyCount {
232
+ let groupLayers = try makeGroupLayers(
233
+ from: items,
234
+ parentGroup: nil, // The repeater layer acts as the parent of its sublayers
235
+ parentGroupPath: parentGroupPath,
236
+ context: context)
237
+
238
+ for groupLayer in groupLayers {
239
+ let repeatedLayer = RepeaterLayer(repeater: repeater, childLayer: groupLayer, index: index)
240
+ addSublayer(repeatedLayer)
241
+ }
202
242
  }
203
243
  }
204
244
 
205
245
  /// Creates a `GroupLayer` for each `Group` in the given list of `ShapeItem`s
206
246
  /// - Each `Group` item becomes its own `GroupLayer` sublayer.
207
247
  /// - Other `ShapeItem` are applied to all sublayers
208
- fileprivate func makeGroupLayers(
248
+ private func makeGroupLayers(
209
249
  from items: [ShapeItemLayer.Item],
210
250
  parentGroup: Group?,
211
251
  parentGroupPath: [String],
@@ -346,6 +386,32 @@ extension Collection {
346
386
 
347
387
  return (trueElements, falseElements)
348
388
  }
389
+
390
+ /// Splits this collection into an array of grouping separated by the given separator.
391
+ /// For example, `[A, B, C]` split by `B` returns an array with two elements:
392
+ /// 1. `(grouping: [A], trailingSeparator: B)`
393
+ /// 2. `(grouping: [C], trailingSeparator: nil)`
394
+ func split(whereSeparator separatorPredicate: (Element) -> Bool)
395
+ -> [(grouping: [Element], trailingSeparator: Element?)]
396
+ {
397
+ guard !isEmpty else { return [] }
398
+
399
+ var groupings: [(grouping: [Element], trailingSeparator: Element?)] = []
400
+
401
+ for element in self {
402
+ if groupings.isEmpty || groupings.last?.trailingSeparator != nil {
403
+ groupings.append((grouping: [], trailingSeparator: nil))
404
+ }
405
+
406
+ if separatorPredicate(element) {
407
+ groupings[groupings.indices.last!].trailingSeparator = element
408
+ } else {
409
+ groupings[groupings.indices.last!].grouping.append(element)
410
+ }
411
+ }
412
+
413
+ return groupings
414
+ }
349
415
  }
350
416
 
351
417
  // MARK: - ShapeRenderGroup
@@ -359,7 +425,7 @@ struct ShapeRenderGroup {
359
425
  var otherItems: [ShapeItemLayer.Item] = []
360
426
  }
361
427
 
362
- extension Array where Element == ShapeItemLayer.Item {
428
+ extension [ShapeItemLayer.Item] {
363
429
  /// Splits this list of `ShapeItem`s into groups that should be rendered together as individual units,
364
430
  /// plus the remaining items that were not included in any group.
365
431
  /// - groupHasChildGroupsToInheritUnusedItems: whether or not this group has child groups
@@ -35,13 +35,16 @@ final class SolidLayer: BaseCompositionLayer {
35
35
  override func setupAnimations(context: LayerAnimationContext) throws {
36
36
  try super.setupAnimations(context: context)
37
37
 
38
+ var context = context
39
+ context = context.addingKeypathComponent(solidLayer.name)
40
+
38
41
  // Even though the Lottie json schema provides a fixed `solidLayer.colorHex` value,
39
42
  // we still need to create a set of keyframes and go through the standard `CAAnimation`
40
43
  // codepath so that this value can be customized using the custom `ValueProvider`s API.
41
44
  try shapeLayer.addAnimation(
42
45
  for: .fillColor,
43
- keyframes: KeyframeGroup(solidLayer.colorHex.cgColor),
44
- value: { $0 },
46
+ keyframes: KeyframeGroup(solidLayer.colorHex.lottieColor),
47
+ value: { $0.cgColorValue },
45
48
  context: context)
46
49
  }
47
50
 
@@ -16,7 +16,7 @@ enum EpoxyModelArrayBuilder<Model> {
16
16
  }
17
17
 
18
18
  static func buildExpression(_ expression: Expression?) -> Component {
19
- if let expression = expression {
19
+ if let expression {
20
20
  return [expression]
21
21
  }
22
22
  return []
@@ -93,8 +93,8 @@ extension EpoxyModelProperty.UpdateStrategy {
93
93
  /// calls the old closure and then subsequently calls the new closure.
94
94
  static func chain() -> EpoxyModelProperty<(() -> Void)?>.UpdateStrategy {
95
95
  .init { old, new in
96
- guard let new = new else { return old }
97
- guard let old = old else { return new }
96
+ guard let new else { return old }
97
+ guard let old else { return new }
98
98
  return {
99
99
  old()
100
100
  new()
@@ -106,8 +106,8 @@ extension EpoxyModelProperty.UpdateStrategy {
106
106
  /// calls the old closure and then subsequently calls the new closure.
107
107
  static func chain<A>() -> EpoxyModelProperty<((A) -> Void)?>.UpdateStrategy {
108
108
  .init { old, new in
109
- guard let new = new else { return old }
110
- guard let old = old else { return new }
109
+ guard let new else { return old }
110
+ guard let old else { return new }
111
111
  return { a in
112
112
  old(a)
113
113
  new(a)
@@ -119,8 +119,8 @@ extension EpoxyModelProperty.UpdateStrategy {
119
119
  /// calls the old closure and then subsequently calls the new closure.
120
120
  static func chain<A, B>() -> EpoxyModelProperty<((A, B) -> Void)?>.UpdateStrategy {
121
121
  .init { old, new in
122
- guard let new = new else { return old }
123
- guard let old = old else { return new }
122
+ guard let new else { return old }
123
+ guard let old else { return new }
124
124
  return { a, b in
125
125
  old(a, b)
126
126
  new(a, b)
@@ -132,8 +132,8 @@ extension EpoxyModelProperty.UpdateStrategy {
132
132
  /// calls the old closure and then subsequently calls the new closure.
133
133
  static func chain<A, B, C>() -> EpoxyModelProperty<((A, B, C) -> Void)?>.UpdateStrategy {
134
134
  .init { old, new in
135
- guard let new = new else { return old }
136
- guard let old = old else { return new }
135
+ guard let new else { return old }
136
+ guard let old else { return new }
137
137
  return { a, b, c in
138
138
  old(a, b, c)
139
139
  new(a, b, c)
@@ -145,8 +145,8 @@ extension EpoxyModelProperty.UpdateStrategy {
145
145
  /// calls the old closure and then subsequently calls the new closure.
146
146
  static func chain<A, B, C, D>() -> EpoxyModelProperty<((A, B, C, D) -> Void)?>.UpdateStrategy {
147
147
  .init { old, new in
148
- guard let new = new else { return old }
149
- guard let old = old else { return new }
148
+ guard let new else { return old }
149
+ guard let old else { return new }
150
150
  return { a, b, c, d in
151
151
  old(a, b, c, d)
152
152
  new(a, b, c, d)
@@ -1,9 +1,9 @@
1
1
  // Created by eric_horacek on 10/8/21.
2
2
  // Copyright © 2021 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(SwiftUI) && !os(macOS)
4
5
  import SwiftUI
5
6
 
6
- #if !os(macOS)
7
7
  // MARK: - EpoxySwiftUIUIHostingController
8
8
 
9
9
  /// A `UIHostingController` that hosts SwiftUI views within an Epoxy container, e.g. an Epoxy
@@ -1,11 +1,10 @@
1
1
  // Created by eric_horacek on 9/16/21.
2
2
  // Copyright © 2021 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(Combine) && canImport(SwiftUI) && !os(macOS)
4
5
  import Combine
5
6
  import SwiftUI
6
7
 
7
- #if !os(macOS)
8
-
9
8
  // MARK: - SwiftUIHostingViewReuseBehavior
10
9
 
11
10
  /// The reuse behavior of an `EpoxySwiftUIHostingView`.
@@ -387,5 +386,4 @@ struct EpoxyHostingWrapper<Content: View>: View {
387
386
  .environment(\.epoxyIntrinsicContentSizeInvalidator, environment.intrinsicContentSizeInvalidator)
388
387
  }
389
388
  }
390
-
391
389
  #endif
@@ -1,6 +1,7 @@
1
1
  // Created by matthew_cheok on 11/19/21.
2
2
  // Copyright © 2021 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(SwiftUI)
4
5
  import SwiftUI
5
6
 
6
7
  // MARK: - EpoxyIntrinsicContentSizeInvalidator
@@ -42,3 +43,4 @@ extension EnvironmentValues {
42
43
  private struct EpoxyIntrinsicContentSizeInvalidatorKey: EnvironmentKey {
43
44
  static let defaultValue = EpoxyIntrinsicContentSizeInvalidator(invalidate: { })
44
45
  }
46
+ #endif
@@ -1,6 +1,7 @@
1
1
  // Created by eric_horacek on 10/8/21.
2
2
  // Copyright © 2021 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(SwiftUI)
4
5
  import SwiftUI
5
6
 
6
7
  // MARK: - View
@@ -49,3 +50,4 @@ private struct EpoxyLayoutMarginsPadding: ViewModifier {
49
50
  content.padding(epoxyLayoutMargins)
50
51
  }
51
52
  }
53
+ #endif
@@ -1,6 +1,7 @@
1
1
  // Created by eric_horacek on 9/13/21.
2
2
  // Copyright © 2021 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(SwiftUI)
4
5
  import SwiftUI
5
6
 
6
7
  // MARK: - StyledView
@@ -170,3 +171,4 @@ extension StyledView
170
171
  }
171
172
  }
172
173
  }
174
+ #endif
@@ -1,6 +1,7 @@
1
1
  // Created by eric_horacek on 6/22/22.
2
2
  // Copyright © 2022 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(SwiftUI)
4
5
  import SwiftUI
5
6
 
6
7
  // MARK: - MeasuringViewRepresentable
@@ -126,3 +127,4 @@ extension MeasuringViewRepresentable {
126
127
  #endif
127
128
  }
128
129
  #endif
130
+ #endif
@@ -1,6 +1,7 @@
1
1
  // Created by Bryn Bodayle on 1/24/22.
2
2
  // Copyright © 2022 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(SwiftUI)
4
5
  import SwiftUI
5
6
 
6
7
  // MARK: - SwiftUIMeasurementContainer
@@ -450,3 +451,4 @@ extension CGSize {
450
451
  height: height == ViewType.noIntrinsicMetric ? fallback.height : height)
451
452
  }
452
453
  }
454
+ #endif
@@ -1,6 +1,7 @@
1
1
  // Created by eric_horacek on 9/8/22.
2
2
  // Copyright © 2022 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(SwiftUI)
4
5
  import SwiftUI
5
6
 
6
7
  // MARK: - SwiftUIView
@@ -146,3 +147,4 @@ extension SwiftUIView {
146
147
  fileprivate(set) var storage: Storage
147
148
  }
148
149
  }
150
+ #endif
@@ -1,6 +1,7 @@
1
1
  // Created by eric_horacek on 3/3/22.
2
2
  // Copyright © 2022 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(SwiftUI)
4
5
  import SwiftUI
5
6
 
6
7
  // MARK: - ViewTypeProtocol + swiftUIView
@@ -38,3 +39,4 @@ protocol ViewTypeProtocol: ViewType { }
38
39
  // MARK: - ViewType + ViewTypeProtocol
39
40
 
40
41
  extension ViewType: ViewTypeProtocol { }
42
+ #endif
@@ -1,6 +1,7 @@
1
1
  // Created by eric_horacek on 3/4/22.
2
2
  // Copyright © 2022 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(SwiftUI)
4
5
  import SwiftUI
5
6
 
6
7
  // MARK: - UIViewConfiguringSwiftUIView
@@ -41,3 +42,4 @@ extension UIViewConfiguringSwiftUIView {
41
42
  return copy
42
43
  }
43
44
  }
45
+ #endif
@@ -1,8 +1,8 @@
1
1
  // Created by Cal Stephens on 6/26/23.
2
2
  // Copyright © 2023 Airbnb Inc. All rights reserved.
3
3
 
4
+ #if canImport(SwiftUI)
4
5
  import SwiftUI
5
-
6
6
  #if canImport(UIKit)
7
7
  import UIKit
8
8
 
@@ -49,3 +49,4 @@ extension ViewRepresentableType {
49
49
  typealias RepresentableViewType = NSViewType
50
50
  }
51
51
  #endif
52
+ #endif
@@ -0,0 +1,256 @@
1
+ //
2
+ // LRUCache.swift
3
+ // LRUCache
4
+ //
5
+ // Version 1.0.2
6
+ //
7
+ // Created by Nick Lockwood on 05/08/2021.
8
+ // Copyright © 2021 Nick Lockwood. All rights reserved.
9
+ //
10
+ // Distributed under the permissive MIT license
11
+ // Get the latest version from here:
12
+ //
13
+ // https://github.com/nicklockwood/LRUCache
14
+ //
15
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ // of this software and associated documentation files (the "Software"), to deal
17
+ // in the Software without restriction, including without limitation the rights
18
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ // copies of the Software, and to permit persons to whom the Software is
20
+ // furnished to do so, subject to the following conditions:
21
+ //
22
+ // The above copyright notice and this permission notice shall be included in all
23
+ // copies or substantial portions of the Software.
24
+ //
25
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
+ // SOFTWARE.
32
+ //
33
+
34
+ import Foundation
35
+
36
+ #if canImport(UIKit)
37
+ import UIKit
38
+
39
+ /// Notification that cache should be cleared
40
+ let LRUCacheMemoryWarningNotification: NSNotification.Name =
41
+ UIApplication.didReceiveMemoryWarningNotification
42
+
43
+ #else
44
+
45
+ /// Notification that cache should be cleared
46
+ let LRUCacheMemoryWarningNotification: NSNotification.Name =
47
+ .init("LRUCacheMemoryWarningNotification")
48
+
49
+ #endif
50
+
51
+ // MARK: - LRUCache
52
+
53
+ final class LRUCache<Key: Hashable, Value> {
54
+
55
+ // MARK: Lifecycle
56
+
57
+ /// Initialize the cache with the specified `totalCostLimit` and `countLimit`
58
+ init(
59
+ totalCostLimit: Int = .max,
60
+ countLimit: Int = .max,
61
+ notificationCenter: NotificationCenter = .default)
62
+ {
63
+ self.totalCostLimit = totalCostLimit
64
+ self.countLimit = countLimit
65
+ self.notificationCenter = notificationCenter
66
+
67
+ token = notificationCenter.addObserver(
68
+ forName: LRUCacheMemoryWarningNotification,
69
+ object: nil,
70
+ queue: nil)
71
+ { [weak self] _ in
72
+ self?.removeAllValues()
73
+ }
74
+ }
75
+
76
+ deinit {
77
+ if let token {
78
+ notificationCenter.removeObserver(token)
79
+ }
80
+ }
81
+
82
+ // MARK: Internal
83
+
84
+ /// The current total cost of values in the cache
85
+ private(set) var totalCost = 0
86
+
87
+ /// The maximum total cost permitted
88
+ var totalCostLimit: Int {
89
+ didSet { clean() }
90
+ }
91
+
92
+ /// The maximum number of values permitted
93
+ var countLimit: Int {
94
+ didSet { clean() }
95
+ }
96
+
97
+ // MARK: Private
98
+
99
+ private var values: [Key: Container] = [:]
100
+ private unowned(unsafe) var head: Container?
101
+ private unowned(unsafe) var tail: Container?
102
+ private let lock: NSLock = .init()
103
+ private var token: AnyObject?
104
+ private let notificationCenter: NotificationCenter
105
+
106
+ }
107
+
108
+ extension LRUCache {
109
+ /// The number of values currently stored in the cache
110
+ var count: Int {
111
+ values.count
112
+ }
113
+
114
+ /// Is the cache empty?
115
+ var isEmpty: Bool {
116
+ values.isEmpty
117
+ }
118
+
119
+ /// Returns all values in the cache from oldest to newest
120
+ var allValues: [Value] {
121
+ lock.lock()
122
+ defer { lock.unlock() }
123
+ var values = [Value]()
124
+ var next = head
125
+ while let container = next {
126
+ values.append(container.value)
127
+ next = container.next
128
+ }
129
+ return values
130
+ }
131
+
132
+ /// Insert a value into the cache with optional `cost`
133
+ func setValue(_ value: Value?, forKey key: Key, cost: Int = 0) {
134
+ guard let value else {
135
+ removeValue(forKey: key)
136
+ return
137
+ }
138
+ lock.lock()
139
+ if let container = values[key] {
140
+ container.value = value
141
+ totalCost -= container.cost
142
+ container.cost = cost
143
+ remove(container)
144
+ append(container)
145
+ } else {
146
+ let container = Container(
147
+ value: value,
148
+ cost: cost,
149
+ key: key)
150
+ values[key] = container
151
+ append(container)
152
+ }
153
+ totalCost += cost
154
+ lock.unlock()
155
+ clean()
156
+ }
157
+
158
+ /// Remove a value from the cache and return it
159
+ @discardableResult
160
+ func removeValue(forKey key: Key) -> Value? {
161
+ lock.lock()
162
+ defer { lock.unlock() }
163
+ guard let container = values.removeValue(forKey: key) else {
164
+ return nil
165
+ }
166
+ remove(container)
167
+ totalCost -= container.cost
168
+ return container.value
169
+ }
170
+
171
+ /// Fetch a value from the cache
172
+ func value(forKey key: Key) -> Value? {
173
+ lock.lock()
174
+ defer { lock.unlock() }
175
+ if let container = values[key] {
176
+ remove(container)
177
+ append(container)
178
+ return container.value
179
+ }
180
+ return nil
181
+ }
182
+
183
+ /// Remove all values from the cache
184
+ func removeAllValues() {
185
+ lock.lock()
186
+ values.removeAll()
187
+ head = nil
188
+ tail = nil
189
+ lock.unlock()
190
+ }
191
+ }
192
+
193
+ extension LRUCache {
194
+
195
+ // MARK: Fileprivate
196
+
197
+ fileprivate final class Container {
198
+
199
+ // MARK: Lifecycle
200
+
201
+ init(value: Value, cost: Int, key: Key) {
202
+ self.value = value
203
+ self.cost = cost
204
+ self.key = key
205
+ }
206
+
207
+ // MARK: Internal
208
+
209
+ var value: Value
210
+ var cost: Int
211
+ let key: Key
212
+ unowned(unsafe) var prev: Container?
213
+ unowned(unsafe) var next: Container?
214
+
215
+ }
216
+
217
+ // MARK: Private
218
+
219
+ // Remove container from list (must be called inside lock)
220
+ private func remove(_ container: Container) {
221
+ if head === container {
222
+ head = container.next
223
+ }
224
+ if tail === container {
225
+ tail = container.prev
226
+ }
227
+ container.next?.prev = container.prev
228
+ container.prev?.next = container.next
229
+ container.next = nil
230
+ }
231
+
232
+ // Append container to list (must be called inside lock)
233
+ private func append(_ container: Container) {
234
+ assert(container.next == nil)
235
+ if head == nil {
236
+ head = container
237
+ }
238
+ container.prev = tail
239
+ tail?.next = container
240
+ tail = container
241
+ }
242
+
243
+ // Remove expired values (must be called outside lock)
244
+ private func clean() {
245
+ lock.lock()
246
+ defer { lock.unlock() }
247
+ while
248
+ totalCost > totalCostLimit || count > countLimit,
249
+ let container = head
250
+ {
251
+ remove(container)
252
+ values.removeValue(forKey: container.key)
253
+ totalCost -= container.cost
254
+ }
255
+ }
256
+ }
@@ -0,0 +1,24 @@
1
+ ## LRUCache
2
+
3
+ This directory includes the source code of the LRUCache library, from the following release:
4
+ https://github.com/nicklockwood/LRUCache/releases/tag/1.0.4
5
+
6
+ Lottie is distributed via multiple package managers (SPM, Cocoapods, Carthage, and NPM),
7
+ each with different packaging and compilation requirements.
8
+
9
+ Due to limitations of these package managers, we can't depend on / import
10
+ a separate LRUCache module / library. Instead, we include the source
11
+ directly within the Lottie library and compile everything as a single unit.
12
+
13
+ ### Update instructions
14
+
15
+ From time to time we may need to update to a more recent version of LRUCache.
16
+ When doing this, follow these steps:
17
+
18
+ 1. Download the latest release from https://github.com/nicklockwood/LRUCache
19
+ and replace the source code in this directory with the updated code.
20
+
21
+ 2. Update the URL at the top of this file to indicate what release is being used.
22
+
23
+ 3. Change all of the `public` symbols defined in this module to instead be `internal`
24
+ to prevent Lottie from exposing any EpoxyCore APIs.