lottie-ios 4.1.2 → 4.2.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 +27 -9
- package/Lottie.xcodeproj/project.pbxproj +158 -70
- package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +2 -2
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/IDEFindNavigatorScopes.plist +5 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +258 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +13 -2
- package/Package.swift +2 -1
- package/README.md +3 -3
- package/Rakefile +8 -4
- package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +16 -2
- package/Sources/Private/CoreAnimation/Animations/CombinedShapeAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +6 -6
- package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +76 -7
- package/Sources/Private/CoreAnimation/Animations/OpacityAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +66 -102
- package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +2 -2
- package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +3 -3
- package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +66 -17
- package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +55 -32
- package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +16 -12
- package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +3 -3
- package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +24 -11
- package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +2 -2
- package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +1 -1
- package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +13 -2
- package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +9 -1
- package/Sources/Private/CoreAnimation/ValueProviderStore.swift +22 -11
- package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +1 -1
- package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +13 -2
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +16 -7
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +2 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +2 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +20 -8
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +28 -9
- package/Sources/Private/Model/Assets/ImageAsset.swift +4 -3
- package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +2 -8
- package/Sources/Private/Model/DotLottie/DotLottieManifest.swift +3 -14
- package/Sources/Private/Model/DotLottie/DotLottieUtils.swift +11 -1
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+BackingConfiguration.swift +147 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Helpers.swift +351 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+MemoryFile.swift +183 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Progress.swift +66 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Reading.swift +144 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+ReadingDeprecated.swift +49 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Writing.swift +385 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+WritingDeprecated.swift +91 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+ZIP64.swift +170 -0
- package/Sources/Private/Model/DotLottie/{Zip/ZipArchive.swift → ZipFoundation/Archive.swift} +150 -227
- package/Sources/Private/Model/DotLottie/ZipFoundation/Data+Compression.swift +403 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Data+CompressionDeprecated.swift +44 -0
- package/Sources/Private/Model/DotLottie/{Zip → ZipFoundation}/Data+Serialization.swift +62 -0
- package/Sources/Private/Model/DotLottie/{Zip/ZipEntry+Serialization.swift → ZipFoundation/Entry+Serialization.swift} +7 -7
- package/Sources/Private/Model/DotLottie/{Zip/ZipEntry+ZIP64.swift → ZipFoundation/Entry+ZIP64.swift} +13 -19
- package/Sources/Private/Model/DotLottie/{Zip/ZipEntry.swift → ZipFoundation/Entry.swift} +141 -10
- package/Sources/Private/Model/DotLottie/ZipFoundation/FileManager+ZIP.swift +368 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/README.md +24 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/URL+ZIP.swift +32 -0
- package/Sources/Private/Model/Extensions/Bundle.swift +5 -14
- package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +31 -8
- package/Sources/Private/Model/Objects/Transform.swift +58 -17
- package/Sources/Private/Model/ShapeItems/Repeater.swift +41 -7
- package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +61 -7
- package/Sources/Private/Model/Text/TextAnimator.swift +37 -5
- package/Sources/Private/RootAnimationLayer.swift +3 -1
- package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +12 -4
- package/Sources/Private/Utility/Extensions/DataExtension.swift +14 -4
- package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +11 -0
- package/Sources/Private/Utility/Primitives/ColorExtension.swift +10 -13
- package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +28 -6
- package/Sources/Public/Animation/LottieAnimationHelpers.swift +12 -10
- package/Sources/Public/Animation/LottieAnimationView.swift +213 -186
- package/Sources/Public/DotLottie/DotLottieFile.swift +11 -34
- package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +101 -74
- package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +90 -0
- package/Sources/Public/iOS/LottieAnimationViewBase.swift +1 -1
- package/Sources/Public/macOS/LottieAnimationViewBase.macOS.swift +1 -1
- package/lottie-ios.podspec +1 -1
- package/package.json +1 -1
- package/LottieAnimation/LottieAnimation.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/LottieAnimation/LottieAnimation.xcodeproj/project.xcworkspace/xcuserdata/valentinperignon.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/valentinperignon.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
- package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/valentinperignon.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/Sources/Private/Model/DotLottie/Zip/Data+Compression.swift +0 -134
- package/Sources/Private/Model/DotLottie/Zip/FileManager+ZIP.swift +0 -130
- package/Sources/Private/Utility/Interpolatable/KeyframeGroup+Extensions.swift +0 -59
|
@@ -20,7 +20,9 @@ final class GroupNodeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
20
20
|
anchor = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.anchor.keyframes))
|
|
21
21
|
position = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.position.keyframes))
|
|
22
22
|
scale = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.scale.keyframes))
|
|
23
|
-
|
|
23
|
+
rotationX = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.rotationX.keyframes))
|
|
24
|
+
rotationY = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.rotationY.keyframes))
|
|
25
|
+
rotationZ = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.rotationZ.keyframes))
|
|
24
26
|
opacity = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.opacity.keyframes))
|
|
25
27
|
skew = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.skew.keyframes))
|
|
26
28
|
skewAxis = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.skewAxis.keyframes))
|
|
@@ -29,17 +31,22 @@ final class GroupNodeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
29
31
|
anchor = NodeProperty(provider: SingleValueProvider(LottieVector3D(x: CGFloat(0), y: CGFloat(0), z: CGFloat(0))))
|
|
30
32
|
position = NodeProperty(provider: SingleValueProvider(LottieVector3D(x: CGFloat(0), y: CGFloat(0), z: CGFloat(0))))
|
|
31
33
|
scale = NodeProperty(provider: SingleValueProvider(LottieVector3D(x: CGFloat(100), y: CGFloat(100), z: CGFloat(100))))
|
|
32
|
-
|
|
34
|
+
rotationX = NodeProperty(provider: SingleValueProvider(LottieVector1D(0)))
|
|
35
|
+
rotationY = NodeProperty(provider: SingleValueProvider(LottieVector1D(0)))
|
|
36
|
+
rotationZ = NodeProperty(provider: SingleValueProvider(LottieVector1D(0)))
|
|
33
37
|
opacity = NodeProperty(provider: SingleValueProvider(LottieVector1D(100)))
|
|
34
38
|
skew = NodeProperty(provider: SingleValueProvider(LottieVector1D(0)))
|
|
35
39
|
skewAxis = NodeProperty(provider: SingleValueProvider(LottieVector1D(0)))
|
|
36
40
|
}
|
|
37
41
|
keypathProperties = [
|
|
38
42
|
"Anchor Point" : anchor,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
+
PropertyName.position.rawValue : position,
|
|
44
|
+
PropertyName.scale.rawValue : scale,
|
|
45
|
+
PropertyName.rotation.rawValue : rotationZ,
|
|
46
|
+
"Rotation X" : rotationX,
|
|
47
|
+
"Rotation Y" : rotationY,
|
|
48
|
+
"Rotation Z" : rotationZ,
|
|
49
|
+
PropertyName.opacity.rawValue : opacity,
|
|
43
50
|
"Skew" : skew,
|
|
44
51
|
"Skew Axis" : skewAxis,
|
|
45
52
|
]
|
|
@@ -58,7 +65,10 @@ final class GroupNodeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
58
65
|
let anchor: NodeProperty<LottieVector3D>
|
|
59
66
|
let position: NodeProperty<LottieVector3D>
|
|
60
67
|
let scale: NodeProperty<LottieVector3D>
|
|
61
|
-
let
|
|
68
|
+
let rotationX: NodeProperty<LottieVector1D>
|
|
69
|
+
let rotationY: NodeProperty<LottieVector1D>
|
|
70
|
+
let rotationZ: NodeProperty<LottieVector1D>
|
|
71
|
+
|
|
62
72
|
let opacity: NodeProperty<LottieVector1D>
|
|
63
73
|
let skew: NodeProperty<LottieVector1D>
|
|
64
74
|
let skewAxis: NodeProperty<LottieVector1D>
|
|
@@ -68,7 +78,9 @@ final class GroupNodeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
68
78
|
anchor: anchor.value.pointValue,
|
|
69
79
|
position: position.value.pointValue,
|
|
70
80
|
scale: scale.value.sizeValue,
|
|
71
|
-
|
|
81
|
+
rotationX: rotationX.value.cgFloatValue,
|
|
82
|
+
rotationY: rotationY.value.cgFloatValue,
|
|
83
|
+
rotationZ: rotationZ.value.cgFloatValue,
|
|
72
84
|
skew: skew.value.cgFloatValue,
|
|
73
85
|
skewAxis: skewAxis.value.cgFloatValue)
|
|
74
86
|
}
|
|
@@ -20,7 +20,7 @@ final class FillNodeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
20
20
|
opacity = NodeProperty(provider: KeyframeInterpolator(keyframes: fill.opacity.keyframes))
|
|
21
21
|
type = fill.fillRule
|
|
22
22
|
keypathProperties = [
|
|
23
|
-
|
|
23
|
+
PropertyName.opacity.rawValue : opacity,
|
|
24
24
|
PropertyName.color.rawValue : color,
|
|
25
25
|
]
|
|
26
26
|
properties = Array(keypathProperties.values)
|
package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift
CHANGED
|
@@ -24,7 +24,7 @@ final class GradientFillProperties: NodePropertyMap, KeypathSearchable {
|
|
|
24
24
|
numberOfColors = gradientfill.numberOfColors
|
|
25
25
|
fillRule = gradientfill.fillRule
|
|
26
26
|
keypathProperties = [
|
|
27
|
-
|
|
27
|
+
PropertyName.opacity.rawValue : opacity,
|
|
28
28
|
"Start Point" : startPoint,
|
|
29
29
|
"End Point" : endPoint,
|
|
30
30
|
"Colors" : colors,
|
package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift
CHANGED
|
@@ -44,7 +44,7 @@ final class GradientStrokeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
44
44
|
dashPhase = NodeProperty(provider: SingleValueProvider(LottieVector1D(0)))
|
|
45
45
|
}
|
|
46
46
|
keypathProperties = [
|
|
47
|
-
|
|
47
|
+
PropertyName.opacity.rawValue : opacity,
|
|
48
48
|
"Start Point" : startPoint,
|
|
49
49
|
"End Point" : endPoint,
|
|
50
50
|
"Colors" : colors,
|
|
@@ -36,7 +36,7 @@ final class StrokeNodeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
36
36
|
dashPhase = NodeProperty(provider: SingleValueProvider(LottieVector1D(0)))
|
|
37
37
|
}
|
|
38
38
|
keypathProperties = [
|
|
39
|
-
|
|
39
|
+
PropertyName.opacity.rawValue : opacity,
|
|
40
40
|
PropertyName.color.rawValue : color,
|
|
41
41
|
"Stroke Width" : width,
|
|
42
42
|
"Dashes" : dashPattern,
|
|
@@ -28,14 +28,14 @@ final class TextAnimatorNodeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
28
28
|
|
|
29
29
|
if let keyframeGroup = textAnimator.position {
|
|
30
30
|
position = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframeGroup.keyframes))
|
|
31
|
-
properties[
|
|
31
|
+
properties[PropertyName.position.rawValue] = position
|
|
32
32
|
} else {
|
|
33
33
|
position = nil
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
if let keyframeGroup = textAnimator.scale {
|
|
37
37
|
scale = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframeGroup.keyframes))
|
|
38
|
-
properties[
|
|
38
|
+
properties[PropertyName.scale.rawValue] = scale
|
|
39
39
|
} else {
|
|
40
40
|
scale = nil
|
|
41
41
|
}
|
|
@@ -54,16 +54,31 @@ final class TextAnimatorNodeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
54
54
|
skewAxis = nil
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
if let keyframeGroup = textAnimator.
|
|
58
|
-
|
|
59
|
-
properties["Rotation"] =
|
|
57
|
+
if let keyframeGroup = textAnimator.rotationX {
|
|
58
|
+
rotationX = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframeGroup.keyframes))
|
|
59
|
+
properties["Rotation X"] = rotationX
|
|
60
60
|
} else {
|
|
61
|
-
|
|
61
|
+
rotationX = nil
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if let keyframeGroup = textAnimator.rotationY {
|
|
65
|
+
rotationY = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframeGroup.keyframes))
|
|
66
|
+
properties["Rotation Y"] = rotationY
|
|
67
|
+
} else {
|
|
68
|
+
rotationY = nil
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if let keyframeGroup = textAnimator.rotationZ {
|
|
72
|
+
rotationZ = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframeGroup.keyframes))
|
|
73
|
+
properties["Rotation Z"] = rotationZ
|
|
74
|
+
properties[PropertyName.rotation.rawValue] = rotationZ
|
|
75
|
+
} else {
|
|
76
|
+
rotationZ = nil
|
|
62
77
|
}
|
|
63
78
|
|
|
64
79
|
if let keyframeGroup = textAnimator.opacity {
|
|
65
80
|
opacity = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframeGroup.keyframes))
|
|
66
|
-
properties[
|
|
81
|
+
properties[PropertyName.opacity.rawValue] = opacity
|
|
67
82
|
} else {
|
|
68
83
|
opacity = nil
|
|
69
84
|
}
|
|
@@ -110,7 +125,9 @@ final class TextAnimatorNodeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
110
125
|
let scale: NodeProperty<LottieVector3D>?
|
|
111
126
|
let skew: NodeProperty<LottieVector1D>?
|
|
112
127
|
let skewAxis: NodeProperty<LottieVector1D>?
|
|
113
|
-
let
|
|
128
|
+
let rotationX: NodeProperty<LottieVector1D>?
|
|
129
|
+
let rotationY: NodeProperty<LottieVector1D>?
|
|
130
|
+
let rotationZ: NodeProperty<LottieVector1D>?
|
|
114
131
|
let opacity: NodeProperty<LottieVector1D>?
|
|
115
132
|
let strokeColor: NodeProperty<LottieColor>?
|
|
116
133
|
let fillColor: NodeProperty<LottieColor>?
|
|
@@ -125,7 +142,9 @@ final class TextAnimatorNodeProperties: NodePropertyMap, KeypathSearchable {
|
|
|
125
142
|
anchor: anchor?.value.pointValue ?? .zero,
|
|
126
143
|
position: position?.value.pointValue ?? .zero,
|
|
127
144
|
scale: scale?.value.sizeValue ?? CGSize(width: 100, height: 100),
|
|
128
|
-
|
|
145
|
+
rotationX: rotationX?.value.cgFloatValue ?? 0,
|
|
146
|
+
rotationY: rotationY?.value.cgFloatValue ?? 0,
|
|
147
|
+
rotationZ: rotationZ?.value.cgFloatValue ?? 0,
|
|
129
148
|
skew: skew?.value.cgFloatValue,
|
|
130
149
|
skewAxis: skewAxis?.value.cgFloatValue)
|
|
131
150
|
}
|
|
@@ -80,9 +80,10 @@ extension Data {
|
|
|
80
80
|
/// - parameter dataString: The data string to parse.
|
|
81
81
|
/// - parameter options: Options for the string parsing. Default value is `[]`.
|
|
82
82
|
internal init?(dataString: String, options: DataURLReadOptions = []) {
|
|
83
|
+
let trimmedDataString = dataString.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
83
84
|
guard
|
|
84
85
|
dataString.hasPrefix("data:"),
|
|
85
|
-
let url = URL(string:
|
|
86
|
+
let url = URL(string: trimmedDataString)
|
|
86
87
|
else {
|
|
87
88
|
return nil
|
|
88
89
|
}
|
|
@@ -90,10 +91,10 @@ extension Data {
|
|
|
90
91
|
// with messages since url doesn't have a host. This only fixes flooding logs
|
|
91
92
|
// when data inside Data URL is base64 encoded.
|
|
92
93
|
if
|
|
93
|
-
let base64Range =
|
|
94
|
+
let base64Range = trimmedDataString.range(of: ";base64,"),
|
|
94
95
|
!options.contains(DataURLReadOptions.legacy)
|
|
95
96
|
{
|
|
96
|
-
let encodedString = String(
|
|
97
|
+
let encodedString = String(trimmedDataString[base64Range.upperBound...])
|
|
97
98
|
self.init(base64Encoded: encodedString)
|
|
98
99
|
} else {
|
|
99
100
|
try? self.init(contentsOf: url)
|
|
@@ -23,9 +23,6 @@ struct DotLottieAnimation: Codable {
|
|
|
23
23
|
/// mode - "bounce" | "normal"
|
|
24
24
|
var mode: String? = "normal"
|
|
25
25
|
|
|
26
|
-
/// URL to animation, to be set internally
|
|
27
|
-
var animationUrl: URL?
|
|
28
|
-
|
|
29
26
|
/// Loop mode for animation
|
|
30
27
|
var loopMode: LottieLoopMode {
|
|
31
28
|
mode == "bounce" ? .autoReverse : ((loop ?? false) ? .loop : .playOnce)
|
|
@@ -38,12 +35,9 @@ struct DotLottieAnimation: Codable {
|
|
|
38
35
|
|
|
39
36
|
/// Loads `LottieAnimation` from `animationUrl`
|
|
40
37
|
/// - Returns: Deserialized `LottieAnimation`. Optional.
|
|
41
|
-
func animation() throws -> LottieAnimation {
|
|
42
|
-
|
|
43
|
-
throw DotLottieError.animationNotAvailable
|
|
44
|
-
}
|
|
38
|
+
func animation(url: URL) throws -> LottieAnimation {
|
|
39
|
+
let animationUrl = url.appendingPathComponent("\(id).json")
|
|
45
40
|
let data = try Data(contentsOf: animationUrl)
|
|
46
41
|
return try LottieAnimation.from(data: data)
|
|
47
42
|
}
|
|
48
|
-
|
|
49
43
|
}
|
|
@@ -10,21 +10,10 @@ import Foundation
|
|
|
10
10
|
/// Manifest model for .lottie File
|
|
11
11
|
struct DotLottieManifest: Codable {
|
|
12
12
|
|
|
13
|
-
// MARK: Lifecycle
|
|
14
|
-
|
|
15
|
-
init(animations: [DotLottieAnimation], version: String, author: String, generator: String) {
|
|
16
|
-
self.animations = animations
|
|
17
|
-
self.version = version
|
|
18
|
-
self.author = author
|
|
19
|
-
self.generator = generator
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// MARK: Internal
|
|
23
|
-
|
|
24
13
|
var animations: [DotLottieAnimation]
|
|
25
|
-
var version: String
|
|
26
|
-
var author: String
|
|
27
|
-
var generator: String
|
|
14
|
+
var version: String?
|
|
15
|
+
var author: String?
|
|
16
|
+
var generator: String?
|
|
28
17
|
|
|
29
18
|
/// Decodes data to Manifest model
|
|
30
19
|
/// - Parameter data: Data to decode
|
|
@@ -15,7 +15,7 @@ struct DotLottieUtils {
|
|
|
15
15
|
|
|
16
16
|
/// Temp folder to app directory
|
|
17
17
|
static var tempDirectoryURL: URL {
|
|
18
|
-
if #available(iOS 10.0, *) {
|
|
18
|
+
if #available(iOS 10.0, macOS 10.12, *) {
|
|
19
19
|
return FileManager.default.temporaryDirectory
|
|
20
20
|
}
|
|
21
21
|
return URL(fileURLWithPath: NSTemporaryDirectory())
|
|
@@ -52,7 +52,17 @@ extension FileManager {
|
|
|
52
52
|
// MARK: - DotLottieError
|
|
53
53
|
|
|
54
54
|
public enum DotLottieError: Error {
|
|
55
|
+
/// URL response has no data.
|
|
56
|
+
case noDataLoaded
|
|
57
|
+
/// Asset with this name was not found in the provided bundle.
|
|
58
|
+
case assetNotFound(name: String, bundle: Bundle?)
|
|
59
|
+
/// Animation loading from asset is not supported on macOS 10.10.
|
|
60
|
+
case loadingFromAssetNotSupported
|
|
61
|
+
|
|
62
|
+
@available(*, deprecated, message: "Unused")
|
|
55
63
|
case invalidFileFormat
|
|
64
|
+
@available(*, deprecated, message: "Unused")
|
|
56
65
|
case invalidData
|
|
66
|
+
@available(*, deprecated, message: "Unused")
|
|
57
67
|
case animationNotAvailable
|
|
58
68
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Archive+BackingConfiguration.swift
|
|
3
|
+
// ZIPFoundation
|
|
4
|
+
//
|
|
5
|
+
// Copyright © 2017-2021 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
|
|
6
|
+
// Released under the MIT License.
|
|
7
|
+
//
|
|
8
|
+
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
|
|
9
|
+
//
|
|
10
|
+
|
|
11
|
+
import Foundation
|
|
12
|
+
|
|
13
|
+
extension Archive {
|
|
14
|
+
|
|
15
|
+
struct BackingConfiguration {
|
|
16
|
+
let file: FILEPointer
|
|
17
|
+
let endOfCentralDirectoryRecord: EndOfCentralDirectoryRecord
|
|
18
|
+
let zip64EndOfCentralDirectory: ZIP64EndOfCentralDirectory?
|
|
19
|
+
|
|
20
|
+
#if swift(>=5.0)
|
|
21
|
+
let memoryFile: MemoryFile?
|
|
22
|
+
|
|
23
|
+
init(
|
|
24
|
+
file: FILEPointer,
|
|
25
|
+
endOfCentralDirectoryRecord: EndOfCentralDirectoryRecord,
|
|
26
|
+
zip64EndOfCentralDirectory: ZIP64EndOfCentralDirectory? = nil,
|
|
27
|
+
memoryFile: MemoryFile? = nil)
|
|
28
|
+
{
|
|
29
|
+
self.file = file
|
|
30
|
+
self.endOfCentralDirectoryRecord = endOfCentralDirectoryRecord
|
|
31
|
+
self.zip64EndOfCentralDirectory = zip64EndOfCentralDirectory
|
|
32
|
+
self.memoryFile = memoryFile
|
|
33
|
+
}
|
|
34
|
+
#else
|
|
35
|
+
|
|
36
|
+
init(
|
|
37
|
+
file: FILEPointer,
|
|
38
|
+
endOfCentralDirectoryRecord: EndOfCentralDirectoryRecord,
|
|
39
|
+
zip64EndOfCentralDirectory: ZIP64EndOfCentralDirectory?)
|
|
40
|
+
{
|
|
41
|
+
self.file = file
|
|
42
|
+
self.endOfCentralDirectoryRecord = endOfCentralDirectoryRecord
|
|
43
|
+
self.zip64EndOfCentralDirectory = zip64EndOfCentralDirectory
|
|
44
|
+
}
|
|
45
|
+
#endif
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static func makeBackingConfiguration(for url: URL, mode: AccessMode)
|
|
49
|
+
-> BackingConfiguration?
|
|
50
|
+
{
|
|
51
|
+
let fileManager = FileManager()
|
|
52
|
+
switch mode {
|
|
53
|
+
case .read:
|
|
54
|
+
let fileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
|
|
55
|
+
guard
|
|
56
|
+
let archiveFile = fopen(fileSystemRepresentation, "rb"),
|
|
57
|
+
let (eocdRecord, zip64EOCD) = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else
|
|
58
|
+
{
|
|
59
|
+
return nil
|
|
60
|
+
}
|
|
61
|
+
return BackingConfiguration(
|
|
62
|
+
file: archiveFile,
|
|
63
|
+
endOfCentralDirectoryRecord: eocdRecord,
|
|
64
|
+
zip64EndOfCentralDirectory: zip64EOCD)
|
|
65
|
+
case .create:
|
|
66
|
+
let endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord(
|
|
67
|
+
numberOfDisk: 0,
|
|
68
|
+
numberOfDiskStart: 0,
|
|
69
|
+
totalNumberOfEntriesOnDisk: 0,
|
|
70
|
+
totalNumberOfEntriesInCentralDirectory: 0,
|
|
71
|
+
sizeOfCentralDirectory: 0,
|
|
72
|
+
offsetToStartOfCentralDirectory: 0,
|
|
73
|
+
zipFileCommentLength: 0,
|
|
74
|
+
zipFileCommentData: Data())
|
|
75
|
+
do {
|
|
76
|
+
try endOfCentralDirectoryRecord.data.write(to: url, options: .withoutOverwriting)
|
|
77
|
+
} catch { return nil }
|
|
78
|
+
fallthrough
|
|
79
|
+
case .update:
|
|
80
|
+
let fileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
|
|
81
|
+
guard
|
|
82
|
+
let archiveFile = fopen(fileSystemRepresentation, "rb+"),
|
|
83
|
+
let (eocdRecord, zip64EOCD) = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else
|
|
84
|
+
{
|
|
85
|
+
return nil
|
|
86
|
+
}
|
|
87
|
+
fseeko(archiveFile, 0, SEEK_SET)
|
|
88
|
+
return BackingConfiguration(
|
|
89
|
+
file: archiveFile,
|
|
90
|
+
endOfCentralDirectoryRecord: eocdRecord,
|
|
91
|
+
zip64EndOfCentralDirectory: zip64EOCD)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#if swift(>=5.0)
|
|
96
|
+
static func makeBackingConfiguration(for data: Data, mode: AccessMode)
|
|
97
|
+
-> BackingConfiguration?
|
|
98
|
+
{
|
|
99
|
+
let posixMode: String
|
|
100
|
+
switch mode {
|
|
101
|
+
case .read: posixMode = "rb"
|
|
102
|
+
case .create: posixMode = "wb+"
|
|
103
|
+
case .update: posixMode = "rb+"
|
|
104
|
+
}
|
|
105
|
+
let memoryFile = MemoryFile(data: data)
|
|
106
|
+
guard let archiveFile = memoryFile.open(mode: posixMode) else { return nil }
|
|
107
|
+
|
|
108
|
+
switch mode {
|
|
109
|
+
case .read:
|
|
110
|
+
guard let (eocdRecord, zip64EOCD) = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else {
|
|
111
|
+
return nil
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return BackingConfiguration(
|
|
115
|
+
file: archiveFile,
|
|
116
|
+
endOfCentralDirectoryRecord: eocdRecord,
|
|
117
|
+
zip64EndOfCentralDirectory: zip64EOCD,
|
|
118
|
+
memoryFile: memoryFile)
|
|
119
|
+
case .create:
|
|
120
|
+
let endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord(
|
|
121
|
+
numberOfDisk: 0,
|
|
122
|
+
numberOfDiskStart: 0,
|
|
123
|
+
totalNumberOfEntriesOnDisk: 0,
|
|
124
|
+
totalNumberOfEntriesInCentralDirectory: 0,
|
|
125
|
+
sizeOfCentralDirectory: 0,
|
|
126
|
+
offsetToStartOfCentralDirectory: 0,
|
|
127
|
+
zipFileCommentLength: 0,
|
|
128
|
+
zipFileCommentData: Data())
|
|
129
|
+
_ = endOfCentralDirectoryRecord.data.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) in
|
|
130
|
+
fwrite(buffer.baseAddress, buffer.count, 1, archiveFile) // Errors handled during read
|
|
131
|
+
}
|
|
132
|
+
fallthrough
|
|
133
|
+
case .update:
|
|
134
|
+
guard let (eocdRecord, zip64EOCD) = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else {
|
|
135
|
+
return nil
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
fseeko(archiveFile, 0, SEEK_SET)
|
|
139
|
+
return BackingConfiguration(
|
|
140
|
+
file: archiveFile,
|
|
141
|
+
endOfCentralDirectoryRecord: eocdRecord,
|
|
142
|
+
zip64EndOfCentralDirectory: zip64EOCD,
|
|
143
|
+
memoryFile: memoryFile)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
#endif
|
|
147
|
+
}
|