lottie-ios 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/.github/workflows/main.yml +117 -11
  2. package/Gemfile +1 -0
  3. package/Gemfile.lock +5 -0
  4. package/Lottie.xcodeproj/project.pbxproj +1542 -194
  5. package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  6. package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (iOS).xcscheme +1 -1
  7. package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (macOS).xcscheme +1 -1
  8. package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (tvOS).xcscheme +4 -5
  9. package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (visionOS).xcscheme +66 -0
  10. package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +18 -0
  11. package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +2 -11
  12. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  13. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +346 -102
  14. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +16 -5
  15. package/Package.resolved +2 -2
  16. package/Package.swift +16 -9
  17. package/README.md +2 -2
  18. package/Rakefile +122 -25
  19. package/Sources/Private/CoreAnimation/Animations/DropShadowAnimation.swift +160 -0
  20. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +83 -10
  21. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +85 -79
  22. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +7 -7
  23. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +67 -6
  24. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +2 -2
  25. package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +9 -0
  26. package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +1 -0
  27. package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +1 -1
  28. package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +2 -0
  29. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +11 -13
  30. package/Sources/Private/CoreAnimation/Layers/SolidLayer.swift +20 -5
  31. package/Sources/Private/CoreAnimation/Layers/TextLayer.swift +13 -3
  32. package/Sources/Private/CoreAnimation/ValueProviderStore.swift +6 -4
  33. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/Collection+Diff.swift +263 -0
  34. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/Diffable.swift +18 -0
  35. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/DiffableSection.swift +16 -0
  36. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/IndexChangeset.swift +187 -0
  37. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/SectionedChangeset.swift +32 -0
  38. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Logging/EpoxyLogger.swift +99 -0
  39. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/CallbackContextEpoxyModeled.swift +8 -0
  40. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelArrayBuilder.swift +48 -0
  41. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelProperty.swift +158 -0
  42. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelStorage.swift +88 -0
  43. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModeled.swift +54 -0
  44. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Internal/AnyEpoxyModelProperty.swift +29 -0
  45. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Internal/ClassReference.swift +39 -0
  46. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/AnimatedProviding.swift +10 -0
  47. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DataIDProviding.swift +57 -0
  48. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidDisplayProviding.swift +41 -0
  49. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidEndDisplayingProviding.swift +41 -0
  50. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidSelectProviding.swift +36 -0
  51. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ErasedContentProviding.swift +49 -0
  52. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/MakeViewProviding.swift +60 -0
  53. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/SetBehaviorsProviding.swift +38 -0
  54. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/SetContentProviding.swift +38 -0
  55. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/StyleIDProviding.swift +37 -0
  56. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/TraitCollectionProviding.swift +14 -0
  57. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ViewDifferentiatorProviding.swift +34 -0
  58. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ViewProviding.swift +13 -0
  59. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/WillDisplayProviding.swift +41 -0
  60. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/ViewEpoxyModeled.swift +10 -0
  61. package/Sources/Private/EmbeddedLibraries/EpoxyCore/README.md +31 -0
  62. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingController.swift +46 -0
  63. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingView.swift +391 -0
  64. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIIntrinsicContentSizeInvalidator.swift +44 -0
  65. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUILayoutMargins.swift +51 -0
  66. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxyableView+SwiftUIView.swift +172 -0
  67. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/MeasuringViewRepresentable.swift +128 -0
  68. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift +452 -0
  69. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/SwiftUIView.swift +148 -0
  70. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIView+SwiftUIView.swift +40 -0
  71. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIViewConfiguringSwiftUIView.swift +43 -0
  72. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/BehaviorsConfigurableView.swift +45 -0
  73. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ContentConfigurableView.swift +36 -0
  74. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/EpoxyableView.swift +5 -0
  75. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/StyledView.swift +42 -0
  76. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ViewType.swift +51 -0
  77. package/Sources/Private/EmbeddedLibraries/README.md +27 -0
  78. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+BackingConfiguration.swift +4 -4
  79. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+MemoryFile.swift +2 -2
  80. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Writing.swift +4 -4
  81. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive.swift +8 -7
  82. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+Compression.swift +5 -5
  83. package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/FileManager+ZIP.swift +4 -4
  84. package/Sources/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift +6 -0
  85. package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +3 -1
  86. package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +18 -5
  87. package/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift +31 -3
  88. package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +33 -8
  89. package/Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift +8 -1
  90. package/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift +13 -4
  91. package/Sources/Private/MainThread/LayerContainers/Utility/LayerFontProvider.swift +2 -2
  92. package/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift +1 -0
  93. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTextProvider.swift +4 -4
  94. package/Sources/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift +1 -1
  95. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +3 -1
  96. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +2 -1
  97. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift +2 -1
  98. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +1 -1
  99. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +2 -2
  100. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +1 -1
  101. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +1 -1
  102. package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +6 -2
  103. package/Sources/Private/Model/Assets/Asset.swift +8 -0
  104. package/Sources/Private/Model/Assets/AssetLibrary.swift +2 -2
  105. package/Sources/Private/Model/Assets/ImageAsset.swift +3 -3
  106. package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +16 -2
  107. package/Sources/Private/Model/DotLottie/DotLottieImageProvider.swift +20 -7
  108. package/Sources/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift +26 -0
  109. package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +8 -5
  110. package/Sources/Private/Model/LayerEffects/DropShadowEffect.swift +45 -0
  111. package/Sources/Private/Model/LayerEffects/EffectValues/ColorEffectValue.swift +38 -0
  112. package/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift +98 -0
  113. package/Sources/Private/Model/LayerEffects/EffectValues/Vector1DEffectValue.swift +38 -0
  114. package/Sources/Private/Model/LayerEffects/LayerEffect.swift +103 -0
  115. package/Sources/Private/Model/LayerStyles/DropShadowStyle.swift +72 -0
  116. package/Sources/Private/Model/LayerStyles/LayerStyle.swift +85 -0
  117. package/Sources/Private/Model/Layers/LayerModel.swift +27 -0
  118. package/Sources/Private/Model/Objects/Marker.swift +1 -1
  119. package/Sources/Private/Model/Objects/Transform.swift +1 -2
  120. package/Sources/Private/Model/ShapeItems/GradientFill.swift +1 -1
  121. package/Sources/Private/Model/ShapeItems/GradientStroke.swift +2 -2
  122. package/Sources/Private/Model/ShapeItems/Merge.swift +1 -1
  123. package/Sources/Private/Model/ShapeItems/ShapeItem.swift +31 -26
  124. package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +0 -9
  125. package/Sources/Private/Model/ShapeItems/Star.swift +1 -1
  126. package/Sources/Private/Model/Text/Font.swift +2 -2
  127. package/Sources/Private/Model/Text/Glyph.swift +1 -1
  128. package/Sources/Private/RootAnimationLayer.swift +2 -2
  129. package/Sources/Private/Utility/Debugging/LayerDebugging.swift +3 -1
  130. package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +32 -2
  131. package/Sources/Private/Utility/Helpers/AnimationContext.swift +4 -2
  132. package/Sources/Private/Utility/Helpers/AnyEquatable.swift +24 -0
  133. package/Sources/Private/Utility/Helpers/Binding+Map.swift +18 -0
  134. package/Sources/Private/Utility/Helpers/View+ValueChanged.swift +20 -0
  135. package/Sources/Private/Utility/LottieAnimationSource.swift +41 -0
  136. package/Sources/Private/Utility/Primitives/BezierPath.swift +2 -2
  137. package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +2 -2
  138. package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +1 -1
  139. package/Sources/Public/Animation/LottieAnimation.swift +21 -2
  140. package/Sources/Public/Animation/LottieAnimationLayer.swift +1464 -0
  141. package/Sources/Public/Animation/LottieAnimationView.swift +258 -735
  142. package/Sources/Public/Animation/LottiePlaybackMode.swift +117 -0
  143. package/Sources/Public/Animation/LottieView.swift +462 -0
  144. package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +2 -1
  145. package/Sources/Public/AnimationCache/DefaultAnimationCache.swift +5 -6
  146. package/Sources/Public/Configuration/DecodingStrategy.swift +15 -0
  147. package/Sources/Public/Configuration/LottieConfiguration.swift +47 -0
  148. package/Sources/Public/Configuration/ReducedMotionOption.swift +114 -0
  149. package/Sources/Public/{LottieConfiguration.swift → Configuration/RenderingEngineOption.swift} +2 -57
  150. package/Sources/Public/{iOS → Controls}/AnimatedButton.swift +56 -13
  151. package/Sources/Public/{iOS → Controls}/AnimatedControl.swift +80 -8
  152. package/Sources/Public/{iOS → Controls}/AnimatedSwitch.swift +71 -31
  153. package/Sources/Public/Controls/LottieButton.swift +122 -0
  154. package/Sources/Public/Controls/LottieSwitch.swift +144 -0
  155. package/Sources/Public/Controls/LottieViewType.swift +79 -0
  156. package/Sources/Public/DotLottie/DotLottieConfiguration.swift +24 -0
  157. package/Sources/Public/DotLottie/DotLottieFile.swift +21 -6
  158. package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +79 -0
  159. package/Sources/Public/DynamicProperties/AnimationKeypath.swift +11 -1
  160. package/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +14 -0
  161. package/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +13 -0
  162. package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +22 -5
  163. package/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +14 -0
  164. package/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +13 -0
  165. package/Sources/Public/FontProvider/AnimationFontProvider.swift +8 -0
  166. package/Sources/Public/ImageProvider/AnimationImageProvider.swift +24 -0
  167. package/Sources/Public/Keyframes/Keyframe.swift +6 -0
  168. package/Sources/Public/Primitives/Vectors.swift +2 -2
  169. package/Sources/Public/TextProvider/AnimationTextProvider.swift +79 -6
  170. package/Sources/Public/iOS/AnimationSubview.swift +1 -1
  171. package/Sources/Public/iOS/BundleImageProvider.swift +16 -2
  172. package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +2 -2
  173. package/Sources/Public/iOS/FilepathImageProvider.swift +22 -3
  174. package/Sources/Public/iOS/LottieAnimationViewBase.swift +7 -1
  175. package/Sources/Public/macOS/BundleImageProvider.macOS.swift +15 -1
  176. package/Sources/Public/macOS/FilepathImageProvider.macOS.swift +21 -2
  177. package/lottie-ios.podspec +2 -1
  178. package/package.json +1 -1
  179. package/Sources/Private/Model/DotLottie/DotLottieConfiguration.swift +0 -15
  180. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Helpers.swift +0 -0
  181. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Progress.swift +0 -0
  182. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Reading.swift +0 -0
  183. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+ReadingDeprecated.swift +0 -0
  184. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+WritingDeprecated.swift +0 -0
  185. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+ZIP64.swift +0 -0
  186. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+CompressionDeprecated.swift +0 -0
  187. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+Serialization.swift +0 -0
  188. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry+Serialization.swift +0 -0
  189. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry+ZIP64.swift +0 -0
  190. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry.swift +0 -0
  191. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/README.md +0 -0
  192. /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/URL+ZIP.swift +0 -0
