lottie-ios 4.2.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/main.yml +117 -11
- package/Gemfile +1 -0
- package/Gemfile.lock +5 -0
- package/Lottie.xcodeproj/project.pbxproj +1542 -194
- package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (iOS).xcscheme +1 -1
- package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (macOS).xcscheme +1 -1
- package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (tvOS).xcscheme +4 -5
- package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (visionOS).xcscheme +66 -0
- package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +18 -0
- package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +2 -11
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +346 -102
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +16 -5
- package/Package.resolved +2 -2
- package/Package.swift +16 -9
- package/README.md +2 -2
- package/Rakefile +122 -25
- package/Sources/Private/CoreAnimation/Animations/DropShadowAnimation.swift +160 -0
- package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +83 -10
- package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +85 -79
- package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +7 -7
- package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +67 -6
- package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +2 -2
- package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +9 -0
- package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +1 -0
- package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +1 -1
- package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +2 -0
- package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +11 -13
- package/Sources/Private/CoreAnimation/Layers/SolidLayer.swift +20 -5
- package/Sources/Private/CoreAnimation/Layers/TextLayer.swift +13 -3
- package/Sources/Private/CoreAnimation/ValueProviderStore.swift +6 -4
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/Collection+Diff.swift +263 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/Diffable.swift +18 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/DiffableSection.swift +16 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/IndexChangeset.swift +187 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/SectionedChangeset.swift +32 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Logging/EpoxyLogger.swift +99 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/CallbackContextEpoxyModeled.swift +8 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelArrayBuilder.swift +48 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelProperty.swift +158 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelStorage.swift +88 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModeled.swift +54 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Internal/AnyEpoxyModelProperty.swift +29 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Internal/ClassReference.swift +39 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/AnimatedProviding.swift +10 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DataIDProviding.swift +57 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidDisplayProviding.swift +41 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidEndDisplayingProviding.swift +41 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidSelectProviding.swift +36 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ErasedContentProviding.swift +49 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/MakeViewProviding.swift +60 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/SetBehaviorsProviding.swift +38 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/SetContentProviding.swift +38 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/StyleIDProviding.swift +37 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/TraitCollectionProviding.swift +14 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ViewDifferentiatorProviding.swift +34 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ViewProviding.swift +13 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/WillDisplayProviding.swift +41 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/ViewEpoxyModeled.swift +10 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/README.md +31 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingController.swift +46 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingView.swift +391 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIIntrinsicContentSizeInvalidator.swift +44 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUILayoutMargins.swift +51 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxyableView+SwiftUIView.swift +172 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/MeasuringViewRepresentable.swift +128 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift +452 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/SwiftUIView.swift +148 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIView+SwiftUIView.swift +40 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIViewConfiguringSwiftUIView.swift +43 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/BehaviorsConfigurableView.swift +45 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ContentConfigurableView.swift +36 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/EpoxyableView.swift +5 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/StyledView.swift +42 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ViewType.swift +51 -0
- package/Sources/Private/EmbeddedLibraries/README.md +27 -0
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+BackingConfiguration.swift +4 -4
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+MemoryFile.swift +2 -2
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Writing.swift +4 -4
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive.swift +8 -7
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+Compression.swift +5 -5
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/FileManager+ZIP.swift +4 -4
- package/Sources/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift +6 -0
- package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +3 -1
- package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +18 -5
- package/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift +31 -3
- package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +33 -8
- package/Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift +8 -1
- package/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift +13 -4
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerFontProvider.swift +2 -2
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift +1 -0
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerTextProvider.swift +4 -4
- package/Sources/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +3 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +2 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift +2 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +2 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +6 -2
- package/Sources/Private/Model/Assets/Asset.swift +8 -0
- package/Sources/Private/Model/Assets/AssetLibrary.swift +2 -2
- package/Sources/Private/Model/Assets/ImageAsset.swift +3 -3
- package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +16 -2
- package/Sources/Private/Model/DotLottie/DotLottieImageProvider.swift +20 -7
- package/Sources/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift +26 -0
- package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +8 -5
- package/Sources/Private/Model/LayerEffects/DropShadowEffect.swift +45 -0
- package/Sources/Private/Model/LayerEffects/EffectValues/ColorEffectValue.swift +38 -0
- package/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift +98 -0
- package/Sources/Private/Model/LayerEffects/EffectValues/Vector1DEffectValue.swift +38 -0
- package/Sources/Private/Model/LayerEffects/LayerEffect.swift +103 -0
- package/Sources/Private/Model/LayerStyles/DropShadowStyle.swift +72 -0
- package/Sources/Private/Model/LayerStyles/LayerStyle.swift +85 -0
- package/Sources/Private/Model/Layers/LayerModel.swift +27 -0
- package/Sources/Private/Model/Objects/Marker.swift +1 -1
- package/Sources/Private/Model/Objects/Transform.swift +1 -2
- package/Sources/Private/Model/ShapeItems/GradientFill.swift +1 -1
- package/Sources/Private/Model/ShapeItems/GradientStroke.swift +2 -2
- package/Sources/Private/Model/ShapeItems/Merge.swift +1 -1
- package/Sources/Private/Model/ShapeItems/ShapeItem.swift +31 -26
- package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +0 -9
- package/Sources/Private/Model/ShapeItems/Star.swift +1 -1
- package/Sources/Private/Model/Text/Font.swift +2 -2
- package/Sources/Private/Model/Text/Glyph.swift +1 -1
- package/Sources/Private/RootAnimationLayer.swift +2 -2
- package/Sources/Private/Utility/Debugging/LayerDebugging.swift +3 -1
- package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +32 -2
- package/Sources/Private/Utility/Helpers/AnimationContext.swift +4 -2
- package/Sources/Private/Utility/Helpers/AnyEquatable.swift +24 -0
- package/Sources/Private/Utility/Helpers/Binding+Map.swift +18 -0
- package/Sources/Private/Utility/Helpers/View+ValueChanged.swift +20 -0
- package/Sources/Private/Utility/LottieAnimationSource.swift +41 -0
- package/Sources/Private/Utility/Primitives/BezierPath.swift +2 -2
- package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +2 -2
- package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +1 -1
- package/Sources/Public/Animation/LottieAnimation.swift +21 -2
- package/Sources/Public/Animation/LottieAnimationLayer.swift +1464 -0
- package/Sources/Public/Animation/LottieAnimationView.swift +258 -735
- package/Sources/Public/Animation/LottiePlaybackMode.swift +117 -0
- package/Sources/Public/Animation/LottieView.swift +462 -0
- package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +2 -1
- package/Sources/Public/AnimationCache/DefaultAnimationCache.swift +5 -6
- package/Sources/Public/Configuration/DecodingStrategy.swift +15 -0
- package/Sources/Public/Configuration/LottieConfiguration.swift +47 -0
- package/Sources/Public/Configuration/ReducedMotionOption.swift +114 -0
- package/Sources/Public/{LottieConfiguration.swift → Configuration/RenderingEngineOption.swift} +2 -57
- package/Sources/Public/{iOS → Controls}/AnimatedButton.swift +56 -13
- package/Sources/Public/{iOS → Controls}/AnimatedControl.swift +80 -8
- package/Sources/Public/{iOS → Controls}/AnimatedSwitch.swift +71 -31
- package/Sources/Public/Controls/LottieButton.swift +122 -0
- package/Sources/Public/Controls/LottieSwitch.swift +144 -0
- package/Sources/Public/Controls/LottieViewType.swift +79 -0
- package/Sources/Public/DotLottie/DotLottieConfiguration.swift +24 -0
- package/Sources/Public/DotLottie/DotLottieFile.swift +21 -6
- package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +79 -0
- package/Sources/Public/DynamicProperties/AnimationKeypath.swift +11 -1
- package/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +14 -0
- package/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +13 -0
- package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +22 -5
- package/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +14 -0
- package/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +13 -0
- package/Sources/Public/FontProvider/AnimationFontProvider.swift +8 -0
- package/Sources/Public/ImageProvider/AnimationImageProvider.swift +24 -0
- package/Sources/Public/Keyframes/Keyframe.swift +6 -0
- package/Sources/Public/Primitives/Vectors.swift +2 -2
- package/Sources/Public/TextProvider/AnimationTextProvider.swift +79 -6
- package/Sources/Public/iOS/AnimationSubview.swift +1 -1
- package/Sources/Public/iOS/BundleImageProvider.swift +16 -2
- package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +2 -2
- package/Sources/Public/iOS/FilepathImageProvider.swift +22 -3
- package/Sources/Public/iOS/LottieAnimationViewBase.swift +7 -1
- package/Sources/Public/macOS/BundleImageProvider.macOS.swift +15 -1
- package/Sources/Public/macOS/FilepathImageProvider.macOS.swift +21 -2
- package/lottie-ios.podspec +2 -1
- package/package.json +1 -1
- package/Sources/Private/Model/DotLottie/DotLottieConfiguration.swift +0 -15
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Helpers.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Progress.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Reading.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+ReadingDeprecated.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+WritingDeprecated.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+ZIP64.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+CompressionDeprecated.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+Serialization.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry+Serialization.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry+ZIP64.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/README.md +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/URL+ZIP.swift +0 -0
|
@@ -6,65 +6,79 @@
|
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
#if canImport(UIKit)
|
|
10
11
|
import UIKit
|
|
12
|
+
#elseif canImport(AppKit)
|
|
13
|
+
import AppKit
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
// MARK: - AnimatedSwitch
|
|
11
17
|
|
|
12
18
|
/// An interactive switch with an 'On' and 'Off' state. When the user taps on the
|
|
13
19
|
/// switch the state is toggled and the appropriate animation is played.
|
|
14
20
|
///
|
|
15
21
|
/// Both the 'On' and 'Off' have an animation play range associated with their state.
|
|
22
|
+
///
|
|
23
|
+
/// Also available as a SwiftUI view (`LottieSwitch`).
|
|
16
24
|
open class AnimatedSwitch: AnimatedControl {
|
|
17
25
|
|
|
18
26
|
// MARK: Lifecycle
|
|
19
27
|
|
|
20
28
|
public override init(
|
|
21
|
-
animation: LottieAnimation
|
|
29
|
+
animation: LottieAnimation?,
|
|
22
30
|
configuration: LottieConfiguration = .shared)
|
|
23
31
|
{
|
|
24
32
|
/// Generate a haptic generator if available.
|
|
25
33
|
#if os(iOS)
|
|
26
|
-
|
|
27
|
-
self.hapticGenerator = HapticGenerator()
|
|
28
|
-
} else {
|
|
29
|
-
hapticGenerator = NullHapticGenerator()
|
|
30
|
-
}
|
|
34
|
+
hapticGenerator = HapticGenerator()
|
|
31
35
|
#else
|
|
32
36
|
hapticGenerator = NullHapticGenerator()
|
|
33
37
|
#endif
|
|
34
38
|
super.init(animation: animation, configuration: configuration)
|
|
39
|
+
|
|
40
|
+
#if canImport(UIKit)
|
|
35
41
|
isAccessibilityElement = true
|
|
42
|
+
#elseif canImport(AppKit)
|
|
43
|
+
setAccessibilityElement(true)
|
|
44
|
+
#endif
|
|
45
|
+
|
|
36
46
|
updateOnState(isOn: _isOn, animated: false, shouldFireHaptics: false)
|
|
37
47
|
}
|
|
38
48
|
|
|
39
49
|
public override init() {
|
|
40
50
|
/// Generate a haptic generator if available.
|
|
41
51
|
#if os(iOS)
|
|
42
|
-
|
|
43
|
-
self.hapticGenerator = HapticGenerator()
|
|
44
|
-
} else {
|
|
45
|
-
hapticGenerator = NullHapticGenerator()
|
|
46
|
-
}
|
|
52
|
+
hapticGenerator = HapticGenerator()
|
|
47
53
|
#else
|
|
48
54
|
hapticGenerator = NullHapticGenerator()
|
|
49
55
|
#endif
|
|
56
|
+
|
|
50
57
|
super.init()
|
|
58
|
+
|
|
59
|
+
#if canImport(UIKit)
|
|
51
60
|
isAccessibilityElement = true
|
|
61
|
+
#elseif canImport(AppKit)
|
|
62
|
+
setAccessibilityElement(true)
|
|
63
|
+
#endif
|
|
64
|
+
|
|
52
65
|
updateOnState(isOn: _isOn, animated: false, shouldFireHaptics: false)
|
|
53
66
|
}
|
|
54
67
|
|
|
55
68
|
required public init?(coder aDecoder: NSCoder) {
|
|
56
69
|
/// Generate a haptic generator if available.
|
|
57
70
|
#if os(iOS)
|
|
58
|
-
|
|
59
|
-
self.hapticGenerator = HapticGenerator()
|
|
60
|
-
} else {
|
|
61
|
-
hapticGenerator = NullHapticGenerator()
|
|
62
|
-
}
|
|
71
|
+
hapticGenerator = HapticGenerator()
|
|
63
72
|
#else
|
|
64
73
|
hapticGenerator = NullHapticGenerator()
|
|
65
74
|
#endif
|
|
66
75
|
super.init(coder: aDecoder)
|
|
76
|
+
|
|
77
|
+
#if canImport(UIKit)
|
|
67
78
|
isAccessibilityElement = true
|
|
79
|
+
#elseif canImport(AppKit)
|
|
80
|
+
setAccessibilityElement(true)
|
|
81
|
+
#endif
|
|
68
82
|
}
|
|
69
83
|
|
|
70
84
|
// MARK: Open
|
|
@@ -73,12 +87,23 @@ open class AnimatedSwitch: AnimatedControl {
|
|
|
73
87
|
updateOnState(isOn: _isOn, animated: animateUpdateWhenChangingAnimation, shouldFireHaptics: false)
|
|
74
88
|
}
|
|
75
89
|
|
|
90
|
+
#if canImport(UIKit)
|
|
76
91
|
open override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
|
|
77
92
|
super.endTracking(touch, with: event)
|
|
78
93
|
updateOnState(isOn: !_isOn, animated: true, shouldFireHaptics: true)
|
|
79
94
|
sendActions(for: .valueChanged)
|
|
80
95
|
}
|
|
81
96
|
|
|
97
|
+
#elseif canImport(AppKit)
|
|
98
|
+
open override func handle(_ event: LottieNSControlEvent) {
|
|
99
|
+
super.handle(event)
|
|
100
|
+
|
|
101
|
+
if event == .touchUpInside {
|
|
102
|
+
updateOnState(isOn: !_isOn, animated: true, shouldFireHaptics: true)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
#endif
|
|
106
|
+
|
|
82
107
|
// MARK: Public
|
|
83
108
|
|
|
84
109
|
/// Defines what happens when the user taps the switch while an
|
|
@@ -94,10 +119,15 @@ open class AnimatedSwitch: AnimatedControl {
|
|
|
94
119
|
/// If `false` the switch will not play the animation when changing between animations.
|
|
95
120
|
public var animateUpdateWhenChangingAnimation = true
|
|
96
121
|
|
|
122
|
+
#if canImport(UIKit)
|
|
97
123
|
public override var accessibilityTraits: UIAccessibilityTraits {
|
|
98
124
|
set { super.accessibilityTraits = newValue }
|
|
99
125
|
get { super.accessibilityTraits.union(.button) }
|
|
100
126
|
}
|
|
127
|
+
#endif
|
|
128
|
+
|
|
129
|
+
/// A closure that is called when the `isOn` state is updated
|
|
130
|
+
public var stateUpdated: ((_ isOn: Bool) -> Void)?
|
|
101
131
|
|
|
102
132
|
/// The current state of the switch.
|
|
103
133
|
public var isOn: Bool {
|
|
@@ -136,6 +166,11 @@ open class AnimatedSwitch: AnimatedControl {
|
|
|
136
166
|
|
|
137
167
|
// MARK: Internal
|
|
138
168
|
|
|
169
|
+
private(set) var onStartProgress: CGFloat = 0
|
|
170
|
+
private(set) var onEndProgress: CGFloat = 1
|
|
171
|
+
private(set) var offStartProgress: CGFloat = 1
|
|
172
|
+
private(set) var offEndProgress: CGFloat = 0
|
|
173
|
+
|
|
139
174
|
// MARK: Animation State
|
|
140
175
|
|
|
141
176
|
func updateOnState(isOn: Bool, animated: Bool, shouldFireHaptics: Bool) {
|
|
@@ -188,21 +223,27 @@ open class AnimatedSwitch: AnimatedControl {
|
|
|
188
223
|
|
|
189
224
|
// MARK: Fileprivate
|
|
190
225
|
|
|
191
|
-
fileprivate var onStartProgress: CGFloat = 0
|
|
192
|
-
fileprivate var onEndProgress: CGFloat = 1
|
|
193
|
-
fileprivate var offStartProgress: CGFloat = 1
|
|
194
|
-
fileprivate var offEndProgress: CGFloat = 0
|
|
195
|
-
fileprivate var _isOn = false
|
|
196
226
|
fileprivate var hapticGenerator: ImpactGenerator
|
|
197
227
|
|
|
228
|
+
fileprivate var _isOn = false {
|
|
229
|
+
didSet {
|
|
230
|
+
stateUpdated?(_isOn)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
198
234
|
// MARK: Private
|
|
199
235
|
|
|
200
236
|
private func updateAccessibilityLabel() {
|
|
201
|
-
|
|
237
|
+
let value = _isOn ? NSLocalizedString("On", comment: "On") : NSLocalizedString("Off", comment: "Off")
|
|
238
|
+
|
|
239
|
+
#if canImport(UIKit)
|
|
240
|
+
accessibilityValue = value
|
|
241
|
+
#elseif canImport(AppKit)
|
|
242
|
+
setAccessibilityValue(value)
|
|
243
|
+
#endif
|
|
202
244
|
}
|
|
203
245
|
|
|
204
246
|
}
|
|
205
|
-
#endif
|
|
206
247
|
|
|
207
248
|
// MARK: - ImpactGenerator
|
|
208
249
|
|
|
@@ -210,14 +251,7 @@ protocol ImpactGenerator {
|
|
|
210
251
|
func generateImpact()
|
|
211
252
|
}
|
|
212
253
|
|
|
213
|
-
// MARK: - NullHapticGenerator
|
|
214
|
-
|
|
215
|
-
class NullHapticGenerator: ImpactGenerator {
|
|
216
|
-
func generateImpact() { }
|
|
217
|
-
}
|
|
218
|
-
|
|
219
254
|
#if os(iOS)
|
|
220
|
-
@available(iOS 10.0, *)
|
|
221
255
|
class HapticGenerator: ImpactGenerator {
|
|
222
256
|
|
|
223
257
|
// MARK: Internal
|
|
@@ -230,4 +264,10 @@ class HapticGenerator: ImpactGenerator {
|
|
|
230
264
|
|
|
231
265
|
fileprivate let impact = UIImpactFeedbackGenerator(style: .light)
|
|
232
266
|
}
|
|
267
|
+
#else
|
|
268
|
+
// MARK: - NullHapticGenerator
|
|
269
|
+
|
|
270
|
+
class NullHapticGenerator: ImpactGenerator {
|
|
271
|
+
func generateImpact() { }
|
|
272
|
+
}
|
|
233
273
|
#endif
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Created by Cal Stephens on 8/14/23.
|
|
2
|
+
// Copyright © 2023 Airbnb Inc. All rights reserved.
|
|
3
|
+
|
|
4
|
+
import SwiftUI
|
|
5
|
+
|
|
6
|
+
/// A wrapper which exposes Lottie's `AnimatedButton` to SwiftUI
|
|
7
|
+
@available(iOS 13.0, tvOS 13.0, macOS 10.15, *)
|
|
8
|
+
public struct LottieButton: UIViewConfiguringSwiftUIView {
|
|
9
|
+
|
|
10
|
+
// MARK: Lifecycle
|
|
11
|
+
|
|
12
|
+
public init(animation: LottieAnimation?, action: @escaping () -> Void) {
|
|
13
|
+
self.animation = animation
|
|
14
|
+
self.action = action
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// MARK: Public
|
|
18
|
+
|
|
19
|
+
public var body: some View {
|
|
20
|
+
AnimatedButton.swiftUIView {
|
|
21
|
+
let button = AnimatedButton(animation: animation, configuration: configuration)
|
|
22
|
+
button.performAction = action
|
|
23
|
+
return button
|
|
24
|
+
}
|
|
25
|
+
.configure { context in
|
|
26
|
+
// We check referential equality of the animation before updating as updating the
|
|
27
|
+
// animation has a side-effect of rebuilding the animation layer, and it would be
|
|
28
|
+
// prohibitive to do so on every state update.
|
|
29
|
+
if animation !== context.view.animationView.animation {
|
|
30
|
+
context.view.animationView.animation = animation
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#if os(macOS)
|
|
34
|
+
// Disable the intrinsic content size constraint on the inner animation view,
|
|
35
|
+
// or the Epoxy `SwiftUIMeasurementContainer` won't size this view correctly.
|
|
36
|
+
context.view.animationView.isVerticalContentSizeConstraintActive = false
|
|
37
|
+
context.view.animationView.isHorizontalContentSizeConstraintActive = false
|
|
38
|
+
#endif
|
|
39
|
+
}
|
|
40
|
+
.configurations(configurations)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Returns a copy of this `LottieView` updated to have the given closure applied to its
|
|
44
|
+
/// represented `LottieAnimationView` whenever it is updated via the `updateUIView(…)`
|
|
45
|
+
/// or `updateNSView(…)` method.
|
|
46
|
+
public func configure(_ configure: @escaping (AnimatedButton) -> Void) -> Self {
|
|
47
|
+
var copy = self
|
|
48
|
+
copy.configurations.append { context in
|
|
49
|
+
configure(context.view)
|
|
50
|
+
}
|
|
51
|
+
return copy
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// Returns a copy of this view with its `LottieConfiguration` updated to the given value.
|
|
55
|
+
public func configuration(_ configuration: LottieConfiguration) -> Self {
|
|
56
|
+
var copy = self
|
|
57
|
+
copy.configuration = configuration
|
|
58
|
+
|
|
59
|
+
copy = copy.configure { view in
|
|
60
|
+
if view.animationView.configuration != configuration {
|
|
61
|
+
view.animationView.configuration = configuration
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return copy
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// Returns a copy of this view configured to animate between the
|
|
69
|
+
/// given progress values when the given event is triggered
|
|
70
|
+
public func animate(
|
|
71
|
+
fromProgress: AnimationProgressTime,
|
|
72
|
+
toProgress: AnimationProgressTime,
|
|
73
|
+
on event: LottieControlEvent)
|
|
74
|
+
-> Self
|
|
75
|
+
{
|
|
76
|
+
configure { view in
|
|
77
|
+
// `setPlayRange` just modifies a dictionary,
|
|
78
|
+
// so we can just call it on every state update without diffing
|
|
79
|
+
view.setPlayRange(fromProgress: fromProgress, toProgress: toProgress, event: event)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// Returns a copy of this view configured to animate between the
|
|
84
|
+
/// given markers when the given event is triggered
|
|
85
|
+
public func animate(
|
|
86
|
+
fromMarker: String,
|
|
87
|
+
toMarker: String,
|
|
88
|
+
on event: LottieControlEvent)
|
|
89
|
+
-> Self
|
|
90
|
+
{
|
|
91
|
+
configure { view in
|
|
92
|
+
// `setPlayRange` just modifies a dictionary,
|
|
93
|
+
// so we can just call it on every state update without diffing
|
|
94
|
+
view.setPlayRange(fromMarker: fromMarker, toMarker: toMarker, event: event)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// Returns a copy of this view using the given value provider for the given keypath.
|
|
99
|
+
/// The value provider must be `Equatable` to avoid unnecessary state updates / re-renders.
|
|
100
|
+
public func valueProvider<ValueProvider: AnyValueProvider & Equatable>(
|
|
101
|
+
_ valueProvider: ValueProvider,
|
|
102
|
+
for keypath: AnimationKeypath)
|
|
103
|
+
-> Self
|
|
104
|
+
{
|
|
105
|
+
configure { view in
|
|
106
|
+
if (view.animationView.valueProviders[keypath] as? ValueProvider) != valueProvider {
|
|
107
|
+
view.animationView.setValueProvider(valueProvider, keypath: keypath)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// MARK: Internal
|
|
113
|
+
|
|
114
|
+
var configurations = [SwiftUIView<AnimatedButton, Void>.Configuration]()
|
|
115
|
+
|
|
116
|
+
// MARK: Private
|
|
117
|
+
|
|
118
|
+
private let animation: LottieAnimation?
|
|
119
|
+
private let action: () -> Void
|
|
120
|
+
private var configuration: LottieConfiguration = .shared
|
|
121
|
+
|
|
122
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Created by Cal Stephens on 8/11/23.
|
|
2
|
+
// Copyright © 2023 Airbnb Inc. All rights reserved.
|
|
3
|
+
|
|
4
|
+
import SwiftUI
|
|
5
|
+
|
|
6
|
+
/// A wrapper which exposes Lottie's `AnimatedSwitch` to SwiftUI
|
|
7
|
+
@available(iOS 13.0, tvOS 13.0, macOS 10.15, *)
|
|
8
|
+
public struct LottieSwitch: UIViewConfiguringSwiftUIView {
|
|
9
|
+
|
|
10
|
+
// MARK: Lifecycle
|
|
11
|
+
|
|
12
|
+
public init(animation: LottieAnimation?) {
|
|
13
|
+
self.animation = animation
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// MARK: Public
|
|
17
|
+
|
|
18
|
+
public var body: some View {
|
|
19
|
+
AnimatedSwitch.swiftUIView {
|
|
20
|
+
let animatedSwitch = AnimatedSwitch(animation: animation, configuration: configuration)
|
|
21
|
+
animatedSwitch.isOn = isOn?.wrappedValue ?? false
|
|
22
|
+
return animatedSwitch
|
|
23
|
+
}
|
|
24
|
+
.configure { context in
|
|
25
|
+
// We check referential equality of the animation before updating as updating the
|
|
26
|
+
// animation has a side-effect of rebuilding the animation layer, and it would be
|
|
27
|
+
// prohibitive to do so on every state update.
|
|
28
|
+
if animation !== context.view.animationView.animation {
|
|
29
|
+
context.view.animationView.animation = animation
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#if os(macOS)
|
|
33
|
+
// Disable the intrinsic content size constraint on the inner animation view,
|
|
34
|
+
// or the Epoxy `SwiftUIMeasurementContainer` won't size this view correctly.
|
|
35
|
+
context.view.animationView.isVerticalContentSizeConstraintActive = false
|
|
36
|
+
context.view.animationView.isHorizontalContentSizeConstraintActive = false
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
if let isOn = isOn?.wrappedValue, isOn != context.view.isOn {
|
|
40
|
+
context.view.setIsOn(isOn, animated: true)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
.configurations(configurations)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// Returns a copy of this `LottieView` updated to have the given closure applied to its
|
|
47
|
+
/// represented `LottieAnimationView` whenever it is updated via the `updateUIView(…)`
|
|
48
|
+
/// or `updateNSView(…)` method.
|
|
49
|
+
public func configure(_ configure: @escaping (AnimatedSwitch) -> Void) -> Self {
|
|
50
|
+
var copy = self
|
|
51
|
+
copy.configurations.append { context in
|
|
52
|
+
configure(context.view)
|
|
53
|
+
}
|
|
54
|
+
return copy
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Returns a copy of this view with its `LottieConfiguration` updated to the given value.
|
|
58
|
+
public func configuration(_ configuration: LottieConfiguration) -> Self {
|
|
59
|
+
var copy = self
|
|
60
|
+
copy.configuration = configuration
|
|
61
|
+
|
|
62
|
+
copy = copy.configure { view in
|
|
63
|
+
if view.animationView.configuration != configuration {
|
|
64
|
+
view.animationView.configuration = configuration
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return copy
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// Returns a copy of this view with the given `Binding` reflecting the `isOn` state of the switch.
|
|
72
|
+
public func isOn(_ binding: Binding<Bool>) -> Self {
|
|
73
|
+
var copy = self
|
|
74
|
+
copy.isOn = binding
|
|
75
|
+
return copy.configure { view in
|
|
76
|
+
view.stateUpdated = { isOn in
|
|
77
|
+
DispatchQueue.main.async {
|
|
78
|
+
binding.wrappedValue = isOn
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// Returns a copy of this view with the "on" animation configured
|
|
85
|
+
/// to start and end at the given progress values.
|
|
86
|
+
/// Defaults to playing the entire animation forwards (0...1).
|
|
87
|
+
public func onAnimation(
|
|
88
|
+
fromProgress onStartProgress: AnimationProgressTime,
|
|
89
|
+
toProgress onEndProgress: AnimationProgressTime)
|
|
90
|
+
-> Self
|
|
91
|
+
{
|
|
92
|
+
configure { view in
|
|
93
|
+
if onStartProgress != view.onStartProgress || onEndProgress != view.onEndProgress {
|
|
94
|
+
view.setProgressForState(
|
|
95
|
+
fromProgress: onStartProgress,
|
|
96
|
+
toProgress: onEndProgress,
|
|
97
|
+
forOnState: true)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/// Returns a copy of this view with the "on" animation configured
|
|
103
|
+
/// to start and end at the given progress values.
|
|
104
|
+
/// Defaults to playing the entire animation backwards (1...0).
|
|
105
|
+
public func offAnimation(
|
|
106
|
+
fromProgress offStartProgress: AnimationProgressTime,
|
|
107
|
+
toProgress offEndProgress: AnimationProgressTime)
|
|
108
|
+
-> Self
|
|
109
|
+
{
|
|
110
|
+
configure { view in
|
|
111
|
+
if offStartProgress != view.offStartProgress || offEndProgress != view.offEndProgress {
|
|
112
|
+
view.setProgressForState(
|
|
113
|
+
fromProgress: offStartProgress,
|
|
114
|
+
toProgress: offEndProgress,
|
|
115
|
+
forOnState: false)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// Returns a copy of this view using the given value provider for the given keypath.
|
|
121
|
+
/// The value provider must be `Equatable` to avoid unnecessary state updates / re-renders.
|
|
122
|
+
public func valueProvider<ValueProvider: AnyValueProvider & Equatable>(
|
|
123
|
+
_ valueProvider: ValueProvider,
|
|
124
|
+
for keypath: AnimationKeypath)
|
|
125
|
+
-> Self
|
|
126
|
+
{
|
|
127
|
+
configure { view in
|
|
128
|
+
if (view.animationView.valueProviders[keypath] as? ValueProvider) != valueProvider {
|
|
129
|
+
view.animationView.setValueProvider(valueProvider, keypath: keypath)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// MARK: Internal
|
|
135
|
+
|
|
136
|
+
var configurations = [SwiftUIView<AnimatedSwitch, Void>.Configuration]()
|
|
137
|
+
|
|
138
|
+
// MARK: Private
|
|
139
|
+
|
|
140
|
+
private let animation: LottieAnimation?
|
|
141
|
+
private var configuration: LottieConfiguration = .shared
|
|
142
|
+
private var isOn: Binding<Bool>?
|
|
143
|
+
|
|
144
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Created by Cal Stephens on 8/11/23.
|
|
2
|
+
// Copyright © 2023 Airbnb Inc. All rights reserved.
|
|
3
|
+
|
|
4
|
+
#if canImport(UIKit)
|
|
5
|
+
import UIKit
|
|
6
|
+
|
|
7
|
+
/// The control base type for this platform.
|
|
8
|
+
/// - `UIControl` on iOS / tvOS and `NSControl` on macOS.
|
|
9
|
+
public typealias LottieControlType = UIControl
|
|
10
|
+
|
|
11
|
+
/// The `State` type of `LottieControlType`
|
|
12
|
+
/// - `UIControl.State` on iOS / tvOS and `NSControl.StateValue` on macOS.
|
|
13
|
+
public typealias LottieControlState = UIControl.State
|
|
14
|
+
|
|
15
|
+
/// The event type handled by the `LottieControlType` component for this platform.
|
|
16
|
+
/// - `UIControl.Event` on iOS / tvOS and `LottieNSControlEvent` on macOS.
|
|
17
|
+
public typealias LottieControlEvent = UIControl.Event
|
|
18
|
+
|
|
19
|
+
extension LottieControlEvent {
|
|
20
|
+
var id: AnyHashable {
|
|
21
|
+
rawValue
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
#else
|
|
25
|
+
import AppKit
|
|
26
|
+
|
|
27
|
+
/// The control base type for this platform.
|
|
28
|
+
/// - `UIControl` on iOS / tvOS and `NSControl` on macOS.
|
|
29
|
+
public typealias LottieControlType = NSControl
|
|
30
|
+
|
|
31
|
+
/// The `State` type of `LottieControlType`
|
|
32
|
+
/// - `UIControl.State` on iOS / tvOS and `NSControl.StateValue` on macOS.
|
|
33
|
+
public typealias LottieControlState = LottieNSControlState
|
|
34
|
+
|
|
35
|
+
/// AppKit equivalent of `UIControl.State` for `AnimatedControl`
|
|
36
|
+
public enum LottieNSControlState: UInt, RawRepresentable {
|
|
37
|
+
/// The normal, or default, state of a control where the control is enabled but neither selected nor highlighted.
|
|
38
|
+
case normal
|
|
39
|
+
/// The highlighted state of a control.
|
|
40
|
+
case highlighted
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// The event type handled by the `LottieControlType` component for this platform.
|
|
44
|
+
/// - `UIControl.Event` on iOS / tvOS and `LottieNSControlEvent` on macOS.
|
|
45
|
+
public typealias LottieControlEvent = LottieNSControlEvent
|
|
46
|
+
|
|
47
|
+
public struct LottieNSControlEvent: Equatable {
|
|
48
|
+
|
|
49
|
+
// MARK: Lifecycle
|
|
50
|
+
|
|
51
|
+
public init(_ event: NSEvent.EventType, inside: Bool) {
|
|
52
|
+
self.event = event
|
|
53
|
+
self.inside = inside
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// MARK: Public
|
|
57
|
+
|
|
58
|
+
/// macOS equivalent to `UIControl.Event.touchDown`
|
|
59
|
+
public static let touchDown = LottieNSControlEvent(.leftMouseDown, inside: true)
|
|
60
|
+
|
|
61
|
+
/// macOS equivalent to `UIControl.Event.touchUpInside`
|
|
62
|
+
public static let touchUpInside = LottieNSControlEvent(.leftMouseUp, inside: true)
|
|
63
|
+
|
|
64
|
+
/// macOS equivalent to `UIControl.Event.touchUpInside`
|
|
65
|
+
public static let touchUpOutside = LottieNSControlEvent(.leftMouseUp, inside: false)
|
|
66
|
+
|
|
67
|
+
/// The underlying `NSEvent.EventType` of this event, which is roughly equivalent to `UIControl.Event`
|
|
68
|
+
public var event: NSEvent.EventType
|
|
69
|
+
|
|
70
|
+
/// Whether or not the mouse must be inside the control.
|
|
71
|
+
public var inside: Bool
|
|
72
|
+
|
|
73
|
+
// MARK: Internal
|
|
74
|
+
|
|
75
|
+
var id: AnyHashable {
|
|
76
|
+
[AnyHashable(event.rawValue), AnyHashable(inside)]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
#endif
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//
|
|
2
|
+
// DotLottieConfiguration.swift
|
|
3
|
+
// Lottie
|
|
4
|
+
//
|
|
5
|
+
// Created by Evandro Hoffmann on 19/10/22.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
// MARK: - DotLottieConfiguration
|
|
9
|
+
|
|
10
|
+
/// The `DotLottieConfiguration` model holds the presets extracted from DotLottieAnimation
|
|
11
|
+
/// The presets are used as input to setup `LottieAnimationView` before playing the animation.
|
|
12
|
+
public struct DotLottieConfiguration {
|
|
13
|
+
/// id of the animation
|
|
14
|
+
public var id: String
|
|
15
|
+
|
|
16
|
+
/// Animation Image Provider
|
|
17
|
+
public var imageProvider: AnimationImageProvider?
|
|
18
|
+
|
|
19
|
+
/// Loop behaviour of animation
|
|
20
|
+
public var loopMode: LottieLoopMode
|
|
21
|
+
|
|
22
|
+
/// Playback speed of animation
|
|
23
|
+
public var speed: Double
|
|
24
|
+
}
|
|
@@ -25,19 +25,21 @@ public final class DotLottieFile {
|
|
|
25
25
|
try decompress(data: data, to: fileUrl)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
// MARK:
|
|
28
|
+
// MARK: Public
|
|
29
29
|
|
|
30
30
|
/// Definition for a single animation within a `DotLottieFile`
|
|
31
|
-
struct Animation {
|
|
32
|
-
let animation: LottieAnimation
|
|
33
|
-
let configuration: DotLottieConfiguration
|
|
31
|
+
public struct Animation {
|
|
32
|
+
public let animation: LottieAnimation
|
|
33
|
+
public let configuration: DotLottieConfiguration
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/// List of `LottieAnimation` in the file
|
|
37
|
-
private(set) var animations: [Animation] = []
|
|
37
|
+
public private(set) var animations: [Animation] = []
|
|
38
|
+
|
|
39
|
+
// MARK: Internal
|
|
38
40
|
|
|
39
41
|
/// Image provider for animations
|
|
40
|
-
private(set) var imageProvider:
|
|
42
|
+
private(set) var imageProvider: DotLottieImageProvider?
|
|
41
43
|
|
|
42
44
|
/// Animations folder url
|
|
43
45
|
lazy var animationsUrl: URL = fileUrl.appendingPathComponent("\(DotLottieFile.animationsFolderName)")
|
|
@@ -60,6 +62,12 @@ public final class DotLottieFile {
|
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
/// The `LottieAnimation` and `DotLottieConfiguration` for the given animation index in this file
|
|
66
|
+
func animation(at index: Int) -> DotLottieFile.Animation? {
|
|
67
|
+
guard index < animations.count else { return nil }
|
|
68
|
+
return animations[index]
|
|
69
|
+
}
|
|
70
|
+
|
|
63
71
|
// MARK: Private
|
|
64
72
|
|
|
65
73
|
private static let manifestFileName = "manifest.json"
|
|
@@ -136,3 +144,10 @@ extension String {
|
|
|
136
144
|
(self as NSString).deletingPathExtension
|
|
137
145
|
}
|
|
138
146
|
}
|
|
147
|
+
|
|
148
|
+
// MARK: - DotLottieFile + Sendable
|
|
149
|
+
|
|
150
|
+
// Mark `DotLottieFile` as `@unchecked Sendable` to allow it to be used when strict concurrency is enabled.
|
|
151
|
+
// In the future, it may be necessary to make changes to the internal implementation of `DotLottieFile`
|
|
152
|
+
// to make it truly thread-safe.
|
|
153
|
+
extension DotLottieFile: @unchecked Sendable { }
|