diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9934800e23..d693a757c1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,13 +9,12 @@ on: jobs: build-package-no-visionOS: name: "Build Package" - runs-on: macos-13 + runs-on: macos-14 strategy: fail-fast: false matrix: xcode: - - '14.1' # Swift 5.7 - - '14.3' # Swift 5.8 + - '15.0.1' # Swift 5.9, but no visionOS support steps: - uses: actions/checkout@v2 - uses: ./.github/actions/setup @@ -88,7 +87,7 @@ jobs: build-xcframework-minimum-supported-version: name: "Build XCFramework" - runs-on: macos-13 + runs-on: macos-14 strategy: matrix: xcode: @@ -96,36 +95,9 @@ jobs: # The Xcode version we use for this job is that oldest Xcode version that # will be able to use these XCFrameworks and the lottie-spm package. # This should be the minimum Xcode version permitted by the App Store. - # As of April 2023, this is Xcode 14.1: https://developer.apple.com/news/?id=jd9wcyov - # - TODO: Once this minimum supported Xcode version is 15.0 or later, - # we can use Xcode 15.2 here and remove the `build-xcframework-with-visionOS-support` job. - # Testing in https://github.com/airbnb/lottie-spm/pull/12 shows that Xcode 15.0 can - # use an XCFramework built by Xcode 15.2. - - '14.1' # Swift 5.7.1 - steps: - - uses: actions/checkout@v2 - - uses: apple-actions/import-codesign-certs@v2 - continue-on-error: true - with: - p12-file-base64: ${{ secrets.SIGNING_CERTIFICATE_BASE_64 }} - p12-password: ${{ secrets.SIGNING_CERTIFICATE_PASSWORD }} - - uses: ./.github/actions/setup - with: - xcode: ${{ matrix.xcode }} - - name: Build XCFramework - run: SKIP_VISION_OS=true bundle exec rake build:xcframework[Lottie-Xcode-${{ matrix.xcode }}] - - name: Upload XCFramework - uses: actions/upload-artifact@v2 - with: - name: BuildProducts - path: .build/archives - - build-xcframework-with-visionOS-support: - name: "Build XCFramework" - runs-on: macos-14 - strategy: - matrix: - xcode: + # As of April 2024, this is Xcode 15.0: https://developer.apple.com/news/?id=fxu2qp7b + # - However, testing in https://github.com/airbnb/lottie-spm/pull/12 shows that + # Xcode 15.0 can use an XCFramework built by Xcode 15.2. - '15.2' # Swift 5.9, first Xcode version with visionOS support. steps: - uses: actions/checkout@v2 diff --git a/Example/Example/AnimationListView.swift b/Example/Example/AnimationListView.swift index 1f87b123fc..a57907208c 100644 --- a/Example/Example/AnimationListView.swift +++ b/Example/Example/AnimationListView.swift @@ -88,9 +88,9 @@ struct AnimationListView: View { private var directory: String { switch content { case .directory(let directory): - return directory + directory case .custom: - return "n/a" + "n/a" } } @@ -112,12 +112,12 @@ extension AnimationListView { var items: [Item] { switch content { case .directory: - return animations.map { .animation(name: $0.name, path: $0.path) } + animations.map { .animation(name: $0.name, path: $0.path) } + subdirectoryURLs.map { .animationList(.directory("\(directory)/\($0.lastPathComponent)")) } + customDemos case .custom(_, let items): - return items + items } } @@ -171,15 +171,15 @@ extension AnimationListView.Item { var name: String { switch self { case .animation(let animationName, _), .remoteAnimations(let animationName, _): - return animationName + animationName case .animationList(let content): - return content.name + content.name case .controlsDemo: - return "Controls Demo" + "Controls Demo" case .swiftUIInteroperability: - return "SwiftUI Interoperability Demo" + "SwiftUI Interoperability Demo" case .lottieViewLayoutDemo: - return "LottieView Layout Demo" + "LottieView Layout Demo" } } } @@ -204,9 +204,9 @@ extension AnimationListView.Content { var name: String { switch self { case .directory(let directory): - return directory.components(separatedBy: "/").last ?? directory + directory.components(separatedBy: "/").last ?? directory case .custom(let name, _): - return name + name } } } diff --git a/Example/Example/AnimationPreviewView.swift b/Example/Example/AnimationPreviewView.swift index b100af81fd..37e9bd64cb 100644 --- a/Example/Example/AnimationPreviewView.swift +++ b/Example/Example/AnimationPreviewView.swift @@ -17,6 +17,7 @@ struct AnimationPreviewView: View { case .remote(let urls, _): _currentURLIndex = State(initialValue: urls.startIndex) self.urls = urls + default: _currentURLIndex = State(initialValue: 0) urls = [] @@ -32,9 +33,9 @@ struct AnimationPreviewView: View { var name: String { switch self { case .local(let name): - return name + name case .remote(_, let name): - return name + name } } } @@ -124,9 +125,9 @@ struct AnimationPreviewView: View { private var playbackMode: LottiePlaybackMode { if animationPlaying { - return .playing(.fromProgress(playFromProgress, toProgress: playToProgress, loopMode: loopMode)) + .playing(.fromProgress(playFromProgress, toProgress: playToProgress, loopMode: loopMode)) } else { - return .paused(at: .progress(sliderValue)) + .paused(at: .progress(sliderValue)) } } @@ -184,13 +185,13 @@ struct AnimationPreviewView: View { switch animationSource { case .local(let name): if name.hasSuffix(".lottie") { - return try await DotLottieFile.named(name).animationSource + try await DotLottieFile.named(name).animationSource } else { - return LottieAnimation.named(name)?.animationSource + LottieAnimation.named(name)?.animationSource } case .remote: - return await LottieAnimation.loadedFrom(url: urls[currentURLIndex])?.animationSource + await LottieAnimation.loadedFrom(url: urls[currentURLIndex])?.animationSource } } diff --git a/Package.resolved b/Package.resolved index 31a8a3fa40..20ed813a6b 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/airbnb/swift", "state" : { - "revision" : "bc6aa7c3e21b6ab951ce75afc0a6e6d16fd6caef", - "version" : "1.0.6" + "revision" : "fa3ae574d0b9c93a1655424bd4381044274c5cb4", + "version" : "1.0.7" } }, { diff --git a/Package.swift b/Package.swift index 02b3e147fb..e8a4b13dab 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.7 +// swift-tools-version:5.9 import PackageDescription let package = Package( diff --git a/README.md b/README.md index e852aa8771..1eaea75f50 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ In your application targets “General” tab under the “Linked Frameworks and ## Swift Version Support -Lottie supports Swift / Xcode versions back to the minimum version that is permited by Apple for submissions to the App Store. You can see the most up-to-date information for which Swift versions Lottie supports on [Swift Package Index](https://swiftpackageindex.com/airbnb/lottie-ios): +Lottie supports Swift / Xcode versions back to the minimum version that is permitted by Apple for submissions to the App Store. You can see the most up-to-date information for which Swift versions Lottie supports on [Swift Package Index](https://swiftpackageindex.com/airbnb/lottie-ios): [![Swift Versions](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fairbnb%2Flottie-ios%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/airbnb/lottie-ios) diff --git a/Rakefile b/Rakefile index 65115837f0..7a9f2867e2 100644 --- a/Rakefile +++ b/Rakefile @@ -249,7 +249,7 @@ def xcodebuild(command) end # Runs the given code block, unless `SKIP_VISION_OS=true`. -# TODO: Remove this once CI only uses Xcode 15.2+. +# TODO: Remove this once Lottie only supports Xcode 15.2+. def ifVisionOSEnabled if ENV["SKIP_VISION_OS"] == "true" puts "Skipping visionOS build" diff --git a/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift b/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift index 35dd69dfb4..1447419e92 100644 --- a/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +++ b/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift @@ -305,9 +305,9 @@ extension CALayer { // to segments based on the `CAAnimationCalculationMode`, so we can just // check the first keyframe. if keyframes[0].isHold { - return .discrete + .discrete } else { - return .linear + .linear } } diff --git a/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift b/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift index b9f69d605c..806ff135d5 100644 --- a/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +++ b/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift @@ -280,12 +280,12 @@ extension CALayer { anchor, position, positionX, positionY, scale, rotationX, rotationY, rotationZ, skew, skewAxis -> Hold in - let transformPosition: CGPoint - if transformModel._positionX != nil, transformModel._positionY != nil { - transformPosition = CGPoint(x: positionX.cgFloatValue, y: positionY.cgFloatValue) - } else { - transformPosition = position.pointValue - } + let transformPosition: CGPoint = + if transformModel._positionX != nil, transformModel._positionY != nil { + CGPoint(x: positionX.cgFloatValue, y: positionY.cgFloatValue) + } else { + position.pointValue + } let transform = CATransform3D.makeTransform( anchor: anchor.pointValue, diff --git a/Sources/Private/CoreAnimation/CoreAnimationLayer.swift b/Sources/Private/CoreAnimation/CoreAnimationLayer.swift index e97750a037..594368dc51 100644 --- a/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +++ b/Sources/Private/CoreAnimation/CoreAnimationLayer.swift @@ -308,8 +308,8 @@ final class CoreAnimationLayer: BaseAnimationLayer { add(timedProgressAnimation, forKey: #keyPath(animationProgress)) } - // Removes the current `CAAnimation`s, and rebuilds new animations - // using the same configuration as the previous animations. + /// Removes the current `CAAnimation`s, and rebuilds new animations + /// using the same configuration as the previous animations. private func rebuildCurrentAnimation() { guard // Don't replace any pending animations that are queued to begin @@ -343,15 +343,15 @@ extension CoreAnimationLayer: RootAnimationLayer { var isAnimationPlaying: Bool? { switch pendingAnimationConfiguration?.playbackState { case .playing: - return true + true case .paused: - return false + false case nil: switch playbackState { case .playing: - return animation(forKey: #keyPath(animationProgress)) != nil + animation(forKey: #keyPath(animationProgress)) != nil case nil, .paused: - return false + false } } } diff --git a/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift b/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift index ceaefd7466..5b70c512a7 100644 --- a/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +++ b/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift @@ -320,9 +320,9 @@ extension KeyframeGroup { /// The value to use for a combined set of keyframes, for the given index fileprivate func valueForCombinedKeyframes(at index: Int) -> T { if keyframes.count == 1 { - return keyframes[0].value + keyframes[0].value } else { - return keyframes[index].value + keyframes[index].value } } } diff --git a/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift b/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift index e15ae531a2..dfd10b58af 100644 --- a/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +++ b/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift @@ -15,7 +15,7 @@ protocol AnimationLayer: CALayer { // MARK: - LayerAnimationContext -// Context describing the timing parameters of the current animation +/// Context describing the timing parameters of the current animation struct LayerAnimationContext { /// The animation being played let animation: LottieAnimation @@ -74,12 +74,12 @@ struct LayerAnimationContext { // Normal animation playback (like when looping) skips the last frame. // However when the animation is paused, we need to be able to render the final frame. // To allow this we have to extend the length of the animation by one frame. - let animationEndFrame: AnimationFrameTime - if timingConfiguration.speed == 0 { - animationEndFrame = animation.endFrame + 1 - } else { - animationEndFrame = animation.endFrame - } + let animationEndFrame: AnimationFrameTime = + if timingConfiguration.speed == 0 { + animation.endFrame + 1 + } else { + animation.endFrame + } return Double(animationEndFrame - animation.startFrame) / animation.framerate } diff --git a/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift b/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift index 23524d107b..2b3412d67f 100644 --- a/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +++ b/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift @@ -118,19 +118,19 @@ final class ShapeItemLayer: BaseAnimationLayer { // We have to build a different layer hierarchy depending on if // we're rendering a gradient (a `CAGradientLayer` masked by a `CAShapeLayer`) // or a solid shape (a simple `CAShapeLayer`). - let fillLayerConfiguration: FillLayerConfiguration - if let gradientFill = otherItems.first(GradientFill.self) { - fillLayerConfiguration = setupGradientFillLayerHierarchy(for: gradientFill) - } else { - fillLayerConfiguration = setupSolidFillLayerHierarchy() - } + let fillLayerConfiguration: FillLayerConfiguration = + if let gradientFill = otherItems.first(GradientFill.self) { + setupGradientFillLayerHierarchy(for: gradientFill) + } else { + setupSolidFillLayerHierarchy() + } - let gradientStrokeConfiguration: GradientLayers? - if let gradientStroke = otherItems.first(GradientStroke.self) { - gradientStrokeConfiguration = setupGradientStrokeLayerHierarchy(for: gradientStroke) - } else { - gradientStrokeConfiguration = nil - } + let gradientStrokeConfiguration: GradientLayers? = + if let gradientStroke = otherItems.first(GradientStroke.self) { + setupGradientStrokeLayerHierarchy(for: gradientStroke) + } else { + nil + } sublayerConfiguration = (fillLayerConfiguration, gradientStrokeConfiguration) } diff --git a/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift b/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift index 7249d39777..6a38808af9 100644 --- a/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +++ b/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift @@ -308,11 +308,11 @@ extension ShapeItem { var drawsCGPath: Bool { switch type { case .ellipse, .rectangle, .shape, .star: - return true + true case .fill, .gradientFill, .group, .gradientStroke, .merge, .repeater, .round, .stroke, .trim, .transform, .unknown: - return false + false } } @@ -320,11 +320,11 @@ extension ShapeItem { var isFill: Bool { switch type { case .fill, .gradientFill: - return true + true case .ellipse, .rectangle, .shape, .star, .group, .gradientStroke, .merge, .repeater, .round, .stroke, .trim, .transform, .unknown: - return false + false } } @@ -332,18 +332,18 @@ extension ShapeItem { var isStroke: Bool { switch type { case .stroke, .gradientStroke: - return true + true case .ellipse, .rectangle, .shape, .star, .group, .gradientFill, .merge, .repeater, .round, .fill, .trim, .transform, .unknown: - return false + false } } - // For any inherited shape items that are affected by scaling (e.g. strokes but not fills), - // any `ShapeTransform` in the given child group isn't supposed to be applied to the item. - // To cancel out the effect of the transform, we can apply an inverse transform to the - // shape item. + /// For any inherited shape items that are affected by scaling (e.g. strokes but not fills), + /// any `ShapeTransform` in the given child group isn't supposed to be applied to the item. + /// To cancel out the effect of the transform, we can apply an inverse transform to the + /// shape item. func scaledCopyForChildGroup(_ childGroup: Group, context: LayerContext) throws -> ShapeItem { guard // Path-drawing items aren't inherited by child groups in this way @@ -502,15 +502,15 @@ extension [ShapeItemLayer.Item] { // A `CAShapeLayer` can only draw a stroke on top of a fill -- if the fill is supposed to be // drawn on top of the stroke, then they have to be rendered as separate layers. - let strokeDrawnOnTopOfFill: Bool - if - let strokeIndex = strokesAndFills.firstIndex(where: { $0.item.isStroke }), - let fillIndex = strokesAndFills.firstIndex(where: { $0.item.isFill }) - { - strokeDrawnOnTopOfFill = strokeIndex < fillIndex - } else { - strokeDrawnOnTopOfFill = false - } + let strokeDrawnOnTopOfFill: Bool = + if + let strokeIndex = strokesAndFills.firstIndex(where: { $0.item.isStroke }), + let fillIndex = strokesAndFills.firstIndex(where: { $0.item.isFill }) + { + strokeIndex < fillIndex + } else { + false + } // `Fill` and `Stroke` items have an `alpha` property that can be animated separately, // but each layer only has a single `opacity` property. We can only use a single `CAShapeLayer` diff --git a/Sources/Private/CoreAnimation/ValueProviderStore.swift b/Sources/Private/CoreAnimation/ValueProviderStore.swift index 68a1432ca4..76934114bc 100644 --- a/Sources/Private/CoreAnimation/ValueProviderStore.swift +++ b/Sources/Private/CoreAnimation/ValueProviderStore.swift @@ -40,8 +40,8 @@ final class ValueProviderStore { valueProviders.append((keypath: keypath, valueProvider: valueProvider)) } - // Retrieves the custom value keyframes for the given property, - // if an `AnyValueProvider` was registered for the given keypath. + /// Retrieves the custom value keyframes for the given property, + /// if an `AnyValueProvider` was registered for the given keypath. func customKeyframes( of customizableProperty: CustomizableProperty, for keypath: AnimationKeypath, @@ -115,9 +115,9 @@ extension AnyValueProviderStorage { var isSupportedByCoreAnimationRenderingEngine: Bool { switch self { case .singleValue, .keyframes: - return true + true case .closure: - return false + false } } } diff --git a/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift b/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift index eb875c8f8a..cf39e22e9c 100644 --- a/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift +++ b/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift @@ -24,12 +24,12 @@ final class SwiftUIMeasurementContainer: ViewType { // On iOS 15 and below, passing zero can result in a constraint failure the first time a view // is displayed, but the system gracefully recovers afterwards. On iOS 16, it's fine to pass // zero. - let initialSize: CGSize - if #available(iOS 16, tvOS 16, macOS 13, *) { - initialSize = .zero - } else { - initialSize = .init(width: 375, height: 150) - } + let initialSize: CGSize = + if #available(iOS 16, tvOS 16, macOS 13, *) { + .zero + } else { + .init(width: 375, height: 150) + } super.init(frame: .init(origin: .zero, size: initialSize)) addSubview(content) @@ -180,12 +180,16 @@ final class SwiftUIMeasurementContainer: ViewType { resolved = .intrinsic(intrinsicSize) } } + case .proposed: resolved = .proposed + case .intrinsicHeightProposedWidth: resolved = .intrinsicHeightProposedWidth + case .intrinsicWidthProposedHeight: resolved = .intrinsicWidthProposedHeight + case .intrinsic: resolved = .intrinsic(content.systemLayoutFittingIntrinsicSize()) } @@ -223,12 +227,15 @@ final class SwiftUIMeasurementContainer: ViewType { case .proposed: constraints[.trailing]?.priority = .required constraints[.bottom]?.priority = .required + case .intrinsicHeightProposedWidth: constraints[.trailing]?.priority = .required constraints[.bottom]?.priority = .almostRequired + case .intrinsicWidthProposedHeight: constraints[.trailing]?.priority = .almostRequired constraints[.bottom]?.priority = .required + case .intrinsic: constraints[.trailing]?.priority = .almostRequired constraints[.bottom]?.priority = .almostRequired diff --git a/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift b/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift index 9a0e033391..771e0b4caa 100644 --- a/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift +++ b/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift @@ -216,7 +216,7 @@ extension LRUCache { // MARK: Private - // Remove container from list (must be called inside lock) + /// Remove container from list (must be called inside lock) private func remove(_ container: Container) { if head === container { head = container.next @@ -229,7 +229,7 @@ extension LRUCache { container.next = nil } - // Append container to list (must be called inside lock) + /// Append container to list (must be called inside lock) private func append(_ container: Container) { assert(container.next == nil) if head == nil { @@ -240,7 +240,7 @@ extension LRUCache { tail = container } - // Remove expired values (must be called outside lock) + /// Remove expired values (must be called outside lock) private func clean() { lock.lock() defer { lock.unlock() } diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+BackingConfiguration.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+BackingConfiguration.swift index 101b0363f3..cd9d4418ac 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+BackingConfiguration.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+BackingConfiguration.swift @@ -62,6 +62,7 @@ extension Archive { file: archiveFile, endOfCentralDirectoryRecord: eocdRecord, zip64EndOfCentralDirectory: zip64EOCD) + case .create: let endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord( numberOfDisk: 0, @@ -76,6 +77,7 @@ extension Archive { try endOfCentralDirectoryRecord.data.write(to: url, options: .withoutOverwriting) } catch { return nil } fallthrough + case .update: let fileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path) guard @@ -96,12 +98,12 @@ extension Archive { static func makeBackingConfiguration(for data: Data, mode: AccessMode) -> BackingConfiguration? { - let posixMode: String - switch mode { - case .read: posixMode = "rb" - case .create: posixMode = "wb+" - case .update: posixMode = "rb+" - } + let posixMode = + switch mode { + case .read: "rb" + case .create: "wb+" + case .update: "rb+" + } let memoryFile = MemoryFile(data: data) guard let archiveFile = memoryFile.open(mode: posixMode) else { return nil } @@ -116,6 +118,7 @@ extension Archive { endOfCentralDirectoryRecord: eocdRecord, zip64EndOfCentralDirectory: zip64EOCD, memoryFile: memoryFile) + case .create: let endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord( numberOfDisk: 0, @@ -130,6 +133,7 @@ extension Archive { fwrite(buffer.baseAddress, buffer.count, 1, archiveFile) // Errors handled during read } fallthrough + case .update: guard let (eocdRecord, zip64EOCD) = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else { return nil diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift index 28690de5fe..34fee19504 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift @@ -83,6 +83,7 @@ extension Archive { bufferSize: bufferSize, progress: progress, provider: provider) + case .deflate: (sizeWritten, checksum) = try writeCompressed( size: uncompressedSize, @@ -90,9 +91,11 @@ extension Archive { progress: progress, provider: provider) } + case .directory: _ = try provider(0, 0) if let progress { progress.completedUnitCount = progress.totalUnitCount } + case .symlink: let (linkSizeWritten, linkChecksum) = try writeSymbolicLink( size: Int(uncompressedSize), @@ -226,6 +229,7 @@ extension Archive { throw ArchiveError.invalidCentralDirectoryEntryCount } return (sizeOfCD + UInt64(cdDataLengthChange), numberOfTotalEntries + UInt64(countChange)) + case .remove: return (sizeOfCD - UInt64(-cdDataLengthChange), numberOfTotalEntries - UInt64(-countChange)) } diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Progress.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Progress.swift index f8c3bd69cb..a55d5d18f8 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Progress.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Progress.swift @@ -32,9 +32,9 @@ extension Archive { func totalUnitCountForReading(_ entry: Entry) -> Int64 { switch entry.type { case .file, .symlink: - return Int64(entry.uncompressedSize) + Int64(entry.uncompressedSize) case .directory: - return defaultDirectoryUnitCount + defaultDirectoryUnitCount } } diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Reading.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Reading.swift index cf5510dc7e..1d00eba8e8 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Reading.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Reading.swift @@ -52,6 +52,7 @@ extension Archive { skipCRC32: skipCRC32, progress: progress, consumer: consumer) + case .directory: let consumer = { (_: Data) in try fileManager.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil) @@ -62,6 +63,7 @@ extension Archive { skipCRC32: skipCRC32, progress: progress, consumer: consumer) + case .symlink: guard !fileManager.itemExists(at: url) else { throw CocoaError(.fileWriteFileExists, userInfo: [NSFilePathErrorKey: url.path]) @@ -121,6 +123,7 @@ extension Archive { skipCRC32: skipCRC32, progress: progress, with: consumer) + case .deflate: checksum = try readCompressed( entry: entry, bufferSize: bufferSize, @@ -128,9 +131,11 @@ extension Archive { progress: progress, with: consumer) } + case .directory: try consumer(Data()) progress?.completedUnitCount = totalUnitCountForReading(entry) + case .symlink: let localFileHeader = entry.localFileHeader let size = Int(localFileHeader.compressedSize) diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Writing.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Writing.swift index 8006439470..dd5bef5a7a 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Writing.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Writing.swift @@ -96,6 +96,7 @@ extension Archive { bufferSize: bufferSize, progress: progress, provider: provider) + case .directory: provider = { _, _ in Data() } try addEntry( @@ -108,6 +109,7 @@ extension Archive { bufferSize: bufferSize, progress: progress, provider: provider) + case .symlink: provider = { _, _ -> Data in let linkDestination = try fileManager.destinationOfSymbolicLink(atPath: fileURL.path) diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift index 065661696a..db9b73dd1c 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift @@ -169,6 +169,7 @@ extension Data { if operation == COMPRESSION_STREAM_DECODE, !skipCRC32 { crc32 = outputData.crc32(checksum: crc32) } stream.dst_ptr = destPointer stream.dst_size = bufferSize + default: throw CompressionError.corruptedData } } while status == COMPRESSION_STATUS_OK diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Entry+ZIP64.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Entry+ZIP64.swift index f763a21891..bbebc91f82 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Entry+ZIP64.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Entry+ZIP64.swift @@ -121,9 +121,9 @@ extension Entry.ZIP64ExtendedInformation { var size: Int { switch self { case .uncompressedSize, .compressedSize, .relativeOffsetOfLocalHeader: - return 8 + 8 case .diskNumberStart: - return 4 + 4 } } } diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Entry.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Entry.swift index d8514530fa..c152192585 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Entry.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Entry.swift @@ -185,6 +185,7 @@ struct Entry: Equatable { default: return isDirectory ? .directory : .file } + case .msdos: isDirectory = isDirectory || ((centralDirectoryStructure.externalFileAttributes >> 4) == 0x01) fallthrough // For all other OSes we can only guess based on the directory suffix char diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift index 69ea55e163..e297da7f9c 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift @@ -44,21 +44,22 @@ extension FileManager { let permissions = mode_t(externalFileAttributes >> 16) & ~S_IFMT let defaultPermissions = entryType == .directory ? defaultDirectoryPermissions : defaultFilePermissions return permissions == 0 ? defaultPermissions : UInt16(permissions) + default: return entryType == .directory ? defaultDirectoryPermissions : defaultFilePermissions } } class func externalFileAttributesForEntry(of type: Entry.EntryType, permissions: UInt16) -> UInt32 { - var typeInt: UInt16 - switch type { - case .file: - typeInt = UInt16(S_IFREG) - case .directory: - typeInt = UInt16(S_IFDIR) - case .symlink: - typeInt = UInt16(S_IFLNK) - } + let typeInt = + switch type { + case .file: + UInt16(S_IFREG) + case .directory: + UInt16(S_IFDIR) + case .symlink: + UInt16(S_IFLNK) + } var externalFileAttributes = UInt32(typeInt | UInt16(permissions)) externalFileAttributes = (externalFileAttributes << 16) return externalFileAttributes diff --git a/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift b/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift index d1182dbaff..bfab6ea50c 100644 --- a/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift @@ -11,19 +11,19 @@ extension MaskMode { var usableMode: MaskMode { switch self { case .add: - return .add + .add case .subtract: - return .subtract + .subtract case .intersect: - return .intersect + .intersect case .lighten: - return .add + .add case .darken: - return .darken + .darken case .difference: - return .intersect + .intersect case .none: - return .none + .none } } } diff --git a/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift b/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift index f26a51cfce..ce31ba3bee 100644 --- a/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift @@ -16,22 +16,22 @@ extension TextJustification { var textAlignment: NSTextAlignment { switch self { case .left: - return .left + .left case .right: - return .right + .right case .center: - return .center + .center } } var caTextAlignement: CATextLayerAlignmentMode { switch self { case .left: - return .left + .left case .right: - return .right + .right case .center: - return .center + .center } } } @@ -121,14 +121,14 @@ final class TextCompositionLayer: CompositionLayer { // Prior to Lottie 4.3.0 the Main Thread rendering engine always just used `LegacyAnimationTextProvider` // and called it with the `keypathName` (only the last path component of the full keypath). // Starting in Lottie 4.3.0 we use `AnimationKeypathTextProvider` instead if implemented. - let textString: String - if let keypathTextValue = textProvider.text(for: fullAnimationKeypath, sourceText: text.text) { - textString = keypathTextValue - } else if let legacyTextProvider = textProvider as? LegacyAnimationTextProvider { - textString = legacyTextProvider.textFor(keypathName: keypathName, sourceText: text.text) - } else { - textString = text.text - } + let textString: String = + if let keypathTextValue = textProvider.text(for: fullAnimationKeypath, sourceText: text.text) { + keypathTextValue + } else if let legacyTextProvider = textProvider as? LegacyAnimationTextProvider { + legacyTextProvider.textFor(keypathName: keypathName, sourceText: text.text) + } else { + text.text + } let strokeColor = rootNode?.textOutputNode.strokeColor ?? text.strokeColorData?.cgColorValue let strokeWidth = rootNode?.textOutputNode.strokeWidth ?? CGFloat(text.strokeWidth ?? 0) diff --git a/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift b/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift index c62b53c4b9..75fdd4f9f7 100644 --- a/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift @@ -127,16 +127,16 @@ final class MainThreadAnimationLayer: CALayer, RootAnimationLayer { public override func display() { guard Thread.isMainThread else { return } - var newFrame: CGFloat - if - let animationKeys = animationKeys(), - !animationKeys.isEmpty - { - newFrame = presentation()?.currentFrame ?? currentFrame - } else { - // We ignore the presentation's frame if there's no animation in the layer. - newFrame = currentFrame - } + var newFrame: CGFloat = + if + let animationKeys = animationKeys(), + !animationKeys.isEmpty + { + presentation()?.currentFrame ?? currentFrame + } else { + // We ignore the presentation's frame if there's no animation in the layer. + currentFrame + } if respectAnimationFrameRate { newFrame = floor(newFrame) } diff --git a/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift b/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift index e485d4b0fc..cacba1657a 100644 --- a/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift @@ -137,19 +137,19 @@ final class CoreTextRenderLayer: CALayer { let drawingPath = CGPath(rect: drawingRect, transform: nil) - let fillFrame: CTFrame? - if let setter = fillFrameSetter { - fillFrame = CTFramesetterCreateFrame(setter, CFRangeMake(0, attributedString.length), drawingPath, nil) - } else { - fillFrame = nil - } + let fillFrame: CTFrame? = + if let setter = fillFrameSetter { + CTFramesetterCreateFrame(setter, CFRangeMake(0, attributedString.length), drawingPath, nil) + } else { + nil + } - let strokeFrame: CTFrame? - if let setter = strokeFrameSetter { - strokeFrame = CTFramesetterCreateFrame(setter, CFRangeMake(0, attributedString.length), drawingPath, nil) - } else { - strokeFrame = nil - } + let strokeFrame: CTFrame? = + if let setter = strokeFrameSetter { + CTFramesetterCreateFrame(setter, CFRangeMake(0, attributedString.length), drawingPath, nil) + } else { + nil + } // This fixes a vertical padding issue that arises when drawing some fonts. // For some reason some fonts, such as Helvetica draw with and ascender that is greater than the one reported by CTFontGetAscender. @@ -183,7 +183,7 @@ final class CoreTextRenderLayer: CALayer { private var strokeFrameSetter: CTFramesetter? private var needsContentUpdate = false - // Draws Debug colors for the font alignment. + /// Draws Debug colors for the font alignment. private func drawDebug(_ ctx: CGContext) { if let font { let ascent = CTFontGetAscent(font) diff --git a/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift b/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift index 7ef739afe8..fc5d2dae90 100644 --- a/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +++ b/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift @@ -119,17 +119,17 @@ class LayerTransformNode: AnimatorNode { func rebuildOutputs(frame _: CGFloat) { opacity = Float(transformProperties.opacity.value.cgFloatValue) * 0.01 - let position: CGPoint - if let point = transformProperties.position?.value.pointValue { - position = point - } else if - let xPos = transformProperties.positionX?.value.cgFloatValue, - let yPos = transformProperties.positionY?.value.cgFloatValue - { - position = CGPoint(x: xPos, y: yPos) - } else { - position = .zero - } + let position: CGPoint = + if let point = transformProperties.position?.value.pointValue { + point + } else if + let xPos = transformProperties.positionX?.value.cgFloatValue, + let yPos = transformProperties.positionY?.value.cgFloatValue + { + CGPoint(x: xPos, y: yPos) + } else { + .zero + } localTransform = CATransform3D.makeTransform( anchor: transformProperties.anchor.value.pointValue, diff --git a/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift b/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift index 24f7930be2..53b9d3a770 100644 --- a/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift +++ b/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift @@ -49,10 +49,12 @@ extension [ShapeItem] { switch star.starType { case .none: continue + case .polygon: let node = PolygonNode(parentNode: nodeTree.rootNode, star: star) nodeTree.rootNode = node nodeTree.childrenNodes.append(node) + case .star: let node = StarNode(parentNode: nodeTree.rootNode, star: star) nodeTree.rootNode = node diff --git a/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift b/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift index 44218df650..c858909a9d 100644 --- a/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift +++ b/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift @@ -11,18 +11,18 @@ extension FillRule { var cgFillRule: CGPathFillRule { switch self { case .evenOdd: - return .evenOdd + .evenOdd default: - return .winding + .winding } } var caFillRule: CAShapeLayerFillRule { switch self { case .evenOdd: - return CAShapeLayerFillRule.evenOdd + CAShapeLayerFillRule.evenOdd default: - return CAShapeLayerFillRule.nonZero + CAShapeLayerFillRule.nonZero } } } diff --git a/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift b/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift index 342c5709c2..2e400e43e5 100644 --- a/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +++ b/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift @@ -11,26 +11,26 @@ extension LineJoin { var cgLineJoin: CGLineJoin { switch self { case .bevel: - return .bevel + .bevel case .none: - return .miter + .miter case .miter: - return .miter + .miter case .round: - return .round + .round } } var caLineJoin: CAShapeLayerLineJoin { switch self { case .none: - return CAShapeLayerLineJoin.miter + CAShapeLayerLineJoin.miter case .miter: - return CAShapeLayerLineJoin.miter + CAShapeLayerLineJoin.miter case .round: - return CAShapeLayerLineJoin.round + CAShapeLayerLineJoin.round case .bevel: - return CAShapeLayerLineJoin.bevel + CAShapeLayerLineJoin.bevel } } } @@ -39,26 +39,26 @@ extension LineCap { var cgLineCap: CGLineCap { switch self { case .none: - return .butt + .butt case .butt: - return .butt + .butt case .round: - return .round + .round case .square: - return .square + .square } } var caLineCap: CAShapeLayerLineCap { switch self { case .none: - return CAShapeLayerLineCap.butt + CAShapeLayerLineCap.butt case .butt: - return CAShapeLayerLineCap.butt + CAShapeLayerLineCap.butt case .round: - return CAShapeLayerLineCap.round + CAShapeLayerLineCap.round case .square: - return CAShapeLayerLineCap.square + CAShapeLayerLineCap.square } } } diff --git a/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift b/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift index ba8aaf490d..49e502b9c4 100644 --- a/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +++ b/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift @@ -122,7 +122,7 @@ extension BezierPath { var vertices = [CurveVertex(point: point + position, inTangentRelative: .zero, outTangentRelative: .zero)] var previousPoint = point - currentAngle += anglePerPoint; + currentAngle += anglePerPoint for _ in 0..(value)] } else { - var frameDictionaries: [[String: Any]] - if let singleFrameDictionary = dictionary[KeyframeWrapperKey.keyframeData.rawValue] as? [String: Any] { - frameDictionaries = [singleFrameDictionary] - } else { - frameDictionaries = try dictionary.value(for: KeyframeWrapperKey.keyframeData) - } + let frameDictionaries: [[String: Any]] = + if + let singleFrameDictionary = + dictionary[KeyframeWrapperKey.keyframeData.rawValue] as? [String: Any] + { + [singleFrameDictionary] + } else { + try dictionary.value(for: KeyframeWrapperKey.keyframeData) + } var previousKeyframeData: KeyframeData? for frameDictionary in frameDictionaries { let data = try KeyframeData(dictionary: frameDictionary) diff --git a/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift b/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift index 8cae5e599e..4f154f52c9 100644 --- a/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift +++ b/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift @@ -23,14 +23,14 @@ extension EffectValueType: ClassFamily { func getType() -> AnyObject.Type { switch self { case .slider: - return Vector1DEffectValue.self + Vector1DEffectValue.self case .angle: - return Vector1DEffectValue.self + Vector1DEffectValue.self case .color: - return ColorEffectValue.self + ColorEffectValue.self case .unknown: // Unsupported - return LayerEffect.self + LayerEffect.self } } } diff --git a/Sources/Private/Model/LayerEffects/LayerEffect.swift b/Sources/Private/Model/LayerEffects/LayerEffect.swift index 9bb8c27c05..654acfc2fc 100644 --- a/Sources/Private/Model/LayerEffects/LayerEffect.swift +++ b/Sources/Private/Model/LayerEffects/LayerEffect.swift @@ -21,10 +21,10 @@ extension LayerEffectType: ClassFamily { func getType() -> AnyObject.Type { switch self { case .dropShadow: - return DropShadowEffect.self + DropShadowEffect.self case .unknown: // Unsupported - return LayerEffect.self + LayerEffect.self } } } diff --git a/Sources/Private/Model/LayerStyles/LayerStyle.swift b/Sources/Private/Model/LayerStyles/LayerStyle.swift index b6ef1c32d4..70d28a5d5a 100644 --- a/Sources/Private/Model/LayerStyles/LayerStyle.swift +++ b/Sources/Private/Model/LayerStyles/LayerStyle.swift @@ -20,10 +20,10 @@ extension LayerStyleType: ClassFamily { func getType() -> AnyObject.Type { switch self { case .dropShadow: - return DropShadowStyle.self + DropShadowStyle.self case .unknown: // Unsupported - return LayerStyle.self + LayerStyle.self } } } diff --git a/Sources/Private/Model/Layers/LayerModel.swift b/Sources/Private/Model/Layers/LayerModel.swift index 836c09a197..e2e3e38888 100644 --- a/Sources/Private/Model/Layers/LayerModel.swift +++ b/Sources/Private/Model/Layers/LayerModel.swift @@ -14,19 +14,19 @@ extension LayerType: ClassFamily { func getType() -> AnyObject.Type { switch self { case .precomp: - return PreCompLayerModel.self + PreCompLayerModel.self case .solid: - return SolidLayerModel.self + SolidLayerModel.self case .image: - return ImageLayerModel.self + ImageLayerModel.self case .null: - return LayerModel.self + LayerModel.self case .shape: - return ShapeLayerModel.self + ShapeLayerModel.self case .text: - return TextLayerModel.self + TextLayerModel.self case .unknown: - return LayerModel.self + LayerModel.self } } } diff --git a/Sources/Private/Model/ShapeItems/ShapeItem.swift b/Sources/Private/Model/ShapeItems/ShapeItem.swift index 5911a69147..f058100600 100644 --- a/Sources/Private/Model/ShapeItems/ShapeItem.swift +++ b/Sources/Private/Model/ShapeItems/ShapeItem.swift @@ -38,35 +38,35 @@ extension ShapeType: ClassFamily { func getType() -> AnyObject.Type { switch self { case .ellipse: - return Ellipse.self + Ellipse.self case .fill: - return Fill.self + Fill.self case .gradientFill: - return GradientFill.self + GradientFill.self case .group: - return Group.self + Group.self case .gradientStroke: - return GradientStroke.self + GradientStroke.self case .merge: - return Merge.self + Merge.self case .rectangle: - return Rectangle.self + Rectangle.self case .repeater: - return Repeater.self + Repeater.self case .round: - return RoundedCorners.self + RoundedCorners.self case .shape: - return Shape.self + Shape.self case .star: - return Star.self + Star.self case .stroke: - return Stroke.self + Stroke.self case .trim: - return Trim.self + Trim.self case .transform: - return ShapeTransform.self + ShapeTransform.self default: - return ShapeItem.self + ShapeItem.self } } } diff --git a/Sources/Private/Utility/Debugging/LayerDebugging.swift b/Sources/Private/Utility/Debugging/LayerDebugging.swift index 5081ee985d..601ec870f7 100644 --- a/Sources/Private/Utility/Debugging/LayerDebugging.swift +++ b/Sources/Private/Utility/Debugging/LayerDebugging.swift @@ -95,12 +95,12 @@ extension CALayer { } if visible { - let style: LayerDebugStyle - if let layerDebugging = self as? LayerDebugging { - style = layerDebugging.debugStyle - } else { - style = LayerDebugStyle.defaultStyle() - } + let style: LayerDebugStyle = + if let layerDebugging = self as? LayerDebugging { + layerDebugging.debugStyle + } else { + LayerDebugStyle.defaultStyle() + } let debugLayer = DebugLayer(style: style) var container = self if let cust = self as? CustomLayerDebugging { diff --git a/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift b/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift index 669c8e600e..f79920e3e6 100644 --- a/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +++ b/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift @@ -124,12 +124,12 @@ extension KeypathSearchable { func allKeypaths(for keyPath: AnimationKeypath? = nil) -> [String] { var allKeypaths: [String] = [] - let newKeypath: AnimationKeypath - if let previousKeypath = keyPath { - newKeypath = previousKeypath.appendingKey(keypathName) - } else { - newKeypath = AnimationKeypath(keys: [keypathName]) - } + let newKeypath: AnimationKeypath = + if let previousKeypath = keyPath { + previousKeypath.appendingKey(keypathName) + } else { + AnimationKeypath(keys: [keypathName]) + } allKeypaths.append(newKeypath.fullPath) @@ -148,12 +148,12 @@ extension KeypathSearchable { func layerKeypaths(for keyPath: AnimationKeypath? = nil) -> [CALayer: AnimationKeypath] { var allKeypaths: [CALayer: AnimationKeypath] = [:] - let newKeypath: AnimationKeypath - if let previousKeypath = keyPath { - newKeypath = previousKeypath.appendingKey(keypathName) - } else { - newKeypath = AnimationKeypath(keys: [keypathName]) - } + let newKeypath: AnimationKeypath = + if let previousKeypath = keyPath { + previousKeypath.appendingKey(keypathName) + } else { + AnimationKeypath(keys: [keypathName]) + } if let layer = self as? CALayer { allKeypaths[layer] = newKeypath @@ -197,7 +197,7 @@ extension AnimationKeypath { keys.joined(separator: ".") } - // Pops the top keypath from the stack if the keyname matches. + /// Pops the top keypath from the stack if the keyname matches. func popKey(_ keyname: String) -> AnimationKeypath? { guard let currentKey, @@ -245,11 +245,11 @@ extension String { var keyPathType: KeyType { switch self { case "*": - return .wildcard + .wildcard case "**": - return .fuzzyWildcard + .fuzzyWildcard default: - return .specific + .specific } } diff --git a/Sources/Private/Utility/Extensions/BlendMode+Filter.swift b/Sources/Private/Utility/Extensions/BlendMode+Filter.swift index ef93a39c25..2d7ad22167 100644 --- a/Sources/Private/Utility/Extensions/BlendMode+Filter.swift +++ b/Sources/Private/Utility/Extensions/BlendMode+Filter.swift @@ -10,22 +10,22 @@ extension BlendMode { /// Supported compositing filters are defined here: https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html#//apple_ref/doc/uid/TP30000136-SW71 var filterName: String? { switch self { - case .normal: return nil - case .multiply: return "multiplyBlendMode" - case .screen: return "screenBlendMode" - case .overlay: return "overlayBlendMode" - case .darken: return "darkenBlendMode" - case .lighten: return "lightenBlendMode" - case .colorDodge: return "colorDodgeBlendMode" - case .colorBurn: return "colorBurnBlendMode" - case .hardLight: return "hardLightBlendMode" - case .softLight: return "softLightBlendMode" - case .difference: return "differenceBlendMode" - case .exclusion: return "exclusionBlendMode" - case .hue: return "hueBlendMode" - case .saturation: return "saturationBlendMode" - case .color: return "colorBlendMode" - case .luminosity: return "luminosityBlendMode" + case .normal: nil + case .multiply: "multiplyBlendMode" + case .screen: "screenBlendMode" + case .overlay: "overlayBlendMode" + case .darken: "darkenBlendMode" + case .lighten: "lightenBlendMode" + case .colorDodge: "colorDodgeBlendMode" + case .colorBurn: "colorBurnBlendMode" + case .hardLight: "hardLightBlendMode" + case .softLight: "softLightBlendMode" + case .difference: "differenceBlendMode" + case .exclusion: "exclusionBlendMode" + case .hue: "hueBlendMode" + case .saturation: "saturationBlendMode" + case .color: "colorBlendMode" + case .luminosity: "luminosityBlendMode" } } } diff --git a/Sources/Private/Utility/Extensions/CGFloatExtensions.swift b/Sources/Private/Utility/Extensions/CGFloatExtensions.swift index 015a10ce45..28f0e29bf3 100644 --- a/Sources/Private/Utility/Extensions/CGFloatExtensions.swift +++ b/Sources/Private/Utility/Extensions/CGFloatExtensions.swift @@ -41,19 +41,19 @@ extension CGFloat { t = 1 } else { // Calculate t - let a = -P0.x + 3 * P1.x - 3 * P2.x + P3.x; - let b = 3 * P0.x - 6 * P1.x + 3 * P2.x; - let c = -3 * P0.x + 3 * P1.x; - let d = P0.x - self; - let tTemp = CGFloat.SolveCubic(a, b, c, d); + let a = -P0.x + 3 * P1.x - 3 * P2.x + P3.x + let b = 3 * P0.x - 6 * P1.x + 3 * P2.x + let c = -3 * P0.x + 3 * P1.x + let d = P0.x - self + let tTemp = CGFloat.SolveCubic(a, b, c, d) if tTemp == -1 { - return -1; + return -1 } t = tTemp } // Calculate y from t - return (1 - t).cubed * P0.y + 3 * t * (1 - t).squared * P1.y + 3 * t.squared * (1 - t) * P2.y + t.cubed * P3.y; + return (1 - t).cubed * P0.y + 3 * t * (1 - t).squared * P1.y + 3 * t.squared * (1 - t) * P2.y + t.cubed * P3.y } func cubicBezier(_ t: CGFloat, _ c1: CGFloat, _ c2: CGFloat, _ end: CGFloat) -> CGFloat { @@ -66,23 +66,23 @@ extension CGFloat { return self * ttt_ + 3.0 * c1 * tt_ * t + 3.0 * c2 * t_ * tt - + end * ttt; + + end * ttt } // MARK: Fileprivate fileprivate static func SolveQuadratic(_ a: CGFloat, _ b: CGFloat, _ c: CGFloat) -> CGFloat { - var result = (-b + sqrt(b.squared - 4 * a * c)) / (2 * a); + var result = (-b + sqrt(b.squared - 4 * a * c)) / (2 * a) guard !result.isInRangeOrEqual(0, 1) else { return result } - result = (-b - sqrt(b.squared - 4 * a * c)) / (2 * a); + result = (-b - sqrt(b.squared - 4 * a * c)) / (2 * a) guard !result.isInRangeOrEqual(0, 1) else { return result } - return -1; + return -1 } fileprivate static func SolveCubic(_ a: CGFloat, _ b: CGFloat, _ c: CGFloat, _ d: CGFloat) -> CGFloat { @@ -110,43 +110,43 @@ extension CGFloat { var t = r - sqrt(disc) t = (t < 0) ? -((-t).cubicRoot) : t.cubicRoot - let result = -term1 + s + t; + let result = -term1 + s + t if result.isInRangeOrEqual(0, 1) { return result } } else if disc == 0 { - let r13 = (r < 0) ? -((-r).cubicRoot) : r.cubicRoot; + let r13 = (r < 0) ? -((-r).cubicRoot) : r.cubicRoot - var result = -term1 + 2.0 * r13; + var result = -term1 + 2.0 * r13 if result.isInRangeOrEqual(0, 1) { return result } - result = -(r13 + term1); + result = -(r13 + term1) if result.isInRangeOrEqual(0, 1) { return result } } else { - q = -q; - var dum1 = q * q * q; - dum1 = acos(r / sqrt(dum1)); - let r13 = 2.0 * sqrt(q); + q = -q + var dum1 = q * q * q + dum1 = acos(r / sqrt(dum1)) + let r13 = 2.0 * sqrt(q) - var result = -term1 + r13 * cos(dum1 / 3.0); + var result = -term1 + r13 * cos(dum1 / 3.0) if result.isInRangeOrEqual(0, 1) { return result } - result = -term1 + r13 * cos((dum1 + 2.0 * .pi) / 3.0); + result = -term1 + r13 * cos((dum1 + 2.0 * .pi) / 3.0) if result.isInRangeOrEqual(0, 1) { return result } - result = -term1 + r13 * cos((dum1 + 4.0 * .pi) / 3.0); + result = -term1 + r13 * cos((dum1 + 4.0 * .pi) / 3.0) if result.isInRangeOrEqual(0, 1) { return result } } - return -1; + return -1 } } diff --git a/Sources/Private/Utility/Extensions/MathKit.swift b/Sources/Private/Utility/Extensions/MathKit.swift index 7886aa532f..1be2ffbd0f 100644 --- a/Sources/Private/Utility/Extensions/MathKit.swift +++ b/Sources/Private/Utility/Extensions/MathKit.swift @@ -426,7 +426,7 @@ extension CGPoint { } func colinear(_ a: CGPoint, _ b: CGPoint) -> Bool { - let area = x * (a.y - b.y) + a.x * (b.y - y) + b.x * (y - a.y); + let area = x * (a.y - b.y) + a.x * (b.y - y) + b.x * (y - a.y) let accuracy: CGFloat = 0.05 if area < accuracy, area > -accuracy { return true diff --git a/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift b/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift index b390b56a5e..7c7fc8b13c 100644 --- a/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift +++ b/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift @@ -16,7 +16,7 @@ extension LottieColor { init(h: Double, s: Double, v: Double, a: Double) { let i = floor(h * 6) let f = h * 6 - i - let p = v * (1 - s); + let p = v * (1 - s) let q = v * (1 - f * s) let t = v * (1 - (1 - f) * s) @@ -25,26 +25,32 @@ extension LottieColor { r = v g = t b = p + case 1: r = q g = v b = p + case 2: r = p g = v b = t + case 3: r = p g = q b = v + case 4: r = t g = p b = v + case 5: r = v g = p b = q + default: r = 0 g = 0 @@ -71,10 +77,10 @@ extension LottieColor { var h: Double, s: Double, v: Double = maxValue let d = maxValue - minValue - s = maxValue == 0 ? 0 : d / maxValue; + s = maxValue == 0 ? 0 : d / maxValue if maxValue == minValue { - h = 0; // achromatic + h = 0 // achromatic } else { switch maxValue { case r: h = (g - b) / d + (g < b ? 6 : 0) diff --git a/Sources/Private/Utility/LottieAnimationSource.swift b/Sources/Private/Utility/LottieAnimationSource.swift index 167483485b..1e96491512 100644 --- a/Sources/Private/Utility/LottieAnimationSource.swift +++ b/Sources/Private/Utility/LottieAnimationSource.swift @@ -19,9 +19,9 @@ extension LottieAnimationSource { var animation: LottieAnimation? { switch self { case .lottieAnimation(let animation): - return animation + animation case .dotLottieFile: - return dotLottieAnimation?.animation + dotLottieAnimation?.animation } } @@ -29,9 +29,9 @@ extension LottieAnimationSource { var dotLottieAnimation: DotLottieFile.Animation? { switch self { case .lottieAnimation: - return nil + nil case .dotLottieFile(let dotLottieFile): - return dotLottieFile.animation() + dotLottieFile.animation() } } } diff --git a/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift b/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift index 01c5d5ee6c..7a0c1186df 100644 --- a/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +++ b/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift @@ -30,7 +30,7 @@ import Foundation // shape's vertex distances and the roundedness set in the animation. extension CompoundBezierPath { - // Round corners of a compound bezier + /// Round corners of a compound bezier func roundCorners(radius: CGFloat) -> CompoundBezierPath { var newPaths = [BezierPath]() for path in paths { @@ -43,7 +43,7 @@ extension CompoundBezierPath { } extension BezierPath { - // Computes a new `BezierPath` with each corner rounded based on the given `radius` + /// Computes a new `BezierPath` with each corner rounded based on the given `radius` func roundCorners(radius: CGFloat) -> BezierPath { var newPath = BezierPath() var uniquePath = BezierPath() diff --git a/Sources/Private/Utility/Primitives/ColorExtension.swift b/Sources/Private/Utility/Primitives/ColorExtension.swift index 286f0d9347..4fe60b1a06 100644 --- a/Sources/Private/Utility/Primitives/ColorExtension.swift +++ b/Sources/Private/Utility/Primitives/ColorExtension.swift @@ -16,26 +16,26 @@ extension LottieColor: Codable { public init(from decoder: Decoder) throws { var container = try decoder.unkeyedContainer() - var r1: Double - if !container.isAtEnd { - r1 = try container.decode(Double.self) - } else { - r1 = 0 - } - - var g1: Double - if !container.isAtEnd { - g1 = try container.decode(Double.self) - } else { - g1 = 0 - } - - var b1: Double - if !container.isAtEnd { - b1 = try container.decode(Double.self) - } else { - b1 = 0 - } + var r1: Double = + if !container.isAtEnd { + try container.decode(Double.self) + } else { + 0 + } + + var g1: Double = + if !container.isAtEnd { + try container.decode(Double.self) + } else { + 0 + } + + var b1: Double = + if !container.isAtEnd { + try container.decode(Double.self) + } else { + 0 + } if r1 > 1, g1 > 1, b1 > 1 { r1 = r1 / 255 diff --git a/Sources/Private/Utility/Primitives/CompoundBezierPath.swift b/Sources/Private/Utility/Primitives/CompoundBezierPath.swift index 14e465d665..b0aa268aa4 100644 --- a/Sources/Private/Utility/Primitives/CompoundBezierPath.swift +++ b/Sources/Private/Utility/Primitives/CompoundBezierPath.swift @@ -101,15 +101,15 @@ struct CompoundBezierPath { return self } - var positions: [(start: CGFloat, end: CGFloat)] - if endPosition < startPosition { - positions = [ - (start: 0, end: endPosition * length), - (start: startPosition * length, end: length), - ] - } else { - positions = [(start: startPosition * length, end: endPosition * length)] - } + var positions: [(start: CGFloat, end: CGFloat)] = + if endPosition < startPosition { + [ + (start: 0, end: endPosition * length), + (start: startPosition * length, end: length), + ] + } else { + [(start: startPosition * length, end: endPosition * length)] + } var compoundPath = CompoundBezierPath() var trim = positions.remove(at: 0) diff --git a/Sources/Public/Animation/LottieAnimationLayer.swift b/Sources/Public/Animation/LottieAnimationLayer.swift index 8126d419e2..e686665995 100644 --- a/Sources/Public/Animation/LottieAnimationLayer.swift +++ b/Sources/Public/Animation/LottieAnimationLayer.swift @@ -237,12 +237,12 @@ public class LottieAnimationLayer: CALayer { self.loopMode = loopMode } - let fromTime: CGFloat - if let fromName = fromMarker, let from = markers[fromName] { - fromTime = CGFloat(from.frameTime) - } else { - fromTime = currentFrame - } + let fromTime: CGFloat = + if let fromName = fromMarker, let from = markers[fromName] { + CGFloat(from.frameTime) + } else { + currentFrame + } let playTo = playEndMarkerFrame ? CGFloat(to.frameTime) : CGFloat(to.frameTime) - 1 let context = AnimationContext( @@ -339,7 +339,7 @@ public class LottieAnimationLayer: CALayer { // If we don't have any more markers to play, then the marker sequence has completed. completion?(completed) } else { - self.play(markers: followingMarkers, completion: completion) + play(markers: followingMarkers, completion: completion) } }) } @@ -370,6 +370,7 @@ public class LottieAnimationLayer: CALayer { case .frame(let animationFrameTime): currentFrame = animationFrameTime + case .time(let timeInterval): currentTime = timeInterval @@ -670,9 +671,9 @@ public class LottieAnimationLayer: CALayer { } get { if let animation { - return animation.progressTime(forFrame: currentFrame) + animation.progressTime(forFrame: currentFrame) } else { - return 0 + 0 } } } @@ -692,9 +693,9 @@ public class LottieAnimationLayer: CALayer { } get { if let animation { - return animation.time(forFrame: currentFrame) + animation.time(forFrame: currentFrame) } else { - return 0 + 0 } } } @@ -992,16 +993,20 @@ public class LottieAnimationLayer: CALayer { case .stop: removeCurrentAnimation() updateAnimationFrame(currentContext.playFrom) + case .pause: removeCurrentAnimation() + case .pauseAndRestore: currentContext.closure.ignoreDelegate = true removeCurrentAnimation() /// Keep the stale context around for when the app enters the foreground. animationContext = currentContext + case .forceFinish: removeCurrentAnimation() updateAnimationFrame(currentContext.playTo) + case .continuePlaying: break } @@ -1117,9 +1122,9 @@ public class LottieAnimationLayer: CALayer { fileprivate var activeAnimationName: String { switch rootAnimationLayer?.primaryAnimationKey { case .specific(let animationKey): - return animationKey + animationKey case .managed, nil: - return _activeAnimationName + _activeAnimationName } } @@ -1148,15 +1153,15 @@ public class LottieAnimationLayer: CALayer { guard let animation else { return } - let rootAnimationLayer: RootAnimationLayer? - switch renderingEngine { - case .automatic: - rootAnimationLayer = makeAutomaticEngineLayer(for: animation) - case .specific(.coreAnimation): - rootAnimationLayer = makeCoreAnimationLayer(for: animation) - case .specific(.mainThread): - rootAnimationLayer = makeMainThreadAnimationLayer(for: animation) - } + let rootAnimationLayer: RootAnimationLayer? = + switch renderingEngine { + case .automatic: + makeAutomaticEngineLayer(for: animation) + case .specific(.coreAnimation): + makeCoreAnimationLayer(for: animation) + case .specific(.mainThread): + makeMainThreadAnimationLayer(for: animation) + } guard let animationLayer = rootAnimationLayer else { return @@ -1259,8 +1264,8 @@ public class LottieAnimationLayer: CALayer { } } - // Handles any compatibility issues with the Core Animation engine - // by falling back to the Main Thread engine + /// Handles any compatibility issues with the Core Animation engine + /// by falling back to the Main Thread engine fileprivate func automaticEngineLayerDidSetUpAnimation(_ compatibilityIssues: [CompatibilityIssue]) { // If there weren't any compatibility issues, then there's nothing else to do if compatibilityIssues.isEmpty { @@ -1462,9 +1467,9 @@ public class LottieAnimationLayer: CALayer { private var reducedMotionMarker: Marker? { switch configuration.reducedMotionOption.currentReducedMotionMode { case .standardMotion: - return nil + nil case .reducedMotion: - return animation?.reducedMotionMarker + animation?.reducedMotionMarker } } @@ -1503,15 +1508,15 @@ extension LottieLoopMode { var caAnimationConfiguration: (repeatCount: Float, autoreverses: Bool) { switch self { case .playOnce: - return (repeatCount: 1, autoreverses: false) + (repeatCount: 1, autoreverses: false) case .loop: - return (repeatCount: .greatestFiniteMagnitude, autoreverses: false) + (repeatCount: .greatestFiniteMagnitude, autoreverses: false) case .autoReverse: - return (repeatCount: .greatestFiniteMagnitude, autoreverses: true) + (repeatCount: .greatestFiniteMagnitude, autoreverses: true) case .repeat(let amount): - return (repeatCount: amount, autoreverses: false) + (repeatCount: amount, autoreverses: false) case .repeatBackwards(let amount): - return (repeatCount: amount, autoreverses: true) + (repeatCount: amount, autoreverses: true) } } } diff --git a/Sources/Public/Animation/LottieAnimationView.swift b/Sources/Public/Animation/LottieAnimationView.swift index f5db6b48da..0ddec0ba3c 100644 --- a/Sources/Public/Animation/LottieAnimationView.swift +++ b/Sources/Public/Animation/LottieAnimationView.swift @@ -43,9 +43,9 @@ public enum LottieBackgroundBehavior { public static func `default`(for renderingEngine: RenderingEngine) -> LottieBackgroundBehavior { switch renderingEngine { case .mainThread: - return .pauseAndRestore + .pauseAndRestore case .coreAnimation: - return .continuePlaying + .continuePlaying } } } @@ -73,13 +73,13 @@ extension LottieLoopMode: Equatable { switch (lhs, rhs) { case (.repeat(let lhsAmount), .repeat(let rhsAmount)), (.repeatBackwards(let lhsAmount), .repeatBackwards(let rhsAmount)): - return lhsAmount == rhsAmount + lhsAmount == rhsAmount case (.playOnce, .playOnce), (.loop, .loop), (.autoReverse, .autoReverse): - return true + true default: - return false + false } } } @@ -567,9 +567,9 @@ open class LottieAnimationView: LottieAnimationViewBase { // duration and curve are captured and added to the layer. This is used in the // layout block to animate the animationLayer's position and size. let rect = bounds - self.bounds = CGRect.zero - self.bounds = rect - self.setNeedsLayout() + bounds = CGRect.zero + bounds = rect + setNeedsLayout() } } @@ -813,7 +813,7 @@ open class LottieAnimationView: LottieAnimationViewBase { // MARK: Internal - // The backing CALayer for this animation view. + /// The backing CALayer for this animation view. let lottieAnimationLayer: LottieAnimationLayer var animationLayer: RootAnimationLayer? { @@ -823,7 +823,7 @@ open class LottieAnimationView: LottieAnimationViewBase { /// Set animation name from Interface Builder @IBInspectable var animationName: String? { didSet { - self.lottieAnimationLayer.animation = animationName.flatMap { LottieAnimation.named($0, animationCache: nil) + lottieAnimationLayer.animation = animationName.flatMap { LottieAnimation.named($0, animationCache: nil) } } } @@ -835,15 +835,15 @@ open class LottieAnimationView: LottieAnimationViewBase { lottieAnimationLayer.animationLoaded = { [weak self] _, animation in guard let self else { return } - self.animationLoaded?(self, animation) - self.invalidateIntrinsicContentSize() - self.setNeedsLayout() + animationLoaded?(self, animation) + invalidateIntrinsicContentSize() + setNeedsLayout() } lottieAnimationLayer.animationLayerDidLoad = { [weak self] _, _ in guard let self else { return } - self.invalidateIntrinsicContentSize() - self.setNeedsLayout() + invalidateIntrinsicContentSize() + setNeedsLayout() } } diff --git a/Sources/Public/Animation/LottieAnimationViewInitializers.swift b/Sources/Public/Animation/LottieAnimationViewInitializers.swift index a2bc01dbd8..919cc934f2 100644 --- a/Sources/Public/Animation/LottieAnimationViewInitializers.swift +++ b/Sources/Public/Animation/LottieAnimationViewInitializers.swift @@ -122,6 +122,7 @@ extension LottieAnimationView { case .success(let dotLottieFile): self.loadAnimation(animationId, from: dotLottieFile) completion?(self, nil) + case .failure(let error): completion?(self, error) } @@ -147,6 +148,7 @@ extension LottieAnimationView { case .success(let dotLottieFile): self.loadAnimation(animationId, from: dotLottieFile) completion?(self, nil) + case .failure(let error): completion?(self, error) } @@ -176,6 +178,7 @@ extension LottieAnimationView { case .success(let lottie): self.loadAnimation(animationId, from: lottie) completion?(self, nil) + case .failure(let error): completion?(self, error) } @@ -203,6 +206,7 @@ extension LottieAnimationView { case .success(let dotLottieFile): self.loadAnimation(animationId, from: dotLottieFile) completion?(self, nil) + case .failure(let error): completion?(self, error) } diff --git a/Sources/Public/Animation/LottiePlaybackMode.swift b/Sources/Public/Animation/LottiePlaybackMode.swift index dd93a95e70..e33372405b 100644 --- a/Sources/Public/Animation/LottiePlaybackMode.swift +++ b/Sources/Public/Animation/LottiePlaybackMode.swift @@ -170,7 +170,7 @@ extension LottiePlaybackMode.PlaybackMode { .fromProgress(nil, toProgress: toProgress, loopMode: loopMode) } - // Plays the animation from the current frame to the given frame. + /// Plays the animation from the current frame to the given frame. /// - Parameter toFrame: The end frame of the animation. /// - Parameter loopMode: The loop behavior of the animation. public static func toFrame(_ toFrame: AnimationFrameTime, loopMode: LottieLoopMode) -> Self { @@ -211,32 +211,32 @@ extension LottiePlaybackMode { func loopMode(_ updatedLoopMode: LottieLoopMode) -> LottiePlaybackMode { switch self { case .playing(let playbackMode): - return .playing(playbackMode.loopMode(updatedLoopMode)) + .playing(playbackMode.loopMode(updatedLoopMode)) case .fromProgress(let fromProgress, toProgress: let toProgress, _): - return .playing(.fromProgress( + .playing(.fromProgress( fromProgress, toProgress: toProgress, loopMode: updatedLoopMode)) case .fromFrame(let fromFrame, toFrame: let toFrame, _): - return .playing(.fromFrame( + .playing(.fromFrame( fromFrame, toFrame: toFrame, loopMode: updatedLoopMode)) case .fromMarker(let fromMarker, let toMarker, let playEndMarkerFrame, _): - return .playing(.fromMarker( + .playing(.fromMarker( fromMarker, toMarker: toMarker, playEndMarkerFrame: playEndMarkerFrame, loopMode: updatedLoopMode)) case .marker(let marker, _): - return .playing(.marker(marker, loopMode: updatedLoopMode)) + .playing(.marker(marker, loopMode: updatedLoopMode)) case .pause, .paused, .progress(_), .time(_), .frame(_), .markers: - return self + self } } } @@ -246,15 +246,15 @@ extension LottiePlaybackMode.PlaybackMode { func loopMode(_ updatedLoopMode: LottieLoopMode) -> LottiePlaybackMode.PlaybackMode { switch self { case .fromProgress(let fromProgress, let toProgress, _): - return .fromProgress(fromProgress, toProgress: toProgress, loopMode: updatedLoopMode) + .fromProgress(fromProgress, toProgress: toProgress, loopMode: updatedLoopMode) case .fromFrame(let fromFrame, let toFrame, _): - return .fromFrame(fromFrame, toFrame: toFrame, loopMode: updatedLoopMode) + .fromFrame(fromFrame, toFrame: toFrame, loopMode: updatedLoopMode) case .fromMarker(let fromMarker, let toMarker, let playEndMarkerFrame, _): - return .fromMarker(fromMarker, toMarker: toMarker, playEndMarkerFrame: playEndMarkerFrame, loopMode: updatedLoopMode) + .fromMarker(fromMarker, toMarker: toMarker, playEndMarkerFrame: playEndMarkerFrame, loopMode: updatedLoopMode) case .marker(let marker, _): - return .marker(marker, loopMode: updatedLoopMode) + .marker(marker, loopMode: updatedLoopMode) case .markers: - return self + self } } } diff --git a/Sources/Public/Animation/LottieView.swift b/Sources/Public/Animation/LottieView.swift index 9147b65a76..f7a8ef1e53 100644 --- a/Sources/Public/Animation/LottieView.swift +++ b/Sources/Public/Animation/LottieView.swift @@ -199,7 +199,7 @@ public struct LottieView: UIViewConfiguringSwiftUIView { playbackMode(.playing(.fromProgress(nil, toProgress: 1, loopMode: loopMode))) } - // Returns a copy of this view playing once from the current frame to the end frame + /// Returns a copy of this view playing once from the current frame to the end frame public func playing() -> Self { playbackMode(.playing(.fromProgress(nil, toProgress: 1, loopMode: .playOnce))) } diff --git a/Sources/Public/Configuration/ReducedMotionOption.swift b/Sources/Public/Configuration/ReducedMotionOption.swift index 0101dc9bda..040d9d3548 100644 --- a/Sources/Public/Configuration/ReducedMotionOption.swift +++ b/Sources/Public/Configuration/ReducedMotionOption.swift @@ -43,9 +43,9 @@ extension ReducedMotionOption { public var currentReducedMotionMode: ReducedMotionMode { switch self { case .specific(let specificMode): - return specificMode + specificMode case .dynamic(let optionProvider, _): - return optionProvider.currentReducedMotionMode + optionProvider.currentReducedMotionMode } } } @@ -56,11 +56,11 @@ extension ReducedMotionOption: Hashable { public static func ==(_ lhs: ReducedMotionOption, _ rhs: ReducedMotionOption) -> Bool { switch (lhs, rhs) { case (.specific(let lhsMode), .specific(let rhsMode)): - return lhsMode == rhsMode + lhsMode == rhsMode case (.dynamic(_, let lhsDataID), .dynamic(_, dataID: let rhsDataID)): - return lhsDataID == rhsDataID + lhsDataID == rhsDataID case (.dynamic, .specific), (.specific, .dynamic): - return false + false } } diff --git a/Sources/Public/Configuration/RenderingEngineOption.swift b/Sources/Public/Configuration/RenderingEngineOption.swift index 187303d8c5..4ef01bcdec 100644 --- a/Sources/Public/Configuration/RenderingEngineOption.swift +++ b/Sources/Public/Configuration/RenderingEngineOption.swift @@ -67,9 +67,9 @@ extension RenderingEngineOption: RawRepresentable, CustomStringConvertible { public var rawValue: String { switch self { case .automatic: - return "Automatic" + "Automatic" case .specific(let engine): - return engine.rawValue + engine.rawValue } } @@ -101,9 +101,9 @@ extension RenderingEngine: RawRepresentable, CustomStringConvertible { public var rawValue: String { switch self { case .mainThread: - return "Main Thread" + "Main Thread" case .coreAnimation: - return "Core Animation" + "Core Animation" } } diff --git a/Sources/Public/Controls/AnimatedSwitch.swift b/Sources/Public/Controls/AnimatedSwitch.swift index 899e2bd823..e116e06e31 100644 --- a/Sources/Public/Controls/AnimatedSwitch.swift +++ b/Sources/Public/Controls/AnimatedSwitch.swift @@ -213,8 +213,8 @@ open class AnimatedSwitch: AnimatedControl { // For the Main Thread rendering engine, we freeze the animation at the expected final progress // once the animation is complete. This isn't necessary on the Core Animation engine. - if finished, !(self.animationView.animationLayer is CoreAnimationLayer) { - self.animationView.currentProgress = finalProgress + if finished, !(animationView.animationLayer is CoreAnimationLayer) { + animationView.currentProgress = finalProgress } }) } diff --git a/Sources/Public/DotLottie/DotLottieFile.swift b/Sources/Public/DotLottie/DotLottieFile.swift index d774d094ac..4e329b2d74 100644 --- a/Sources/Public/DotLottie/DotLottieFile.swift +++ b/Sources/Public/DotLottie/DotLottieFile.swift @@ -56,9 +56,9 @@ public final class DotLottieFile { /// The `LottieAnimation` and `DotLottieConfiguration` for the given animation ID in this file func animation(for id: String? = nil) -> DotLottieFile.Animation? { if let id { - return animations.first(where: { $0.configuration.id == id }) + animations.first(where: { $0.configuration.id == id }) } else { - return animations.first + animations.first } } diff --git a/Sources/Public/DynamicProperties/AnyValueProvider.swift b/Sources/Public/DynamicProperties/AnyValueProvider.swift index 4bd912bdce..9970b48d1d 100644 --- a/Sources/Public/DynamicProperties/AnyValueProvider.swift +++ b/Sources/Public/DynamicProperties/AnyValueProvider.swift @@ -49,13 +49,13 @@ extension ValueProvider { public var typeErasedStorage: AnyValueProviderStorage { switch storage { case .closure(let typedClosure): - return .closure(typedClosure) + .closure(typedClosure) case .singleValue(let typedValue): - return .singleValue(typedValue) + .singleValue(typedValue) case .keyframes(let keyframes): - return .keyframes( + .keyframes( keyframes.map { keyframe in keyframe.withValue(keyframe.value as Any) }, @@ -88,13 +88,13 @@ public enum ValueProviderStorage { func value(frame: AnimationFrameTime) -> T { switch self { case .singleValue(let value): - return value + value case .closure(let closure): - return closure(frame) + closure(frame) case .keyframes(let keyframes): - return KeyframeInterpolator(keyframes: ContiguousArray(keyframes)).storage.value(frame: frame) + KeyframeInterpolator(keyframes: ContiguousArray(keyframes)).storage.value(frame: frame) } } } @@ -119,13 +119,13 @@ public enum AnyValueProviderStorage { func value(frame: AnimationFrameTime) -> Any { switch self { case .singleValue(let value): - return value + value case .closure(let closure): - return closure(frame) + closure(frame) case .keyframes(_, let valueForFrame): - return valueForFrame(frame) + valueForFrame(frame) } } } diff --git a/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift b/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift index d15891b5d3..aa44782670 100644 --- a/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +++ b/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift @@ -70,7 +70,7 @@ public final class GradientValueProvider: ValueProvider { public var storage: ValueProviderStorage<[Double]> { if let block { - return .closure { [self] frame in + .closure { [self] frame in hasUpdate = false let newColors = block(frame) @@ -80,7 +80,7 @@ public final class GradientValueProvider: ValueProvider { return value } } else { - return .singleValue(value) + .singleValue(value) } } diff --git a/Sources/Public/Keyframes/Interpolatable.swift b/Sources/Public/Keyframes/Interpolatable.swift index bb53c13d1d..a0f09b60be 100644 --- a/Sources/Public/Keyframes/Interpolatable.swift +++ b/Sources/Public/Keyframes/Interpolatable.swift @@ -271,9 +271,9 @@ struct Hold: Interpolatable { func interpolate(to: Hold, amount: CGFloat) -> Hold { if amount < 1 { - return self + self } else { - return to + to } } } diff --git a/Sources/Public/Primitives/LottieColor.swift b/Sources/Public/Primitives/LottieColor.swift index 3af8ab1a14..ffae202392 100644 --- a/Sources/Public/Primitives/LottieColor.swift +++ b/Sources/Public/Primitives/LottieColor.swift @@ -15,11 +15,11 @@ public enum ColorFormatDenominator: Hashable { var value: Double { switch self { case .One: - return 1.0 + 1.0 case .OneHundred: - return 100.0 + 100.0 case .TwoFiftyFive: - return 255.0 + 255.0 } } } diff --git a/Sources/Public/TextProvider/AnimationTextProvider.swift b/Sources/Public/TextProvider/AnimationTextProvider.swift index cd41545e8f..52ce0941ec 100644 --- a/Sources/Public/TextProvider/AnimationTextProvider.swift +++ b/Sources/Public/TextProvider/AnimationTextProvider.swift @@ -62,22 +62,22 @@ public final class DictionaryTextProvider: AnimationKeypathTextProvider, LegacyA public func text(for keypath: AnimationKeypath, sourceText: String) -> String? { if let valueForFullKeypath = values[keypath.fullPath] { - return valueForFullKeypath + valueForFullKeypath } else if let lastKeypathComponent = keypath.keys.last, let valueForLastComponent = values[lastKeypathComponent] { - return valueForLastComponent + valueForLastComponent } else { - return sourceText + sourceText } } - // Never called directly by Lottie, but we continue to implement this conformance for backwards compatibility. + /// Never called directly by Lottie, but we continue to implement this conformance for backwards compatibility. public func textFor(keypathName: String, sourceText: String) -> String { values[keypathName] ?? sourceText } diff --git a/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift b/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift index 9b788fc6c2..c78846ffe5 100644 --- a/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +++ b/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift @@ -77,15 +77,15 @@ public enum CompatibleRenderingEngineOption: Int { { switch configuration { case .shared: - return LottieConfiguration.shared + LottieConfiguration.shared case .defaultEngine: - return LottieConfiguration(renderingEngine: .coreAnimation) + LottieConfiguration(renderingEngine: .coreAnimation) case .automatic: - return LottieConfiguration(renderingEngine: .automatic) + LottieConfiguration(renderingEngine: .automatic) case .mainThread: - return LottieConfiguration(renderingEngine: .mainThread) + LottieConfiguration(renderingEngine: .mainThread) case .coreAnimation: - return LottieConfiguration(renderingEngine: .coreAnimation) + LottieConfiguration(renderingEngine: .coreAnimation) } } } @@ -219,7 +219,8 @@ public final class CompatibleAnimationView: UIView { } } - @objc public override var contentMode: UIView.ContentMode { + @objc + public override var contentMode: UIView.ContentMode { set { animationView.contentMode = newValue } get { animationView.contentMode } } @@ -285,15 +286,15 @@ public final class CompatibleAnimationView: UIView { get { switch animationView.backgroundBehavior { case .stop: - return .stop + .stop case .pause: - return .pause + .pause case .pauseAndRestore: - return .pauseAndRestore + .pauseAndRestore case .forceFinish: - return .forceFinish + .forceFinish case .continuePlaying: - return .continuePlaying + .continuePlaying } } set { @@ -440,7 +441,7 @@ public final class CompatibleAnimationView: UIView { public func getColorValue(for keypath: CompatibleAnimationKeypath, atFrame: CGFloat) -> UIColor? { let value = animationView.getValue(for: keypath.animationKeypath, atFrame: atFrame) guard let colorValue = value as? LottieColor else { - return nil; + return nil } return UIColor( diff --git a/Tests/AutomaticEngineTests.swift b/Tests/AutomaticEngineTests.swift index e179dc592f..7ce7adb737 100644 --- a/Tests/AutomaticEngineTests.swift +++ b/Tests/AutomaticEngineTests.swift @@ -42,13 +42,13 @@ final class AutomaticEngineTests: XCTestCase { animationLayer.layoutIfNeeded() animationLayer.display() - let compatibilityReport: String - if compatibilityIssues.isEmpty { - compatibilityReport = "Supports Core Animation engine" - } else { - compatibilityReport = "Does not support Core Animation engine. Encountered compatibility issues:\n" - + compatibilityIssues.map { $0.description }.joined(separator: "\n") - } + let compatibilityReport = + if compatibilityIssues.isEmpty { + "Supports Core Animation engine" + } else { + "Does not support Core Animation engine. Encountered compatibility issues:\n" + + compatibilityIssues.map { $0.description }.joined(separator: "\n") + } assertSnapshot( matching: compatibilityReport, diff --git a/Tests/DataURLTests.swift b/Tests/DataURLTests.swift index 86ed7f510d..0738491f5e 100644 --- a/Tests/DataURLTests.swift +++ b/Tests/DataURLTests.swift @@ -8,8 +8,8 @@ import XCTest // MARK: - DataURLTests -// Tests are based on implementation found here -// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs +/// Tests are based on implementation found here +/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs final class DataURLTests: XCTestCase { let red5x5 = diff --git a/Tests/SnapshotConfiguration.swift b/Tests/SnapshotConfiguration.swift index 35c2fbb380..b3b9bdcb50 100644 --- a/Tests/SnapshotConfiguration.swift +++ b/Tests/SnapshotConfiguration.swift @@ -235,9 +235,9 @@ extension SnapshotConfiguration { /// The `SnapshotConfiguration` to use for the given sample JSON file name static func forSample(named sampleName: String) -> SnapshotConfiguration { if let customConfiguration = customMapping[sampleName] { - return customConfiguration + customConfiguration } else { - return .default + .default } } @@ -333,11 +333,11 @@ extension SnapshotConfiguration { func shouldSnapshot(using configuration: LottieConfiguration) -> Bool { switch configuration.renderingEngine { case .automatic: - return testWithAutomaticEngine + testWithAutomaticEngine case .specific(.coreAnimation): - return !excludeCoreAnimationRenderingEngine + !excludeCoreAnimationRenderingEngine case .specific(.mainThread): - return true + true } } } diff --git a/Tests/SnapshotTests.swift b/Tests/SnapshotTests.swift index 0ef8f0f02d..fa0c82929d 100644 --- a/Tests/SnapshotTests.swift +++ b/Tests/SnapshotTests.swift @@ -164,19 +164,19 @@ final class SnapshotTests: XCTestCase { animationView.setPlaybackMode(.paused(at: pauseState)) - let pauseStateDescription: String - switch pauseState { - case .progress(let percent): - pauseStateDescription = "\(Int(percent * 100))%" - case .frame(let frame): - pauseStateDescription = "Frame \(Int(frame))" - case .time(let time): - pauseStateDescription = "Time \(time))" - case .marker(let markerName, position: _): - pauseStateDescription = markerName - case .currentFrame: - pauseStateDescription = "Current Frame" - } + let pauseStateDescription: String = + switch pauseState { + case .progress(let percent): + "\(Int(percent * 100))%" + case .frame(let frame): + "Frame \(Int(frame))" + case .time(let time): + "Time \(time))" + case .marker(let markerName, position: _): + markerName + case .currentFrame: + "Current Frame" + } assertSnapshot( matching: animationView, diff --git a/Tests/TextProviderTests.swift b/Tests/TextProviderTests.swift index fdc668e2b9..cce6b8d57b 100644 --- a/Tests/TextProviderTests.swift +++ b/Tests/TextProviderTests.swift @@ -129,7 +129,7 @@ private final class LoggingAnimationKeypathTextProvider: AnimationKeypathTextPro } extension LottieAnimationView { - // Causes this `LottieAnimationView` to render its contents immediately + /// Causes this `LottieAnimationView` to render its contents immediately func renderContentsForUnitTests() { if let mainThreadAnimationLayer = lottieAnimationLayer.animationLayer as? MainThreadAnimationLayer { mainThreadAnimationLayer.forceDisplayUpdate() diff --git a/lottie-ios.podspec b/lottie-ios.podspec index e599dccb04..184808e513 100644 --- a/lottie-ios.podspec +++ b/lottie-ios.podspec @@ -22,7 +22,7 @@ Lottie enables designers to create and ship beautiful animations without an engi s.author = { 'Brandon Withrow' => 'buba447@gmail.com', 'Cal Stephens' => 'cal.stephens@airbnb.com' } s.source = { :git => 'https://github.com/airbnb/lottie-ios.git', :tag => s.version.to_s } - s.swift_version = '5.7' + s.swift_version = '5.9' s.ios.deployment_target = '13.0' s.osx.deployment_target = '10.15' s.tvos.deployment_target = '13.0'