@@ -0,0 +1,47 @@
1
+ // Created by Cal Stephens on 12/13/21.
2
+ // Copyright © 2021 Airbnb Inc. All rights reserved.
3
+
4
+ import QuartzCore
5
+
6
+ /// Global configuration options for Lottie animations
7
+ public struct LottieConfiguration: Hashable {
8
+
9
+ // MARK: Lifecycle
10
+
11
+ public init(
12
+ renderingEngine: RenderingEngineOption = .automatic,
13
+ decodingStrategy: DecodingStrategy = .dictionaryBased,
14
+ colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB(),
15
+ reducedMotionOption: ReducedMotionOption = .systemReducedMotionToggle)
16
+ {
17
+ self.renderingEngine = renderingEngine
18
+ self.decodingStrategy = decodingStrategy
19
+ self.colorSpace = colorSpace
20
+ self.reducedMotionOption = reducedMotionOption
21
+ }
22
+
23
+ // MARK: Public
24
+
25
+ /// The global configuration of Lottie,
26
+ /// which applies to all `LottieAnimationView`s by default.
27
+ public static var shared = LottieConfiguration()
28
+
29
+ /// The rendering engine implementation to use when displaying an animation
30
+ /// - Defaults to `RenderingEngineOption.automatic`, which uses the
31
+ /// Core Animation rendering engine for supported animations, and
32
+ /// falls back to using the Main Thread rendering engine for
33
+ /// animations that use features not supported by the Core Animation engine.
34
+ public var renderingEngine: RenderingEngineOption
35
+
36
+ /// The decoding implementation to use when parsing an animation JSON file
37
+ public var decodingStrategy: DecodingStrategy
38
+
39
+ /// Options for controlling animation behavior in response to user / system "reduced motion" configuration.
40
+ /// - Defaults to `ReducedMotionOption.systemReducedMotionToggle`, which returns `.reducedMotion`
41
+ /// when the system `UIAccessibility.isReduceMotionEnabled` option is `true`.
42
+ public var reducedMotionOption: ReducedMotionOption
43
+
44
+ /// The color space to be used for rendering
45
+ /// - Defaults to `CGColorSpaceCreateDeviceRGB()`
46
+ public var colorSpace: CGColorSpace
47
+ }
@@ -0,0 +1,114 @@
1
+ // Created by Cal Stephens on 7/14/23.
2
+ // Copyright © 2023 Airbnb Inc. All rights reserved.
3
+
4
+ #if canImport(UIKit)
5
+ import UIKit
6
+ #elseif canImport(AppKit)
7
+ import AppKit
8
+ #endif
9
+
10
+ // MARK: - ReducedMotionOption
11
+
12
+ /// Options for controlling animation behavior in response to user / system "reduced motion" configuration
13
+ public enum ReducedMotionOption {
14
+ /// Always use the specific given `ReducedMotionMode` value.
15
+ case specific(ReducedMotionMode)
16
+
17
+ /// Dynamically check the given `ReducedMotionOptionProvider` each time an animation begins.
18
+ /// - Includes a Hashable `dataID` to support `ReducedMotionOption`'s `Hashable` requirement,
19
+ /// which is required due to `LottieConfiguration`'s existing `Hashable` requirement.
20
+ case dynamic(ReducedMotionOptionProvider, dataID: AnyHashable)
21
+ }
22
+
23
+ extension ReducedMotionOption {
24
+ /// The standard behavior where Lottie animations play normally with no overrides.
25
+ /// By default this mode is used when the system "reduced motion" option is disabled.
26
+ public static var standardMotion: ReducedMotionOption { .specific(.standardMotion) }
27
+
28
+ /// Lottie animations with a "reduced motion" marker will play that marker instead of any other animations.
29
+ /// By default this mode is used when the system "reduced motion" option is enabled.
30
+ /// - Valid marker names include "reduced motion", "reducedMotion", "reduced_motion" (case insensitive).
31
+ public static var reducedMotion: ReducedMotionOption { .specific(.reducedMotion) }
32
+
33
+ /// A `ReducedMotionOptionProvider` that returns `.reducedMotion` when
34
+ /// the system `UIAccessibility.isReduceMotionEnabled` option is `true`.
35
+ /// This is the default option of `LottieConfiguration`.
36
+ public static var systemReducedMotionToggle: ReducedMotionOption {
37
+ .dynamic(SystemReducedMotionOptionProvider(), dataID: ObjectIdentifier(SystemReducedMotionOptionProvider.self))
38
+ }
39
+ }
40
+
41
+ extension ReducedMotionOption {
42
+ /// The current `ReducedMotionMode` based on the currently selected option.
43
+ public var currentReducedMotionMode: ReducedMotionMode {
44
+ switch self {
45
+ case .specific(let specificMode):
46
+ return specificMode
47
+ case .dynamic(let optionProvider, _):
48
+ return optionProvider.currentReducedMotionMode
49
+ }
50
+ }
51
+ }
52
+
53
+ // MARK: Hashable
54
+
55
+ extension ReducedMotionOption: Hashable {
56
+ public static func ==(_ lhs: ReducedMotionOption, _ rhs: ReducedMotionOption) -> Bool {
57
+ switch (lhs, rhs) {
58
+ case (.specific(let lhsMode), .specific(let rhsMode)):
59
+ return lhsMode == rhsMode
60
+ case (.dynamic(_, let lhsDataID), .dynamic(_, dataID: let rhsDataID)):
61
+ return lhsDataID == rhsDataID
62
+ case (.dynamic, .specific), (.specific, .dynamic):
63
+ return false
64
+ }
65
+ }
66
+
67
+ public func hash(into hasher: inout Hasher) {
68
+ switch self {
69
+ case .specific(let mode):
70
+ hasher.combine(mode)
71
+ case .dynamic(_, let dataID):
72
+ hasher.combine(dataID)
73
+ }
74
+ }
75
+ }
76
+
77
+ // MARK: - ReducedMotionMode
78
+
79
+ public enum ReducedMotionMode: Hashable {
80
+ /// The default behavior where Lottie animations play normally with no overrides
81
+ /// By default this mode is used when the system "reduced motion" option is disabled.
82
+ case standardMotion
83
+
84
+ /// Lottie animations with a "reduced motion" marker will play that marker instead of any other animations.
85
+ /// By default this mode is used when the system "reduced motion" option is enabled.
86
+ case reducedMotion
87
+ }
88
+
89
+ // MARK: - ReducedMotionOptionProvider
90
+
91
+ /// A type that returns a dynamic `ReducedMotionMode` which is checked when playing a Lottie animation.
92
+ public protocol ReducedMotionOptionProvider {
93
+ var currentReducedMotionMode: ReducedMotionMode { get }
94
+ }
95
+
96
+ // MARK: - SystemReducedMotionOptionProvider
97
+
98
+ /// A `ReducedMotionOptionProvider` that returns `.reducedMotion` when
99
+ /// the system `UIAccessibility.isReduceMotionEnabled` option is `true`.
100
+ public struct SystemReducedMotionOptionProvider: ReducedMotionOptionProvider {
101
+ public init() { }
102
+
103
+ public var currentReducedMotionMode: ReducedMotionMode {
104
+ #if canImport(UIKit)
105
+ if UIAccessibility.isReduceMotionEnabled {
106
+ return .reducedMotion
107
+ } else {
108
+ return .standardMotion
109
+ }
110
+ #else
111
+ return .standardMotion
112
+ #endif
113
+ }
114
+ }
@@ -1,45 +1,5 @@
1
- // Created by Cal Stephens on 12/13/21.
2
- // Copyright © 2021 Airbnb Inc. All rights reserved.
3
-
4
- import QuartzCore
5
-
6
- // MARK: - LottieConfiguration
7
-
8
- /// Global configuration options for Lottie animations
9
- public struct LottieConfiguration: Hashable {
10
-
11
- // MARK: Lifecycle
12
-
13
- public init(
14
- renderingEngine: RenderingEngineOption = .automatic,
15
- decodingStrategy: DecodingStrategy = .dictionaryBased,
16
- colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB())
17
- {
18
- self.renderingEngine = renderingEngine
19
- self.decodingStrategy = decodingStrategy
20
- self.colorSpace = colorSpace
21
- }
22
-
23
- // MARK: Public
24
-
25
- /// The global configuration of Lottie,
26
- /// which applies to all `LottieAnimationView`s by default.
27
- public static var shared = LottieConfiguration()
28
-
29
- /// The rendering engine implementation to use when displaying an animation
30
- /// - Defaults to `RenderingEngineOption.automatic`, which uses the
31
- /// Core Animation rendering engine for supported animations, and
32
- /// falls back to using the Main Thread rendering engine for
33
- /// animations that use features not supported by the Core Animation engine.
34
- public var renderingEngine: RenderingEngineOption
35
-
36
- /// The decoding implementation to use when parsing an animation JSON file
37
- public var decodingStrategy: DecodingStrategy
38
-
39
- /// The color space to be used for rendering
40
- /// - Defaults to `CGColorSpaceCreateDeviceRGB()`
41
- public var colorSpace: CGColorSpace
42
- }
1
+ // Created by Cal Stephens on 7/14/23.
2
+ // Copyright © 2023 Airbnb Inc. All rights reserved.
43
3
 
