diff --git a/.travis.yml b/.travis.yml index ab99028e6..4043a9020 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ matrix: language: objective-c osx_image: xcode10.2 cache: yarn + before_script: + - pod repo update script: - yarn health after_success: @@ -27,8 +29,10 @@ matrix: - yarn build-examples --target android - name: iOS Examples language: objective-c - cache: cocoapods osx_image: xcode10.2 + cache: cocoapods + before_script: + - pod repo update script: - yarn build-examples --target ios addons: @@ -43,6 +47,7 @@ before_install: - nvm alias default 10.15.3 - nvm use 10.15.3 - export PATH="$HOME/.yarn/bin:$PATH" +- gem install cocoapods -v '1.7.4' install: yarn branches: only: diff --git a/examples/lorem-ipsum/examples/ios/LoremIpsum.xcodeproj/project.pbxproj b/examples/lorem-ipsum/examples/ios/LoremIpsum.xcodeproj/project.pbxproj index ea3837ae6..d9ac9c2a9 100644 --- a/examples/lorem-ipsum/examples/ios/LoremIpsum.xcodeproj/project.pbxproj +++ b/examples/lorem-ipsum/examples/ios/LoremIpsum.xcodeproj/project.pbxproj @@ -204,18 +204,11 @@ files = ( ); inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-LoremIpsum/Pods-LoremIpsum-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/DiezLoremIpsum/DiezLoremIpsum.framework", - "${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework", + "${PODS_ROOT}/Target Support Files/Pods-LoremIpsum/Pods-LoremIpsum-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DiezLoremIpsum.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lottie.framework", + "${PODS_ROOT}/Target Support Files/Pods-LoremIpsum/Pods-LoremIpsum-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/examples/lorem-ipsum/examples/ios/LoremIpsum/View.swift b/examples/lorem-ipsum/examples/ios/LoremIpsum/View.swift index 4a4b369dc..081f53e47 100644 --- a/examples/lorem-ipsum/examples/ios/LoremIpsum/View.swift +++ b/examples/lorem-ipsum/examples/ios/LoremIpsum/View.swift @@ -11,7 +11,7 @@ class View: UIView { let titleLabel = UILabel() let captionLabel = UILabel() let animationStackView = UIStackView() - let animationView = LOTAnimationView() + let animationView = AnimationView() let animationLabel = UILabel() override init(frame: CGRect) { diff --git a/examples/lorem-ipsum/examples/ios/Podfile b/examples/lorem-ipsum/examples/ios/Podfile index b7bba342c..6927e1297 100644 --- a/examples/lorem-ipsum/examples/ios/Podfile +++ b/examples/lorem-ipsum/examples/ios/Podfile @@ -5,5 +5,5 @@ target 'LoremIpsum' do pod 'DiezLoremIpsum', :path => '../../build/diez-lorem-ipsum-ios' - pod 'lottie-ios', '2.5.2' + pod 'lottie-ios', '3.1.1' end diff --git a/examples/lorem-ipsum/examples/ios/Podfile.lock b/examples/lorem-ipsum/examples/ios/Podfile.lock index ad90abd5c..3b109f0ba 100644 --- a/examples/lorem-ipsum/examples/ios/Podfile.lock +++ b/examples/lorem-ipsum/examples/ios/Podfile.lock @@ -1,11 +1,11 @@ PODS: - DiezLoremIpsum (0.1.0): - - lottie-ios (~> 2.5.2) - - lottie-ios (2.5.2) + - lottie-ios (~> 3.1.1) + - lottie-ios (3.1.1) DEPENDENCIES: - DiezLoremIpsum (from `../../build/diez-lorem-ipsum-ios`) - - lottie-ios (= 2.5.2) + - lottie-ios (= 3.1.1) SPEC REPOS: https://github.com/cocoapods/specs.git: @@ -16,9 +16,9 @@ EXTERNAL SOURCES: :path: "../../build/diez-lorem-ipsum-ios" SPEC CHECKSUMS: - DiezLoremIpsum: 4dccf7d4536f9e1d8ca23aef41237380eeb21a91 - lottie-ios: 3fef45d3fabe63e3c7c2eb603dd64ddfffc73062 + DiezLoremIpsum: 3b02836469ae9dd33886900e766abcbaab33cc2c + lottie-ios: 43a472d22b2dd2bed292cc4010c0b4d2e66d3ba8 -PODFILE CHECKSUM: a79aa59f925d2c472d63b1d2344ba6da58241ee9 +PODFILE CHECKSUM: 0252dab712b9ae8559f499051289c6c08eadc0f9 -COCOAPODS: 1.6.1 +COCOAPODS: 1.7.4 diff --git a/examples/poodle-surf/examples/ios-objc/PoodleSurfObjC/ViewController.m b/examples/poodle-surf/examples/ios-objc/PoodleSurfObjC/ViewController.m index d83c6e99d..e35cae9e7 100644 --- a/examples/poodle-surf/examples/ios-objc/PoodleSurfObjC/ViewController.m +++ b/examples/poodle-surf/examples/ios-objc/PoodleSurfObjC/ViewController.m @@ -49,7 +49,7 @@ - (void)viewDidLoad { imageView.contentMode = UIViewContentModeScaleAspectFit; [self.stackView appendView:imageView]; - LOTAnimationView *animationView = [[LOTAnimationView alloc] init]; + AnimationView *animationView = [[AnimationView alloc] init]; [self.stackView appendView:animationView]; [animationView.heightAnchor constraintEqualToAnchor:animationView.widthAnchor].active = YES; @@ -81,7 +81,7 @@ - (void)viewDidLoad { [gradientView.gradientLayer dez_applyLinearGradient:component.designs.report.waterTemperature.shared.gradient]; - [animationView dez_loadLottie:component.designs.loading.animation withSession:NSURLSession.sharedSession completion:nil]; + [animationView dez_loadLottie:component.designs.loading.animation completion:nil]; }]; } diff --git a/examples/poodle-surf/examples/ios/Podfile b/examples/poodle-surf/examples/ios/Podfile index 2fc821189..1ec0a8d35 100644 --- a/examples/poodle-surf/examples/ios/Podfile +++ b/examples/poodle-surf/examples/ios/Podfile @@ -5,5 +5,5 @@ target 'PoodleSurf' do pod 'DiezPoodleSurf', :path => '../../build/diez-poodle-surf-ios' - pod 'lottie-ios', '2.5.2' + pod 'lottie-ios', '3.1.1' end diff --git a/examples/poodle-surf/examples/ios/Podfile.lock b/examples/poodle-surf/examples/ios/Podfile.lock index d752cc41e..97655d0e9 100644 --- a/examples/poodle-surf/examples/ios/Podfile.lock +++ b/examples/poodle-surf/examples/ios/Podfile.lock @@ -1,11 +1,11 @@ PODS: - DiezPoodleSurf (0.1.0): - - lottie-ios (~> 2.5.2) - - lottie-ios (2.5.2) + - lottie-ios (~> 3.1.1) + - lottie-ios (3.1.1) DEPENDENCIES: - DiezPoodleSurf (from `../../build/diez-poodle-surf-ios`) - - lottie-ios (= 2.5.2) + - lottie-ios (= 3.1.1) SPEC REPOS: https://github.com/cocoapods/specs.git: @@ -16,9 +16,9 @@ EXTERNAL SOURCES: :path: "../../build/diez-poodle-surf-ios" SPEC CHECKSUMS: - DiezPoodleSurf: 86c1d7aa84dc357c559dd3564633a55d0d3c8403 - lottie-ios: 3fef45d3fabe63e3c7c2eb603dd64ddfffc73062 + DiezPoodleSurf: 408fc61002083b2dbe28b3f976f3cad66716ce3e + lottie-ios: 43a472d22b2dd2bed292cc4010c0b4d2e66d3ba8 -PODFILE CHECKSUM: d1516643ba0c111d1e67198e6bf75ecfa9ac807b +PODFILE CHECKSUM: 677d35819389b4af10b2328fe426d72e2250ac2d -COCOAPODS: 1.6.1 +COCOAPODS: 1.7.4 diff --git a/examples/poodle-surf/examples/ios/PoodleSurf.xcodeproj/project.pbxproj b/examples/poodle-surf/examples/ios/PoodleSurf.xcodeproj/project.pbxproj index fd4840330..2b1cd07d4 100644 --- a/examples/poodle-surf/examples/ios/PoodleSurf.xcodeproj/project.pbxproj +++ b/examples/poodle-surf/examples/ios/PoodleSurf.xcodeproj/project.pbxproj @@ -339,18 +339,11 @@ files = ( ); inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-PoodleSurf/Pods-PoodleSurf-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/DiezPoodleSurf/DiezPoodleSurf.framework", - "${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework", + "${PODS_ROOT}/Target Support Files/Pods-PoodleSurf/Pods-PoodleSurf-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DiezPoodleSurf.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lottie.framework", + "${PODS_ROOT}/Target Support Files/Pods-PoodleSurf/Pods-PoodleSurf-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/examples/poodle-surf/examples/ios/PoodleSurf/Loading/LoadingView.swift b/examples/poodle-surf/examples/ios/PoodleSurf/Loading/LoadingView.swift index e20e9917d..7ce803c79 100644 --- a/examples/poodle-surf/examples/ios/PoodleSurf/Loading/LoadingView.swift +++ b/examples/poodle-surf/examples/ios/PoodleSurf/Loading/LoadingView.swift @@ -10,12 +10,13 @@ import UIKit import Lottie class LoadingView: UIView { - let animationView = LOTAnimationView() + let animationView = AnimationView() override init(frame: CGRect) { super.init(frame: CGRect.zero) setupLayout() + configureViews() } override class var requiresConstraintBasedLayout: Bool { @@ -30,6 +31,10 @@ class LoadingView: UIView { animationView.centerYAnchor.constraint(equalTo: centerYAnchor), ]) } + + private func configureViews() { + animationView.backgroundBehavior = .pauseAndRestore + } @available(*, unavailable) required init?(coder aDecoder: NSCoder) { fatalError("\(#function) not implemented.") } diff --git a/examples/site/examples/web/docs/existing-project-integration/ios.md b/examples/site/examples/web/docs/existing-project-integration/ios.md index 45dfdef09..785bbd7ec 100644 --- a/examples/site/examples/web/docs/existing-project-integration/ios.md +++ b/examples/site/examples/web/docs/existing-project-integration/ios.md @@ -94,13 +94,13 @@ extension Lottie { } ``` -#### LOTAnimationView Loader +#### AnimationView Loader ```swift -extension LOTAnimationView { - typealias LoadCompletion = (Result) -> Void +extension AnimationView { + typealias LoadCompletion = (Bool) -> Void - func load(_ lottie: Lottie, session: URLSession = .shared, completion: LoadCompletion? = nil) -> URLSessionDataTask? + func load(_ lottie: Lottie, completion: LoadCompletion? = nil) } ``` diff --git a/packages/targets/sources/ios/bindings/Lottie+AnimationView.swift b/packages/targets/sources/ios/bindings/Lottie+AnimationView.swift new file mode 100644 index 000000000..f45cc89c6 --- /dev/null +++ b/packages/targets/sources/ios/bindings/Lottie+AnimationView.swift @@ -0,0 +1,64 @@ +import Foundation +import Lottie + +/** + An error that occurred when attempting to load a `Lottie` object in a `LOTAnimationView`. + */ +public enum LottieError: Error, CustomDebugStringConvertible { + case invalidURL + case requestFailed(Error?) + case deserializationError(Data, Error) + case invalidType(json: Any) + + public var debugDescription: String { + switch self { + case .invalidURL: + return "Lottie URL is invalid." + case .requestFailed(let error): + return "Request failed: \(String(describing: error))" + case .deserializationError(let data, let error): + let dataAsString = String(data: data, encoding: String.Encoding.utf8) + return "Lottie file failed to be deserialized: \(error)\n\(String(describing: dataAsString))" + case .invalidType(let json): + return "JSON was not in the correct format ([AnyHashable: Any]): \(json)" + } + } +} + +extension AnimationView { + /** + A closure to be called when loading a `Lottie` animation has completed with a value that represents whether the animation was loaded successfully. + */ + public typealias LoadCompletion = (Bool) -> Void + + /** + Loads the provided `Lottie` animation. + */ + @objc(dez_loadLottie:completion:) + public func load(_ lottie: Lottie, completion: LoadCompletion? = nil) { + // TODO: Add a parameter that allows a fade in animated and add a description of the parameter to doc comment. + // TODO: Should this be synchronous when resource is local? + guard let url = lottie.url else { + completion?(false) + return + } + + Animation.loadedFrom(url: url, closure: { [weak self] animation in + guard let self = self else { return } + + guard let animation = animation else { + completion?(false) + return + } + + self.animation = animation + self.loopMode = lottie.loop ? .loop : .playOnce + + if lottie.autoplay { + self.play() + } + + completion?(true) + }, animationCache: nil) + } +} diff --git a/packages/targets/sources/ios/bindings/Lottie+LOTAnimationView.swift b/packages/targets/sources/ios/bindings/Lottie+LOTAnimationView.swift deleted file mode 100644 index dfb4130a5..000000000 --- a/packages/targets/sources/ios/bindings/Lottie+LOTAnimationView.swift +++ /dev/null @@ -1,116 +0,0 @@ -import Lottie - -/** - An error that occurred when attempting to load a `Lottie` object in a `LOTAnimationView`. - */ -public enum LottieError: Error, CustomDebugStringConvertible { - case invalidURL - case requestFailed(Error?) - case deserializationError(Data, Error) - case invalidType(json: Any) - - public var debugDescription: String { - switch self { - case .invalidURL: - return "Lottie URL is invalid." - case .requestFailed(let error): - return "Request failed: \(String(describing: error))" - case .deserializationError(let data, let error): - let dataAsString = String(data: data, encoding: String.Encoding.utf8) - return "Lottie file failed to be deserialized: \(error)\n\(String(describing: dataAsString))" - case .invalidType(let json): - return "JSON was not in the correct format ([AnyHashable: Any]): \(json)" - } - } -} - -extension LOTAnimationView { - /** - A closure to be called when loading a `Lottie` animation has completed. - */ - public typealias LoadCompletion = (Result) -> Void - - /** - - Tag: LOTAnimationView.loadLottieSessionCompletion - - Loads the provided `Lottie` animation. - - - Parameters: - - lottie: The `Lottie` animation to be loaded. - - session: The `URLSession` to be used when fetching the resource. - - completion: A closure to be called when the load operation has completed. - - - Returns: The `URLSessionDataTask` used to fetch the asset, or `nil` if the - [Lottie.url](x-source-tag://Lottie.url) is `nil`. - */ - @discardableResult - public func load(_ lottie: Lottie, session: URLSession = .shared, completion: LoadCompletion? = nil) -> URLSessionDataTask? { - // TODO: Add a parameter that allows a fade in animated and add a description of the parameter to doc comment. - // TODO: Should this be synchronous when resource is local? - guard let url = lottie.url else { - completion?(.failure(.invalidURL)) - return nil - } - - let task = session.dataTask(with: url) { [weak self] (data, response, error) in - self?.loadWith(data: data, lottie: lottie, response: response, error: error, completion: completion) - } - - task.resume() - - return task - } - - private func loadWith(data: Data?, lottie: Lottie, response: URLResponse?, error: Error?, completion: LoadCompletion?) { - guard let data = data else { - DispatchQueue.main.async { completion?(.failure(.requestFailed(error))) } - return - } - - do { - let jsonObject = try JSONSerialization.jsonObject(with: data, options: .allowFragments) - - guard let json = jsonObject as? [AnyHashable: Any] else { - DispatchQueue.main.async { completion?(.failure(.invalidType(json: jsonObject))) } - return - } - - DispatchQueue.main.async { - // TODO: Use bundle for referenced assets? - self.setAnimation(json: json) - - self.loopAnimation = lottie.loop - - guard lottie.autoplay else { - completion?(.success(())) - return - } - - self.play { _ in - completion?(.success(())) - } - } - } catch { - DispatchQueue.main.async { completion?(.failure(.deserializationError(data, error)))} - } - } - - /** - The Objective-C equivalent of load(:session:completion:). - - - See: [load(:session:completion:)](x-source-tag://LOTAnimationView.loadLottieSessionCompletion) - */ - @available(swift, obsoleted: 0.0.1) - @discardableResult - @objc(dez_loadLottie:withSession:completion:) - public func load(_ lottie: Lottie, session: URLSession = .shared, completion: ((_ success: Bool, _ error: NSError?) -> Void)? = nil) -> URLSessionDataTask? { - return load(lottie, session: session) { result in - switch result { - case .success: - completion?(true, nil) - case .failure(let error): - completion?(false, error as NSError) - } - } - } -} diff --git a/packages/targets/src/bindings/Lottie/ios.ts b/packages/targets/src/bindings/Lottie/ios.ts index 543458f73..aa74004da 100644 --- a/packages/targets/src/bindings/Lottie/ios.ts +++ b/packages/targets/src/bindings/Lottie/ios.ts @@ -6,17 +6,17 @@ import {sourcesPath} from '../../utils'; const binding: IosBinding = { sources: [ join(sourcesPath, 'ios', 'bindings', 'Lottie+Binding.swift'), - join(sourcesPath, 'ios', 'bindings', 'Lottie+LOTAnimationView.swift'), + join(sourcesPath, 'ios', 'bindings', 'Lottie+AnimationView.swift'), ], dependencies: [{ cocoapods: { name: 'lottie-ios', - versionConstraint: '~> 2.5.2', + versionConstraint: '~> 3.1.1', }, carthage: { name: 'Lottie', github: 'airbnb/lottie-ios', - versionConstraint: '~> 2.5.2', + versionConstraint: '~> 3.1.1', }, }], }; diff --git a/packages/targets/test/goldens/Bindings/diez-stub-ios/Cartfile b/packages/targets/test/goldens/Bindings/diez-stub-ios/Cartfile index e5ba4e869..c43e86239 100644 --- a/packages/targets/test/goldens/Bindings/diez-stub-ios/Cartfile +++ b/packages/targets/test/goldens/Bindings/diez-stub-ios/Cartfile @@ -1 +1 @@ -github "airbnb/lottie-ios" ~> 2.5.2 +github "airbnb/lottie-ios" ~> 3.1.1 diff --git a/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.podspec b/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.podspec index ea1ebacc3..816ad74ee 100644 --- a/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.podspec +++ b/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.podspec @@ -15,7 +15,7 @@ Pod::Spec.new do |s| # TODO: What are these, actually? s.platforms = { :ios => '12.1' } # TODO: Support new Lottie iOS - s.dependency 'lottie-ios', '~> 2.5.2' + s.dependency 'lottie-ios', '~> 3.1.1' s.source_files = 'Sources/DiezStub/**/*.swift' s.framework = 'UIKit', 'WebKit' # TODO: s.ios.source_files and s.ios.framework for iOS, s.osx.* for macOS, and so on diff --git a/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.xcodeproj/project.pbxproj b/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.xcodeproj/project.pbxproj index db3cba988..c353108e7 100644 --- a/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.xcodeproj/project.pbxproj +++ b/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.xcodeproj/project.pbxproj @@ -13,7 +13,7 @@ 108A4498340BC4C0482D8D2AA211D236 /* Lottie.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263AFEF2C4505E942A50A2C3FFCB425F /* Lottie.swift */; }; 1B0A959296A666217D7A0B4C315371A9 /* Diez.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5200545FEA8D9036054F764B19EEC102 /* Diez.swift */; }; 1E6B4DB1C871835F5C4BD84CC3A5370C /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF6D6468DECE18204492CA00282CCC8F /* Font.swift */; }; - 2D0E231FCC3BB58D4B1997827337661F /* Lottie+LOTAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CF698BEF6434F69456E0191B649BA7 /* Lottie+LOTAnimationView.swift */; }; + 1F47EA530E7E5A009852D1CE32ED2B0A /* Lottie+AnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 207823425A8359D695B824521CC53A7B /* Lottie+AnimationView.swift */; }; 30D8DCC71661D0ECFB778AA59754131A /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8778BD519B243F8B2E2F9E6B58B6660F /* Environment.swift */; }; 31D405B5F5E3947ED5EC505C44F4868D /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6639302602D066191557EE67F2F3A8BB /* File.swift */; }; 35C4CB5F2F0A994E4D65F1145C6CBCCC /* Bundle+Static.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A2033D197C87132619563FDCBF3076E /* Bundle+Static.swift */; }; @@ -51,6 +51,7 @@ 1134BF4AC055DADAD76630D14C02E8A2 /* Typograph+Binding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Typograph+Binding.swift"; sourceTree = ""; }; 123F5E73C868209F9A884D6D03B826D6 /* Bindings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bindings.swift; sourceTree = ""; }; 1D95D9BD0E84421610DD95EEAAEFDA3B /* ReflectedCustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReflectedCustomStringConvertible.swift; sourceTree = ""; }; + 207823425A8359D695B824521CC53A7B /* Lottie+AnimationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Lottie+AnimationView.swift"; sourceTree = ""; }; 263AFEF2C4505E942A50A2C3FFCB425F /* Lottie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lottie.swift; sourceTree = ""; }; 2A67FEB60DD6033589048DEE59E4C2A8 /* Color+Binding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Binding.swift"; sourceTree = ""; }; 465941092F6455C3C1C480BD71338E3E /* DiezStub.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DiezStub.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -67,7 +68,6 @@ 8DC81DA6485DC5CEADF4FB56A15C36F3 /* Image+Binding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Image+Binding.swift"; sourceTree = ""; }; 9BE97E7A473C2D663F9221BBCFB0D6E5 /* Bundle+Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Environment.swift"; sourceTree = ""; }; A6C61241B372972554AA1D66DF18F052 /* LinearGradient+Binding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LinearGradient+Binding.swift"; sourceTree = ""; }; - A9CF698BEF6434F69456E0191B649BA7 /* Lottie+LOTAnimationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Lottie+LOTAnimationView.swift"; sourceTree = ""; }; C3079B1384BD06EE8EBB48505985BAC9 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; C74433DE600D9C72B6D36287376EE502 /* Typograph.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Typograph.swift; sourceTree = ""; }; C9A0B8DEBE9CB8D94DACCED192B2D4E6 /* Lottie.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Lottie.framework; sourceTree = ""; }; @@ -136,8 +136,8 @@ 532372957C7BF2D47B40B9DD6C61D279 /* File+Binding.swift */, 8DC81DA6485DC5CEADF4FB56A15C36F3 /* Image+Binding.swift */, A6C61241B372972554AA1D66DF18F052 /* LinearGradient+Binding.swift */, + 207823425A8359D695B824521CC53A7B /* Lottie+AnimationView.swift */, D7BEA91049CF649A1AE50E700DB149E5 /* Lottie+Binding.swift */, - A9CF698BEF6434F69456E0191B649BA7 /* Lottie+LOTAnimationView.swift */, CA97DDD9A7081279C2BF2D9D3FE190CD /* Point2D+Binding.swift */, 1134BF4AC055DADAD76630D14C02E8A2 /* Typograph+Binding.swift */, ); @@ -313,8 +313,8 @@ 5340E71A3CD2A2FEC7A894D47BA1303F /* Image.swift in Sources */, 0223CD8425934D209393C5C458FEDE68 /* LinearGradient+Binding.swift in Sources */, 799AE05A93E085E50C7234CEEEFAA79B /* LinearGradient.swift in Sources */, + 1F47EA530E7E5A009852D1CE32ED2B0A /* Lottie+AnimationView.swift in Sources */, 43F025A40CF48D48F83C7F712D32F9BE /* Lottie+Binding.swift in Sources */, - 2D0E231FCC3BB58D4B1997827337661F /* Lottie+LOTAnimationView.swift in Sources */, 108A4498340BC4C0482D8D2AA211D236 /* Lottie.swift in Sources */, 535887A1E1AA83159970674B6768228D /* Point2D+Binding.swift in Sources */, 4A0ADC8D0F776D1DB4A99ABC0DE8F1F9 /* Point2D.swift in Sources */, diff --git a/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Bindings/Lottie+AnimationView.swift b/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Bindings/Lottie+AnimationView.swift new file mode 100644 index 000000000..f45cc89c6 --- /dev/null +++ b/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Bindings/Lottie+AnimationView.swift @@ -0,0 +1,64 @@ +import Foundation +import Lottie + +/** + An error that occurred when attempting to load a `Lottie` object in a `LOTAnimationView`. + */ +public enum LottieError: Error, CustomDebugStringConvertible { + case invalidURL + case requestFailed(Error?) + case deserializationError(Data, Error) + case invalidType(json: Any) + + public var debugDescription: String { + switch self { + case .invalidURL: + return "Lottie URL is invalid." + case .requestFailed(let error): + return "Request failed: \(String(describing: error))" + case .deserializationError(let data, let error): + let dataAsString = String(data: data, encoding: String.Encoding.utf8) + return "Lottie file failed to be deserialized: \(error)\n\(String(describing: dataAsString))" + case .invalidType(let json): + return "JSON was not in the correct format ([AnyHashable: Any]): \(json)" + } + } +} + +extension AnimationView { + /** + A closure to be called when loading a `Lottie` animation has completed with a value that represents whether the animation was loaded successfully. + */ + public typealias LoadCompletion = (Bool) -> Void + + /** + Loads the provided `Lottie` animation. + */ + @objc(dez_loadLottie:completion:) + public func load(_ lottie: Lottie, completion: LoadCompletion? = nil) { + // TODO: Add a parameter that allows a fade in animated and add a description of the parameter to doc comment. + // TODO: Should this be synchronous when resource is local? + guard let url = lottie.url else { + completion?(false) + return + } + + Animation.loadedFrom(url: url, closure: { [weak self] animation in + guard let self = self else { return } + + guard let animation = animation else { + completion?(false) + return + } + + self.animation = animation + self.loopMode = lottie.loop ? .loop : .playOnce + + if lottie.autoplay { + self.play() + } + + completion?(true) + }, animationCache: nil) + } +} diff --git a/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Bindings/Lottie+LOTAnimationView.swift b/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Bindings/Lottie+LOTAnimationView.swift deleted file mode 100644 index dfb4130a5..000000000 --- a/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Bindings/Lottie+LOTAnimationView.swift +++ /dev/null @@ -1,116 +0,0 @@ -import Lottie - -/** - An error that occurred when attempting to load a `Lottie` object in a `LOTAnimationView`. - */ -public enum LottieError: Error, CustomDebugStringConvertible { - case invalidURL - case requestFailed(Error?) - case deserializationError(Data, Error) - case invalidType(json: Any) - - public var debugDescription: String { - switch self { - case .invalidURL: - return "Lottie URL is invalid." - case .requestFailed(let error): - return "Request failed: \(String(describing: error))" - case .deserializationError(let data, let error): - let dataAsString = String(data: data, encoding: String.Encoding.utf8) - return "Lottie file failed to be deserialized: \(error)\n\(String(describing: dataAsString))" - case .invalidType(let json): - return "JSON was not in the correct format ([AnyHashable: Any]): \(json)" - } - } -} - -extension LOTAnimationView { - /** - A closure to be called when loading a `Lottie` animation has completed. - */ - public typealias LoadCompletion = (Result) -> Void - - /** - - Tag: LOTAnimationView.loadLottieSessionCompletion - - Loads the provided `Lottie` animation. - - - Parameters: - - lottie: The `Lottie` animation to be loaded. - - session: The `URLSession` to be used when fetching the resource. - - completion: A closure to be called when the load operation has completed. - - - Returns: The `URLSessionDataTask` used to fetch the asset, or `nil` if the - [Lottie.url](x-source-tag://Lottie.url) is `nil`. - */ - @discardableResult - public func load(_ lottie: Lottie, session: URLSession = .shared, completion: LoadCompletion? = nil) -> URLSessionDataTask? { - // TODO: Add a parameter that allows a fade in animated and add a description of the parameter to doc comment. - // TODO: Should this be synchronous when resource is local? - guard let url = lottie.url else { - completion?(.failure(.invalidURL)) - return nil - } - - let task = session.dataTask(with: url) { [weak self] (data, response, error) in - self?.loadWith(data: data, lottie: lottie, response: response, error: error, completion: completion) - } - - task.resume() - - return task - } - - private func loadWith(data: Data?, lottie: Lottie, response: URLResponse?, error: Error?, completion: LoadCompletion?) { - guard let data = data else { - DispatchQueue.main.async { completion?(.failure(.requestFailed(error))) } - return - } - - do { - let jsonObject = try JSONSerialization.jsonObject(with: data, options: .allowFragments) - - guard let json = jsonObject as? [AnyHashable: Any] else { - DispatchQueue.main.async { completion?(.failure(.invalidType(json: jsonObject))) } - return - } - - DispatchQueue.main.async { - // TODO: Use bundle for referenced assets? - self.setAnimation(json: json) - - self.loopAnimation = lottie.loop - - guard lottie.autoplay else { - completion?(.success(())) - return - } - - self.play { _ in - completion?(.success(())) - } - } - } catch { - DispatchQueue.main.async { completion?(.failure(.deserializationError(data, error)))} - } - } - - /** - The Objective-C equivalent of load(:session:completion:). - - - See: [load(:session:completion:)](x-source-tag://LOTAnimationView.loadLottieSessionCompletion) - */ - @available(swift, obsoleted: 0.0.1) - @discardableResult - @objc(dez_loadLottie:withSession:completion:) - public func load(_ lottie: Lottie, session: URLSession = .shared, completion: ((_ success: Bool, _ error: NSError?) -> Void)? = nil) -> URLSessionDataTask? { - return load(lottie, session: session) { result in - switch result { - case .success: - completion?(true, nil) - case .failure(let error): - completion?(false, error as NSError) - } - } - } -}