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.
- package/.github/workflows/main.yml +51 -58
- package/Lottie.xcodeproj/project.pbxproj +40 -0
- package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +4 -17
- package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +37 -40
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +9 -666
- package/Package.resolved +20 -22
- package/Package.swift +4 -2
- package/README.md +21 -3
- package/Rakefile +52 -28
- package/Sources/PrivacyInfo.xcprivacy +23 -0
- package/Sources/Private/CoreAnimation/Animations/CAAnimation+TimingConfiguration.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +23 -13
- package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +8 -2
- package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +7 -1
- package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +15 -2
- package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +8 -1
- package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +8 -1
- package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +12 -1
- package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +0 -1
- package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +19 -11
- package/Sources/Private/CoreAnimation/Animations/VisibilityAnimation.swift +45 -19
- package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +38 -3
- package/Sources/Private/CoreAnimation/Extensions/CALayer+fillBounds.swift +1 -1
- package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +9 -2
- package/Sources/Private/CoreAnimation/Extensions/Keyframes+timeRemapping.swift +46 -0
- package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +77 -13
- package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +1 -1
- package/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift +2 -2
- package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +1 -1
- package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +1 -7
- package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +19 -53
- package/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +2 -2
- package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +97 -31
- package/Sources/Private/CoreAnimation/Layers/SolidLayer.swift +5 -2
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelArrayBuilder.swift +1 -1
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelProperty.swift +10 -10
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingController.swift +1 -1
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingView.swift +1 -3
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIIntrinsicContentSizeInvalidator.swift +2 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUILayoutMargins.swift +2 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxyableView+SwiftUIView.swift +2 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/MeasuringViewRepresentable.swift +2 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift +2 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/SwiftUIView.swift +2 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIView+SwiftUIView.swift +2 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIViewConfiguringSwiftUIView.swift +2 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ViewType.swift +2 -1
- package/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift +256 -0
- package/Sources/Private/EmbeddedLibraries/LRUCache/README.md +24 -0
- package/Sources/Private/EmbeddedLibraries/README.md +16 -0
- package/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift +2 -2
- package/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+MemoryFile.swift +7 -7
- package/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift +2 -2
- package/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift +5 -5
- package/Sources/Private/MainThread/LayerContainers/CompLayers/CompositionLayer.swift +1 -2
- package/Sources/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift +1 -3
- package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +1 -2
- package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +2 -3
- package/Sources/Private/MainThread/LayerContainers/CompLayers/SolidCompositionLayer.swift +2 -3
- package/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift +5 -12
- package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +0 -1
- package/Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift +11 -7
- package/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift +3 -3
- package/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift +12 -12
- package/Sources/Private/MainThread/LayerContainers/Utility/InvertedMatteLayer.swift +1 -3
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerFontProvider.swift +0 -2
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift +1 -3
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerTextProvider.swift +0 -2
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +0 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift +1 -3
- package/Sources/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/KeypathSearchable.swift +0 -1
- package/Sources/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift +0 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift +1 -3
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift +1 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/PathOutputNode.swift +0 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift +0 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +0 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientStrokeRenderer.swift +0 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift +0 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +2 -3
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +1 -3
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +2 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +0 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Protocols/AnimatorNode.swift +0 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Protocols/PathNode.swift +0 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Protocols/RenderNode.swift +0 -2
- package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +0 -1
- package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeRenderLayer.swift +0 -1
- package/Sources/Private/Model/Assets/Asset.swift +2 -3
- package/Sources/Private/Model/Assets/AssetLibrary.swift +11 -11
- package/Sources/Private/Model/Assets/ImageAsset.swift +20 -0
- package/Sources/Private/Model/Assets/PrecompAsset.swift +0 -2
- package/Sources/Private/Model/DictionaryInitializable.swift +18 -10
- package/Sources/Private/Model/DotLottie/DotLottieImageProvider.swift +9 -6
- package/Sources/Private/Model/DotLottie/DotLottieUtils.swift +1 -1
- package/Sources/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift +5 -4
- package/Sources/Private/Model/Keyframes/KeyframeData.swift +1 -4
- package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +1 -3
- package/Sources/Private/Model/LayerEffects/DropShadowEffect.swift +0 -2
- package/Sources/Private/Model/LayerEffects/EffectValues/ColorEffectValue.swift +0 -2
- package/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift +4 -5
- package/Sources/Private/Model/LayerEffects/EffectValues/Vector1DEffectValue.swift +0 -2
- package/Sources/Private/Model/LayerEffects/LayerEffect.swift +2 -3
- package/Sources/Private/Model/LayerStyles/DropShadowStyle.swift +0 -2
- package/Sources/Private/Model/LayerStyles/LayerStyle.swift +2 -3
- package/Sources/Private/Model/Layers/ImageLayerModel.swift +0 -2
- package/Sources/Private/Model/Layers/LayerModel.swift +16 -5
- package/Sources/Private/Model/Layers/PreCompLayerModel.swift +0 -2
- package/Sources/Private/Model/Layers/ShapeLayerModel.swift +0 -2
- package/Sources/Private/Model/Layers/SolidLayerModel.swift +0 -2
- package/Sources/Private/Model/Layers/TextLayerModel.swift +0 -2
- package/Sources/Private/Model/Objects/DashPattern.swift +1 -3
- package/Sources/Private/Model/Objects/Marker.swift +0 -2
- package/Sources/Private/Model/Objects/Mask.swift +0 -2
- package/Sources/Private/Model/Objects/Transform.swift +46 -9
- package/Sources/Private/Model/ShapeItems/Ellipse.swift +0 -2
- package/Sources/Private/Model/ShapeItems/Fill.swift +0 -2
- package/Sources/Private/Model/ShapeItems/GradientFill.swift +1 -3
- package/Sources/Private/Model/ShapeItems/GradientStroke.swift +1 -3
- package/Sources/Private/Model/ShapeItems/Group.swift +0 -2
- package/Sources/Private/Model/ShapeItems/Merge.swift +1 -3
- package/Sources/Private/Model/ShapeItems/Rectangle.swift +0 -2
- package/Sources/Private/Model/ShapeItems/Repeater.swift +0 -2
- package/Sources/Private/Model/ShapeItems/RoundedCorners.swift +0 -2
- package/Sources/Private/Model/ShapeItems/Shape.swift +0 -2
- package/Sources/Private/Model/ShapeItems/ShapeItem.swift +2 -3
- package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +0 -2
- package/Sources/Private/Model/ShapeItems/Star.swift +1 -3
- package/Sources/Private/Model/ShapeItems/Stroke.swift +0 -2
- package/Sources/Private/Model/ShapeItems/Trim.swift +1 -3
- package/Sources/Private/Model/Text/Font.swift +0 -2
- package/Sources/Private/Model/Text/Glyph.swift +0 -2
- package/Sources/Private/Model/Text/TextAnimator.swift +0 -2
- package/Sources/Private/Model/Text/TextDocument.swift +2 -4
- package/Sources/Private/Utility/Debugging/AnimatorNodeDebugging.swift +0 -2
- package/Sources/Private/Utility/Debugging/LayerDebugging.swift +4 -5
- package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +2 -3
- package/Sources/Private/Utility/Extensions/DataExtension.swift +0 -1
- package/Sources/Private/Utility/Extensions/StringExtensions.swift +5 -0
- package/Sources/Private/Utility/Helpers/AnimationContext.swift +2 -3
- package/Sources/Private/Utility/Helpers/AnyEquatable.swift +0 -2
- package/Sources/Private/Utility/Helpers/Binding+Map.swift +2 -0
- package/Sources/Private/Utility/Helpers/View+ValueChanged.swift +2 -0
- package/Sources/Private/Utility/LottieAnimationSource.swift +11 -1
- package/Sources/Private/Utility/Primitives/BezierPath.swift +2 -3
- package/Sources/Private/Utility/Primitives/CGPointExtension.swift +1 -1
- package/Sources/Private/Utility/Primitives/ColorExtension.swift +1 -2
- package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +6 -6
- package/Sources/Public/Animation/LottieAnimation.swift +2 -2
- package/Sources/Public/Animation/LottieAnimationHelpers.swift +7 -5
- package/Sources/Public/Animation/LottieAnimationLayer.swift +30 -43
- package/Sources/Public/Animation/LottieAnimationView.swift +18 -8
- package/Sources/Public/Animation/LottieAnimationViewInitializers.swift +3 -3
- package/Sources/Public/Animation/LottiePlaybackMode.swift +53 -0
- package/Sources/Public/Animation/LottieView.swift +145 -48
- package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +0 -2
- package/Sources/Public/AnimationCache/DefaultAnimationCache.swift +21 -7
- package/Sources/Public/AnimationCache/LRUAnimationCache.swift +0 -2
- package/Sources/Public/Controls/AnimatedButton.swift +4 -6
- package/Sources/Public/Controls/AnimatedControl.swift +1 -3
- package/Sources/Public/Controls/AnimatedSwitch.swift +1 -3
- package/Sources/Public/Controls/LottieButton.swift +2 -1
- package/Sources/Public/Controls/LottieSwitch.swift +2 -0
- package/Sources/Public/DotLottie/Cache/DotLottieCache.swift +17 -4
- package/Sources/Public/DotLottie/Cache/DotLottieCacheProvider.swift +1 -3
- package/Sources/Public/DotLottie/DotLottieConfiguration.swift +53 -5
- package/Sources/Public/DotLottie/DotLottieFile.swift +4 -3
- package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +18 -11
- package/Sources/Public/DynamicProperties/AnimationKeypath.swift +0 -2
- package/Sources/Public/DynamicProperties/AnyValueProvider.swift +0 -1
- package/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +2 -2
- package/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +1 -1
- package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +1 -1
- package/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +1 -1
- package/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +1 -1
- package/Sources/Public/FontProvider/AnimationFontProvider.swift +0 -2
- package/Sources/Public/ImageProvider/AnimationImageProvider.swift +0 -2
- package/Sources/Public/Keyframes/Interpolatable.swift +26 -0
- package/Sources/Public/Primitives/LottieColor.swift +0 -2
- package/Sources/Public/Primitives/Vectors.swift +0 -2
- package/Sources/Public/TextProvider/AnimationTextProvider.swift +0 -2
- package/Sources/Public/iOS/AnimationSubview.swift +0 -1
- package/Sources/Public/iOS/BundleImageProvider.swift +3 -8
- package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +4 -8
- package/Sources/Public/iOS/LottieAnimationViewBase.swift +5 -2
- package/Sources/Public/iOS/UIColorExtension.swift +1 -2
- package/Sources/Public/macOS/BundleImageProvider.macOS.swift +3 -6
- package/lottie-ios.podspec +6 -2
- package/package.json +1 -1
- package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcodeproj/xcuserdata/cal.xcuserdatad/xcschemes/xcschememanagement.plist +0 -37
- package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
- package/Lottie.xcworkspace/xcuserdata/cal.xcuserdatad/xcdebugger/Expressions.xcexplist +0 -153
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/IDEFindNavigatorScopes.plist +0 -5
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +0 -231
- 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
|
-
|
|
40
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
44
|
-
value: { $0 },
|
|
46
|
+
keyframes: KeyframeGroup(solidLayer.colorHex.lottieColor),
|
|
47
|
+
value: { $0.cgColorValue },
|
|
45
48
|
context: context)
|
|
46
49
|
}
|
|
47
50
|
|
|
@@ -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
|
|
97
|
-
guard let old
|
|
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
|
|
110
|
-
guard let old
|
|
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
|
|
123
|
-
guard let old
|
|
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
|
|
136
|
-
guard let old
|
|
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
|
|
149
|
-
guard let old
|
|
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)
|
package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingController.swift
CHANGED
|
@@ -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 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
|
package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIViewConfiguringSwiftUIView.swift
CHANGED
|
@@ -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.
|