44
4
  // MARK: - RenderingEngineOption
45
5
 
@@ -151,18 +111,3 @@ extension RenderingEngine: RawRepresentable, CustomStringConvertible {
151
111
  rawValue
152
112
  }
153
113
  }
154
-
155
- // MARK: - DecodingStrategy
156
-
157
- /// How animation files should be decoded
158
- public enum DecodingStrategy: Hashable {
159
- /// Use Codable. This is was the default strategy introduced on Lottie 3, but should be rarely
160
- /// used as it's slower than `dictionaryBased`. Kept here for any possible compatibility issues
161
- /// that may come up, but consider it soft-deprecated.
162
- case legacyCodable
163
-
164
- /// Manually deserialize a dictionary into an Animation.
165
- /// This should be at least 2-3x faster than using Codable and due to that
166
- /// it's the default as of Lottie 4.x.
167
- case dictionaryBased
168
- }
@@ -6,38 +6,61 @@
6
6
  //
7
7
 
8
8
  import Foundation
9
- #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
9
+
10
+ #if canImport(UIKit)
10
11
  import UIKit
12
+ #elseif canImport(AppKit)
13
+ import AppKit
14
+ #endif
15
+
16
+ // MARK: - AnimatedButton
17
+
11
18
  /// An interactive button that plays an animation when pressed.
