lottie-ios 4.4.1 → 4.4.2

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 (35) hide show
  1. package/.github/workflows/main.yml +5 -0
  2. package/Lottie.xcodeproj/project.pbxproj +40 -44
  3. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  4. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +18 -0
  5. package/Package.swift +1 -1
  6. package/README.md +1 -1
  7. package/Rakefile +5 -12
  8. package/Sources/Private/EmbeddedLibraries/EpoxyCore/README.md +3 -4
  9. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIIntrinsicContentSizeInvalidator.swift +0 -1
  10. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUILayoutMargins.swift +0 -4
  11. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxyableView+SwiftUIView.swift +0 -4
  12. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/MeasuringViewRepresentable.swift +0 -4
  13. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift +0 -1
  14. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/SwiftUIView.swift +0 -4
  15. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIView+SwiftUIView.swift +0 -1
  16. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIViewConfiguringSwiftUIView.swift +0 -2
  17. package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ViewType.swift +0 -4
  18. package/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift +0 -1
  19. package/Sources/Private/Model/DotLottie/DotLottieUtils.swift +3 -5
  20. package/Sources/Private/Utility/Extensions/DataExtension.swift +5 -8
  21. package/Sources/Private/Utility/Extensions/MathKit.swift +2 -2
  22. package/Sources/Private/Utility/Helpers/Binding+Map.swift +0 -1
  23. package/Sources/Private/Utility/Helpers/View+ValueChanged.swift +15 -2
  24. package/Sources/Public/Animation/LottieAnimationHelpers.swift +0 -1
  25. package/Sources/Public/Animation/LottieView.swift +11 -8
  26. package/Sources/Public/Controls/LottieButton.swift +0 -1
  27. package/Sources/Public/Controls/LottieSwitch.swift +0 -1
  28. package/Sources/Public/Controls/LottieViewType.swift +1 -1
  29. package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +0 -5
  30. package/Sources/Public/iOS/LottieAnimationViewBase.swift +1 -5
  31. package/Version.xcconfig +6 -0
  32. package/lottie-ios.podspec +5 -4
  33. package/package.json +1 -1
  34. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingController.swift +0 -46
  35. package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingView.swift +0 -389