12
19
  open class AnimatedButton: AnimatedControl {
13
20
 
14
21
  // MARK: Lifecycle
15
22
 
16
23
  public override init(
17
- animation: LottieAnimation,
24
+ animation: LottieAnimation?,
18
25
  configuration: LottieConfiguration = .shared)
19
26
  {
20
27
  super.init(animation: animation, configuration: configuration)
28
+
29
+ #if canImport(UIKit)
21
30
  isAccessibilityElement = true
31
+ #elseif canImport(AppKit)
32
+ setAccessibilityElement(true)
33
+ #endif
22
34
  }
23
35
 
24
36
  public override init() {
25
37
  super.init()
38
+
39
+ #if canImport(UIKit)
26
40
  isAccessibilityElement = true
41
+ #elseif canImport(AppKit)
42
+ setAccessibilityElement(true)
43
+ #endif
27
44
  }
28
45
 
29
46
  required public init?(coder aDecoder: NSCoder) {
30
47
  super.init(coder: aDecoder)
48
+
49
+ #if canImport(UIKit)
31
50
  isAccessibilityElement = true
51
+ #elseif canImport(AppKit)
52
+ setAccessibilityElement(true)
53
+ #endif
32
54
  }
33
55
 
34
56
  // MARK: Open
35
57
 
58
+ #if canImport(UIKit)
36
59
  open override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
37
60
  let _ = super.beginTracking(touch, with: event)
38
61
  let touchEvent = UIControl.Event.touchDown
39
- if let playrange = rangesForEvents[touchEvent.rawValue] {
40
- animationView.play(fromProgress: playrange.from, toProgress: playrange.to, loopMode: LottieLoopMode.playOnce)
62
+ if let playRange = rangesForEvents[touchEvent.id] {
63
+ animationView.play(fromProgress: playRange.from, toProgress: playRange.to, loopMode: .playOnce)
41
64
  }
42
65
  return true
43
66
  }
@@ -47,40 +70,60 @@ open class AnimatedButton: AnimatedControl {
47
70
  let touchEvent: UIControl.Event
48
71
  if let touch = touch, bounds.contains(touch.location(in: self)) {
49
72
  touchEvent = UIControl.Event.touchUpInside
73
+ performAction?()
50
74
  } else {
51
75
  touchEvent = UIControl.Event.touchUpOutside
52
76
  }
53
77
 
54
- if let playrange = rangesForEvents[touchEvent.rawValue] {
55
- animationView.play(fromProgress: playrange.from, toProgress: playrange.to, loopMode: LottieLoopMode.playOnce)
78
+ if let playRange = rangesForEvents[touchEvent.id] {
79
+ animationView.play(fromProgress: playRange.from, toProgress: playRange.to, loopMode: .playOnce)
56
80
  }
57
81
  }
58
82
 
83
+ #elseif canImport(AppKit)
84
+ open override func handle(_ event: LottieNSControlEvent) {
85
+ super.handle(event)
86
+
87
+ if let playRange = rangesForEvents[event.id] {
88
+ animationView.play(fromProgress: playRange.from, toProgress: playRange.to, loopMode: .playOnce)
89
+ }
90
+
91
+ if event == .touchUpInside {
92
+ performAction?()
93
+ }
94
+ }
95
+ #endif
96
+
59
97
  // MARK: Public
60
98
 
99
+ /// A closure that is called when the button is pressed / clicked
100
+ public var performAction: (() -> Void)?
101
+
102
+ #if canImport(UIKit)
61
103
  public override var accessibilityTraits: UIAccessibilityTraits {
62
104
  set { super.accessibilityTraits = newValue }
63
105
  get { super.accessibilityTraits.union(.button) }
64
106
  }
107
+ #endif
65
108
 
66
109
  /// Sets the play range for the given UIControlEvent.
67
- public func setPlayRange(fromProgress: AnimationProgressTime, toProgress: AnimationProgressTime, event: UIControl.Event) {
68
- rangesForEvents[event.rawValue] = (from: fromProgress, to: toProgress)
110
+ public func setPlayRange(fromProgress: AnimationProgressTime, toProgress: AnimationProgressTime, event: LottieControlEvent) {
111
+ rangesForEvents[event.id] = (from: fromProgress, to: toProgress)
69
112
  }
70
113
 
71
114
  /// Sets the play range for the given UIControlEvent.
72
- public func setPlayRange(fromMarker fromName: String, toMarker toName: String, event: UIControl.Event) {
115
+ public func setPlayRange(fromMarker fromName: String, toMarker toName: String, event: LottieControlEvent) {
73
116
  if
74
117
  let start = animationView.progressTime(forMarker: fromName),
75
118
  let end = animationView.progressTime(forMarker: toName)
76
119
  {
77
- rangesForEvents[event.rawValue] = (from: start, to: end)
120
+ rangesForEvents[event.id] = (from: start, to: end)
78
121
  }
79
122
  }
80
123
 
81
124
  // MARK: Private
82
125
 
83
- private var rangesForEvents: [UInt : (from: CGFloat, to: CGFloat)] =
84
- [UIControl.Event.touchUpInside.rawValue : (from: 0, to: 1)]
126
+ private var rangesForEvents: [AnyHashable : (from: CGFloat, to: CGFloat)] = {
127
+ [LottieControlEvent.touchUpInside.id: (from: 0, to: 1)]
128
+ }()
85
129
  }
86
- #endif
@@ -5,9 +5,15 @@
5
5
  // Created by Brandon Withrow on 2/4/19.
6
6
  //
7
7
 
8
- import Foundation
9
- #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
8
+ #if canImport(UIKit)
10
9
  import UIKit
10
+ #elseif canImport(AppKit)
11
+ import AppKit
12
+ #endif
13
+
14
+ import Foundation
15
+
16
+ // MARK: - AnimatedControl
11
17
 
12
18
  /// Lottie comes prepacked with a two Animated Controls, `AnimatedSwitch` and
13
19
  /// `AnimatedButton`. Both of these controls are built on top of `AnimatedControl`
@@ -24,21 +30,21 @@ import UIKit
24
30
  /// of its layers.
25
31
  ///
26
32
  /// NOTE: Do not initialize directly. This is intended to be subclassed.
27
- open class AnimatedControl: UIControl {
33
+ open class AnimatedControl: LottieControlType {
28
34
 
29
35
  // MARK: Lifecycle
30
36
 
31
37
  // MARK: Initializers
32
38
 
33
39
  public init(
34
- animation: LottieAnimation,
40
+ animation: LottieAnimation?,
35
41
  configuration: LottieConfiguration = .shared)
36
42
  {
37
43
  animationView = LottieAnimationView(
38
44
  animation: animation,
39
45
  configuration: configuration)
40
46
 
41
- super.init(frame: animation.bounds)
47
+ super.init(frame: animation?.bounds ?? .zero)
42
48
  commonInit()
43
49
  }
44
50
 
@@ -64,11 +70,13 @@ open class AnimatedControl: UIControl {
64
70
  }
65
71
  }
66
72
 
73
+ #if canImport(UIKit)
67
74
  open override var isSelected: Bool {
68
75
  didSet {
69
76
  updateForState()
70
77
  }
71
78
  }
79
+ #endif
72
80
 
73
81
  open override var isHighlighted: Bool {
74
82
  didSet {
@@ -80,6 +88,7 @@ open class AnimatedControl: UIControl {
80
88
  animationView.intrinsicContentSize
81
89
  }
82
90
 
91
+ #if canImport(UIKit)
83
92
  open override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
84
93
  updateForState()
85
94
  return super.beginTracking(touch, with: event)
@@ -100,6 +109,50 @@ open class AnimatedControl: UIControl {
100
109
  super.cancelTracking(with: event)
101
110
  }
102
111
 
112
+ #elseif canImport(AppKit)
113
+ open override func mouseDown(with mouseDownEvent: NSEvent) {
114
+ guard let window = window else { return }
115
+
116
+ currentState = .highlighted
117
+ updateForState()
118
+ handle(LottieControlEvent(mouseDownEvent.type, inside: eventIsInside(mouseDownEvent)))
119
+
120
+ // AppKit mouse-tracking loop from:
121
+ // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/HandlingMouseEvents.html#//apple_ref/doc/uid/10000060i-CH6-SW4
122
+ var keepOn = true
123
+ while
124
+ keepOn,
125
+ let event = window.nextEvent(
126
+ matching: .any,
127
+ until: .distantFuture,
128
+ inMode: .eventTracking,
129
+ dequeue: true)
130
+ {
131
+ if event.type == .leftMouseUp {
132
+ keepOn = false
133
+ }
134
+
135
+ let isInside = eventIsInside(event)
136
+ handle(LottieControlEvent(event.type, inside: isInside))
137
+
138
+ let expectedState = (isInside && keepOn) ? LottieNSControlState.highlighted : .normal
139
+ if currentState != expectedState {
140
+ currentState = expectedState
141
+ updateForState()
142
+ }
143
+ }
144
+ }
145
+
146
+ func handle(_: LottieNSControlEvent) {
147
+ // To be overridden in subclasses
148
+ }
149
+
150
+ private func eventIsInside(_ event: NSEvent) -> Bool {
151
+ let mouseLocation = convert(event.locationInWindow, from: nil)
152
+ return isMousePoint(mouseLocation, in: bounds)
153
+ }
154
+ #endif
155
+
103
156
  open func animationDidSet() { }
104
157
 
105
158
  // MARK: Public
@@ -112,7 +165,11 @@ open class AnimatedControl: UIControl {
112
165
  didSet {
113
166
  animationView.animation = animation
114
167
  animationView.bounds = animation?.bounds ?? .zero
168
+ #if canImport(UIKit)
115
169
  setNeedsLayout()
170
+ #elseif canImport(AppKit)
171
+ needsLayout = true
172
+ #endif
116
173
  updateForState()
117
174
  animationDidSet()
118
175
  }
@@ -125,7 +182,7 @@ open class AnimatedControl: UIControl {
125
182
  }
126
183
 
127
184
  /// Sets which Animation Layer should be visible for the given state.
128
- public func setLayer(named: String, forState: UIControl.State) {
185
+ public func setLayer(named: String, forState: LottieControlState) {
129
186
  stateMap[forState.rawValue] = named
130
187
  updateForState()
131
188
  }
@@ -139,10 +196,19 @@ open class AnimatedControl: UIControl {
139
196
 
140
197
  var stateMap: [UInt: String] = [:]
141
198
 
199
+ #if canImport(UIKit)
200
+ var currentState: LottieControlState {
201
+ state
202
+ }
203
+
204
+ #elseif canImport(AppKit)
205
+ var currentState = LottieControlState.normal
206
+ #endif
207
+
142
208
  func updateForState() {
143
209
  guard let animationLayer = animationView.animationLayer else { return }
144
210
  if
145
- let layerName = stateMap[state.rawValue],
211
+ let layerName = stateMap[currentState.rawValue],
146
212
  let stateLayer = animationLayer.layer(for: AnimationKeypath(keypath: layerName))
147
213
  {
148
214
  for layer in animationLayer._animationLayers {
@@ -159,17 +225,23 @@ open class AnimatedControl: UIControl {
159
225
  // MARK: Private
160
226
 
161
227
  private func commonInit() {
228
+ #if canImport(UIKit)
162
229
  animationView.clipsToBounds = false
163
230
  clipsToBounds = true
231
+ #endif
232
+
164
233
  animationView.translatesAutoresizingMaskIntoConstraints = false
165
234
  animationView.backgroundBehavior = .forceFinish
166
235
  addSubview(animationView)
167
236
  animationView.contentMode = .scaleAspectFit
237
+
238
+ #if canImport(UIKit)
168
239
  animationView.isUserInteractionEnabled = false
240
+ #endif
241
+
169
242
  animationView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
170
243
  animationView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
171
244
  animationView.topAnchor.constraint(equalTo: topAnchor).isActive = true
172
245
  animationView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
173
246
  }
174
247
  }
175
- #endif