@@ -1,389 +0,0 @@
1
- // Created by eric_horacek on 9/16/21.
2
- // Copyright © 2021 Airbnb Inc. All rights reserved.
3
-
4
- #if canImport(Combine) && canImport(SwiftUI) && !os(macOS)
5
- import Combine
6
- import SwiftUI
7
-
8
- // MARK: - SwiftUIHostingViewReuseBehavior
9
-
10
- /// The reuse behavior of an `EpoxySwiftUIHostingView`.
11
- enum SwiftUIHostingViewReuseBehavior: Hashable {
12
- /// Instances of a `EpoxySwiftUIHostingView` with `RootView`s of same type can be reused within
13
- /// the Epoxy container.
14
- ///
15
- /// This is the default reuse behavior.
16
- case reusable
17
- /// Instances of a `EpoxySwiftUIHostingView` with `RootView`s of same type can only reused within
18
- /// the Epoxy container when they have identical `reuseID`s.
19
- case unique(reuseID: AnyHashable)
20
- }
21
-
22
- // MARK: - CallbackContextEpoxyModeled
23
-
24
- @available(iOS 13.0, tvOS 13.0, macOS 10.15, *)
25
- extension CallbackContextEpoxyModeled
26
- where
27
- Self: WillDisplayProviding & DidEndDisplayingProviding,
28
- CallbackContext: ViewProviding & AnimatedProviding
29
- {
30
- /// Updates the appearance state of a `EpoxySwiftUIHostingView` in coordination with the
31
- /// `willDisplay` and `didEndDisplaying` callbacks of this `EpoxyableModel`.
32
- ///
33
- /// - Note: You should only need to call then from the implementation of a concrete
34
- /// `EpoxyableModel` convenience vendor method, e.g. `SwiftUI.View.itemModel(…)`.
35
- func linkDisplayLifecycle<RootView: View>() -> Self
36
- where
37
- CallbackContext.View == EpoxySwiftUIHostingView<RootView>
38
- {
39
- willDisplay { context in
40
- context.view.handleWillDisplay(animated: context.animated)
41
- }
42
- .didEndDisplaying { context in
43
- context.view.handleDidEndDisplaying(animated: context.animated)
44
- }
45
- }
46
- }
47
-
48
- // MARK: - EpoxySwiftUIHostingView
49
-
50
- /// A `UIView` that hosts a SwiftUI view within an Epoxy container, e.g. an Epoxy `CollectionView`.
51
- ///
52
- /// Wraps an `EpoxySwiftUIHostingController` and adds it as a child view controller to the next
53
- /// ancestor view controller in the hierarchy.
54
- ///
55
- /// There's a private API that accomplishes this same behavior without needing a `UIViewController`:
56
- /// `_UIHostingView`, but we can't safely use it as 1) the behavior may change out from under us, 2)
57
- /// the API is private and 3) the `_UIHostingView` doesn't not accept setting a new `View` instance.
58
- ///
59
- /// - SeeAlso: `EpoxySwiftUIHostingController`
60
- @available(iOS 13.0, tvOS 13.0, *)
61
- final class EpoxySwiftUIHostingView<RootView: View>: UIView, EpoxyableView {
62
-
63
- // MARK: Lifecycle
64
-
65
- init(style: Style) {
66
- // Ignore the safe area to ensure the view isn't laid out incorrectly when being sized while
67
- // overlapping the safe area.
68
- epoxyContent = EpoxyHostingContent(rootView: style.initialContent.rootView)
69
- viewController = EpoxySwiftUIHostingController(
70
- rootView: .init(content: epoxyContent, environment: epoxyEnvironment),
71
- ignoreSafeArea: true)
72
-
73
- dataID = style.initialContent.dataID ?? DefaultDataID.noneProvided as AnyHashable
74
-
75
- super.init(frame: .zero)
76
-
77
- epoxyEnvironment.intrinsicContentSizeInvalidator = .init(invalidate: { [weak self] in
78
- self?.viewController.view.invalidateIntrinsicContentSize()
79
-
80
- // Inform the enclosing collection view that the size has changed, if we're contained in one,
81
- // allowing the cell to resize.
82
- //
83
- // On iOS 16+, we could call `invalidateIntrinsicContentSize()` on the enclosing collection
84
- // view cell instead, but that currently causes visual artifacts with `MagazineLayout`. The
85
- // better long term fix is likely to switch to `UIHostingConfiguration` on iOS 16+ anyways.
86
- if let enclosingCollectionView = self?.superview?.superview?.superview as? UICollectionView {
87
- enclosingCollectionView.collectionViewLayout.invalidateLayout()
88
- }
89
- })
90
- layoutMargins = .zero
91
- }
92
-
93
- @available(*, unavailable)
94
- required init?(coder _: NSCoder) {
95
- fatalError("init(coder:) has not been implemented")
96
- }
97
-
98
- // MARK: Internal
99
-
100
- struct Style: Hashable {
101
- init(reuseBehavior: SwiftUIHostingViewReuseBehavior, initialContent: Content) {
102
- self.reuseBehavior = reuseBehavior
103
- self.initialContent = initialContent
104
- }
105
-
106
- var reuseBehavior: SwiftUIHostingViewReuseBehavior
107
- var initialContent: Content
108
-
109
- static func == (lhs: Style, rhs: Style) -> Bool {
110
- lhs.reuseBehavior == rhs.reuseBehavior
111
- }
112
-
113
- func hash(into hasher: inout Hasher) {
114
- hasher.combine(reuseBehavior)
115
- }
116
- }
117
-
118
- struct Content: Equatable {
119
- init(rootView: RootView, dataID: AnyHashable?) {
120
- self.rootView = rootView
121
- self.dataID = dataID
122
- }
123
-
124
- var rootView: RootView
125
- var dataID: AnyHashable?
126
-
127
- static func == (_: Content, _: Content) -> Bool {
128
- // The content should never be equal since we need the `rootView` to be updated on every
129
- // content change.
130
- false
131
- }
132
- }
133
-
134
- override func didMoveToWindow() {
135
- super.didMoveToWindow()
136
-
137
- // We'll only be able to discover a valid parent `viewController` once we're added to a window,
138
- // so we do so here in addition to the `handleWillDisplay(…)` method.
139
- if window != nil {
140
- addViewControllerIfNeeded()
141
- }
142
- }
143
-
144
- func setContent(_ content: Content, animated _: Bool) {
145
- // This triggers a change in the observed `EpoxyHostingContent` object and allows the
146
- // propagation of the SwiftUI transaction, instead of just replacing the `rootView`.
147
- epoxyContent.rootView = content.rootView
148
- dataID = content.dataID ?? DefaultDataID.noneProvided as AnyHashable
149
-
150
- // The view controller must be added to the view controller hierarchy to measure its content.
151
- if window != nil {
152
- addViewControllerIfNeeded()
153
- }
154
-
155
- // As of iOS 15.2, `UIHostingController` now renders updated content asynchronously, and as such
156
- // this view will get sized incorrectly with the previous content when reused unless we invoke
157
- // this semi-private API. We couldn't find any other method to get the view to resize
158
- // synchronously after updating `rootView`, but hopefully this will become a internal API soon so
159
- // we can remove this call.
160
- viewController._render(seconds: 0)
161
-
162
- // This is required to ensure that views with new content are properly resized.
163
- viewController.view.invalidateIntrinsicContentSize()
164
- }
165
-
166
- override func layoutMarginsDidChange() {
167
- super.layoutMarginsDidChange()
168
-
169
- let margins = layoutMargins
170
- switch effectiveUserInterfaceLayoutDirection {
171
- case .rightToLeft:
172
- epoxyEnvironment.layoutMargins = .init(
173
- top: margins.top,
174
- leading: margins.right,
175
- bottom: margins.bottom,
176
- trailing: margins.left)
177
- case .leftToRight:
178
- fallthrough
179
- @unknown default:
180
- epoxyEnvironment.layoutMargins = .init(
181
- top: margins.top,
182
- leading: margins.left,
183
- bottom: margins.bottom,
184
- trailing: margins.right)
185
- }
186
-
187
- // Allow the layout margins update to fully propagate through to the SwiftUI View before
188
- // invalidating the layout.
189
- DispatchQueue.main.async {
190
- self.viewController.view.invalidateIntrinsicContentSize()
191
- }
192
- }
193
-
194
- func handleWillDisplay(animated: Bool) {
195
- guard state != .appeared, window != nil else { return }
196
- transition(to: .appearing(animated: animated))
197
- transition(to: .appeared)
198
- }
199
-
200
- func handleDidEndDisplaying(animated: Bool) {
201
- guard state != .disappeared else { return }
202
- transition(to: .disappearing(animated: animated))
203
- transition(to: .disappeared)
204
- }
205
-
206
- // MARK: Private
207
-
208
- private let viewController: EpoxySwiftUIHostingController<EpoxyHostingWrapper<RootView>>
209
- private let epoxyContent: EpoxyHostingContent<RootView>
210
- private let epoxyEnvironment = EpoxyHostingEnvironment()
211
- private var dataID: AnyHashable
212
- private var state: AppearanceState = .disappeared
213
-
214
- /// Updates the appearance state of the `viewController`.
215
- private func transition(to state: AppearanceState) {
216
- guard state != self.state else { return }
217
-
218
- // See "Handling View-Related Notifications" section for the state machine diagram.
219
- // https://developer.apple.com/documentation/uikit/uiviewcontroller
220
- switch (to: state, from: self.state) {
221
- case (to: .appearing(let animated), from: .disappeared):
222
- viewController.beginAppearanceTransition(true, animated: animated)
223
- addViewControllerIfNeeded()
224
- case (to: .disappearing(let animated), from: .appeared):
225
- viewController.beginAppearanceTransition(false, animated: animated)
226
- case (to: .disappeared, from: .disappearing):
227
- removeViewControllerIfNeeded()
228
- case (to: .appeared, from: .appearing):
229
- viewController.endAppearanceTransition()
230
- case (to: .disappeared, from: .appeared):
231
- viewController.beginAppearanceTransition(false, animated: true)
232
- removeViewControllerIfNeeded()
233
- case (to: .appeared, from: .disappearing(let animated)):
234
- viewController.beginAppearanceTransition(true, animated: animated)
235
- viewController.endAppearanceTransition()
236
- case (to: .disappeared, from: .appearing(let animated)):
237
- viewController.beginAppearanceTransition(false, animated: animated)
238
- removeViewControllerIfNeeded()
239
- case (to: .appeared, from: .disappeared):
240
- viewController.beginAppearanceTransition(true, animated: false)
241
- addViewControllerIfNeeded()
242
- viewController.endAppearanceTransition()
243
- case (to: .appearing(let animated), from: .appeared):
244
- viewController.beginAppearanceTransition(false, animated: animated)
245
- viewController.beginAppearanceTransition(true, animated: animated)
246
- case (to: .appearing(let animated), from: .disappearing):
247
- viewController.beginAppearanceTransition(true, animated: animated)
248
- case (to: .disappearing(let animated), from: .disappeared):
249
- viewController.beginAppearanceTransition(true, animated: animated)
250
- addViewControllerIfNeeded()
251
- viewController.beginAppearanceTransition(false, animated: animated)
252
- case (to: .disappearing(let animated), from: .appearing):
253
- viewController.beginAppearanceTransition(false, animated: animated)
254
- case (to: .appearing, from: .appearing),
255
- (to: .appeared, from: .appeared),
256
- (to: .disappearing, from: .disappearing),
257
- (to: .disappeared, from: .disappeared):
258
- // This should never happen since we guard on identical states.
259
- EpoxyLogger.shared.assertionFailure("Impossible state change from \(self.state) to \(state)")
260
- }
261
-
262
- self.state = state
263
- }
264
-
265
- private func addViewControllerIfNeeded() {
266
- // This isn't great, and means that we're going to add this view controller as a child view
267
- // controller of a view controller somewhere else in the hierarchy, which the author of that
268
- // view controller may not be expecting. However there's not really a better pathway forward
269
- // here without requiring a view controller instance to be passed all the way through, which is
270
- // both burdensome and error-prone.
271
- guard let nextViewController = superview?.next(UIViewController.self) else {
272
- EpoxyLogger.shared.assertionFailure(
273
- """
274
- Unable to add a UIHostingController view, could not locate a UIViewController in the \
275
- responder chain for view with ID \(dataID) of type \(RootView.self).
276
- """)
277
- return
278
- }
279
-
280
- guard viewController.parent !== nextViewController else { return }
281
-
282
- // If in a different parent, we need to first remove from it before we add.
283
- if viewController.parent != nil {
284
- removeViewControllerIfNeeded()
285
- }
286
-
287
- addViewController(to: nextViewController)
288
-
289
- state = .appeared
290
- }
291
-
292
- private func addViewController(to parent: UIViewController) {
293
- viewController.willMove(toParent: parent)
294
-
295
- parent.addChild(viewController)
296
-
297
- addSubview(viewController.view)
298
-
299
- // Get the view controller's view to be sized correctly so that we don't have to wait for
300
- // autolayout to perform a pass to do so.
301
- viewController.view.frame = bounds
302
-
303
- viewController.view.translatesAutoresizingMaskIntoConstraints = false
304
- NSLayoutConstraint.activate([
305
- viewController.view.leadingAnchor.constraint(equalTo: leadingAnchor),
306
- viewController.view.topAnchor.constraint(equalTo: topAnchor),
307
- viewController.view.trailingAnchor.constraint(equalTo: trailingAnchor),
308
- viewController.view.bottomAnchor.constraint(equalTo: bottomAnchor),
309
- ])
310
-
311
- viewController.didMove(toParent: parent)
312
- }
313
-
314
- private func removeViewControllerIfNeeded() {
315
- guard viewController.parent != nil else { return }
316
-
317
- viewController.willMove(toParent: nil)
318
- viewController.view.removeFromSuperview()
319
- viewController.removeFromParent()
320
- viewController.didMove(toParent: nil)
321
- }
322
- }
323
-
324
- // MARK: - AppearanceState
325
-
326
- /// The appearance state of a `EpoxySwiftUIHostingController` contained within a
327
- /// `EpoxySwiftUIHostingView`.
328
- private enum AppearanceState: Equatable {
329
- case appearing(animated: Bool)
330
- case appeared
331
- case disappearing(animated: Bool)
332
- case disappeared
333
- }
334
-
335
- // MARK: - UIResponder
336
-
337
- extension UIResponder {
338
- /// Recursively traverses the responder chain upwards from this responder to its next responder
339
- /// until the a responder of the given type is located, else returns `nil`.
340
- @nonobjc
341
- fileprivate func next<ResponderType>(_ type: ResponderType.Type) -> ResponderType? {
342
- self as? ResponderType ?? next?.next(type)
343
- }
344
- }
345
-
346
- // MARK: - EpoxyHostingContent
347
-
348
- /// The object that is used to communicate changes in the root view to the
349
- /// `EpoxySwiftUIHostingController`.
350
- @available(iOS 13.0, tvOS 13.0, *)
351
- final class EpoxyHostingContent<RootView: View>: ObservableObject {
352
-
353
- // MARK: Lifecycle
354
-
355
- init(rootView: RootView) {
356
- _rootView = .init(wrappedValue: rootView)
357
- }
358
-
359
- // MARK: Internal
360
-
361
- @Published var rootView: RootView
362
- }
363
-
364
- // MARK: - EpoxyHostingEnvironment
365
-
366
- /// The object that is used to communicate values to SwiftUI views within an
367
- /// `EpoxySwiftUIHostingController`, e.g. layout margins.
368
- @available(iOS 13.0, tvOS 13.0, *)
369
- final class EpoxyHostingEnvironment: ObservableObject {
370
- @Published var layoutMargins = EdgeInsets()
371
- @Published var intrinsicContentSizeInvalidator = EpoxyIntrinsicContentSizeInvalidator(invalidate: { })
372
- }
373
-
374
- // MARK: - EpoxyHostingWrapper
375
-
376
- /// The wrapper view that is used to communicate values to SwiftUI views within an
377
- /// `EpoxySwiftUIHostingController`, e.g. layout margins.
378
- @available(iOS 13.0, tvOS 13.0, *)
379
- struct EpoxyHostingWrapper<Content: View>: View {
380
- @ObservedObject var content: EpoxyHostingContent<Content>
381
- @ObservedObject var environment: EpoxyHostingEnvironment
382
-
383
- var body: some View {
384
- content.rootView
385
- .environment(\.epoxyLayoutMargins, environment.layoutMargins)
386
- .environment(\.epoxyIntrinsicContentSizeInvalidator, environment.intrinsicContentSizeInvalidator)
387
- }
388
- }
389
- #endif