diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6cb59a2da2..a9335390f3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,22 +7,6 @@ on: branches: [ master ] jobs: - build-package-macos-12: - name: "Build Package" - runs-on: macos-12 - strategy: - fail-fast: false - matrix: - xcode: - - '13.4.1' # Swift 5.6 - steps: - - uses: actions/checkout@v2 - - uses: ./.github/actions/setup - with: - xcode: ${{ matrix.xcode }} - - name: Build Package - run: SKIP_VISION_OS=true bundle exec rake build:package:all - build-package-macos-13: name: "Build Package" runs-on: macos-13 @@ -30,7 +14,7 @@ jobs: fail-fast: false matrix: xcode: - - '14.2' # Swift 5.7 + - '14.1' # Swift 5.7 - '14.3' # Swift 5.8 - '15.0' # Swift 5.9 steps: @@ -88,16 +72,18 @@ jobs: EMERGE_API_TOKEN: ${{ secrets.EMERGE_API_TOKEN }} PR_NUMBER: ${{ github.event.number }} - build-xcframework-macos-12: + build-xcframework-macos-13: name: "Build XCFramework" - runs-on: macos-12 + runs-on: macos-13 strategy: matrix: xcode: # XCFrameworks are forwards-compatible but not backwards-compatible. # 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. - - '13.4.1' # Swift 5.6.1 + # 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 + - '14.1' # Swift 5.7.1 steps: - uses: actions/checkout@v2 - uses: ./.github/actions/setup @@ -162,22 +148,6 @@ jobs: - name: Test Swift Package Manager support run: SKIP_VISION_OS=true bundle exec rake test:spm - spm-xcode-13: - name: "Test Swift Package Manager" - runs-on: macos-12 - strategy: - matrix: - xcode: - - '13.4.1' # Swift 5.6 - steps: - - uses: actions/checkout@v2 - - uses: ./.github/actions/setup - with: - install-mint: true - xcode: ${{ matrix.xcode }} - - name: Test Swift Package Manager support - run: SKIP_VISION_OS=true bundle exec rake test:spm - carthage: name: "Test Carthage support" runs-on: macos-13 diff --git a/Package.resolved b/Package.resolved index c5fafb65e3..31a8a3fa40 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,25 +1,23 @@ { - "object": { - "pins": [ - { - "package": "AirbnbSwift", - "repositoryURL": "https://github.com/airbnb/swift", - "state": { - "branch": null, - "revision": "b408d36b4f5e73ea75441fb9791b849b0a40f58b", - "version": "1.0.5" - } - }, - { - "package": "swift-argument-parser", - "repositoryURL": "https://github.com/apple/swift-argument-parser", - "state": { - "branch": null, - "revision": "df9ee6676cd5b3bf5b330ec7568a5644f547201b", - "version": "1.1.3" - } + "pins" : [ + { + "identity" : "swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/airbnb/swift", + "state" : { + "revision" : "bc6aa7c3e21b6ab951ce75afc0a6e6d16fd6caef", + "version" : "1.0.6" } - ] - }, - "version": 1 + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser", + "state" : { + "revision" : "df9ee6676cd5b3bf5b330ec7568a5644f547201b", + "version" : "1.1.3" + } + } + ], + "version" : 2 } diff --git a/Package.swift b/Package.swift index 2fa4c2fd96..041b390e59 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.7 import PackageDescription let package = Package( diff --git a/README.md b/README.md index 28467e79f6..9438b33bc8 100644 --- a/README.md +++ b/README.md @@ -75,9 +75,15 @@ carthage update ``` In your application targets “General” tab under the “Linked Frameworks and Libraries” section, drag and drop lottie-ios.framework from the Carthage/Build/iOS directory that `carthage update` produced. -### Data collection +## Swift Version Support -The Lottie SDK does not collect any data. We provide this notice to help you fill out [App Privacy Details](https://developer.apple.com/app-store/app-privacy-details/). +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): + +[![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) + +## Privacy + +Lottie does not collect any data. We provide this notice to help you fill out [App Privacy Details](https://developer.apple.com/app-store/app-privacy-details/). We additionally provide a [privacy manifest](https://github.com/airbnb/lottie-ios/blob/master/PrivacyInfo.xcprivacy) which can be included in your app. ## Contributing diff --git a/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift b/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift index db56da13d5..dfeb8afdc7 100644 --- a/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +++ b/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift @@ -65,7 +65,7 @@ struct BezierPathKeyframe { -> KeyframeGroup { guard - let cornerRadius = cornerRadius, + let cornerRadius, cornerRadius.keyframes.contains(where: { $0.value.cgFloatValue > 0 }) else { return path.map { path in diff --git a/Sources/Private/CoreAnimation/Animations/LayerProperty.swift b/Sources/Private/CoreAnimation/Animations/LayerProperty.swift index a48c48279d..71a3453b70 100644 --- a/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +++ b/Sources/Private/CoreAnimation/Animations/LayerProperty.swift @@ -169,7 +169,7 @@ extension LayerProperty { .init( caLayerKeypath: #keyPath(CALayer.transform), isDefaultValue: { transform in - guard let transform = transform else { return false } + guard let transform else { return false } return CATransform3DIsIdentity(transform) }, customizableProperty: nil /* currently unsupported */ ) diff --git a/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift b/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift index f646409794..178cc4ca28 100644 --- a/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +++ b/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift @@ -305,8 +305,8 @@ extension TransformModel { /// Whether or not this transform has a non-zero skew value var hasSkew: Bool { guard - let _skew = _skew, - let _skewAxis = _skewAxis, + let _skew, + let _skewAxis, !_skew.keyframes.isEmpty, !_skewAxis.keyframes.isEmpty else { @@ -320,8 +320,8 @@ extension TransformModel { var hasSkewAnimation: Bool { guard hasSkew, - let _skew = _skew, - let _skewAxis = _skewAxis + let _skew, + let _skewAxis else { return false } return _skew.keyframes.count > 1 diff --git a/Sources/Private/CoreAnimation/CoreAnimationLayer.swift b/Sources/Private/CoreAnimation/CoreAnimationLayer.swift index 3c209d8d7e..4fc4680805 100644 --- a/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +++ b/Sources/Private/CoreAnimation/CoreAnimationLayer.swift @@ -160,7 +160,7 @@ final class CoreAnimationLayer: BaseAnimationLayer { // allocate a very large amount of memory (400mb+). // - Alternatively this layer could subclass `CATransformLayer`, // but this causes Core Animation to emit unnecessary logs. - if var pendingAnimationConfiguration = pendingAnimationConfiguration { + if var pendingAnimationConfiguration { pendingAnimationConfigurationModification?(&pendingAnimationConfiguration.animationConfiguration) pendingAnimationConfigurationModification = nil self.pendingAnimationConfiguration = nil diff --git a/Sources/Private/CoreAnimation/Extensions/CALayer+fillBounds.swift b/Sources/Private/CoreAnimation/Extensions/CALayer+fillBounds.swift index 5b0baf16d1..fe9e9e0268 100644 --- a/Sources/Private/CoreAnimation/Extensions/CALayer+fillBounds.swift +++ b/Sources/Private/CoreAnimation/Extensions/CALayer+fillBounds.swift @@ -10,7 +10,7 @@ extension CALayer { /// without setting `frame` (which is not permitted if the layer can rotate) @nonobjc func fillBoundsOfSuperlayer() { - guard let superlayer = superlayer else { return } + guard let superlayer else { return } if let customLayerLayer = self as? CustomLayoutLayer { customLayerLayer.layout(superlayerBounds: superlayer.bounds) diff --git a/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift b/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift index 445d1dfbd7..dfbf28cff5 100644 --- a/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift +++ b/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift @@ -67,7 +67,7 @@ extension CALayer { // Create the `mask` layer for this layer, if it has a `MatteType` if - let mask = mask, + let mask, let maskLayer = try maskLayer(for: mask.model, type: mask.matteType, context: context) { let maskParentTransformLayer = makeParentTransformLayer( @@ -138,7 +138,7 @@ extension CALayer { } -extension Collection where Element == LayerModel { +extension Collection { /// Pairs each `LayerModel` within this array with /// a `LayerModel` to use as its mask, if applicable /// based on the layer's `MatteType` configuration. diff --git a/Sources/Private/CoreAnimation/Layers/ImageLayer.swift b/Sources/Private/CoreAnimation/Layers/ImageLayer.swift index a3bac617d7..433c06f3b7 100644 --- a/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +++ b/Sources/Private/CoreAnimation/Layers/ImageLayer.swift @@ -65,7 +65,7 @@ extension ImageLayer: CustomLayoutLayer { func layout(superlayerBounds: CGRect) { anchorPoint = .zero - guard let imageAsset = imageAsset else { + guard let imageAsset else { bounds = superlayerBounds return } diff --git a/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift b/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift index 2fe6caa422..9bceb5f46f 100644 --- a/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +++ b/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift @@ -70,7 +70,7 @@ final class PreCompLayer: BaseCompositionLayer { // Precomp layers can adjust the local time of their child layers (relative to the // animation's global time) via `timeRemapping` or a custom `startTime` / `timeStretch` let contextForChildren = context.withTimeRemapping { [preCompLayer, timeRemappingInterpolator] layerLocalFrame in - if let timeRemappingInterpolator = timeRemappingInterpolator { + if let timeRemappingInterpolator { return timeRemappingInterpolator.value(frame: layerLocalFrame) as? AnimationFrameTime ?? layerLocalFrame } else { return (layerLocalFrame * AnimationFrameTime(preCompLayer.timeStretch)) + AnimationFrameTime(preCompLayer.startTime) diff --git a/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift b/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift index 6fd9398d92..23524d107b 100644 --- a/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +++ b/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift @@ -67,7 +67,7 @@ final class ShapeItemLayer: BaseAnimationLayer { override func setupAnimations(context: LayerAnimationContext) throws { try super.setupAnimations(context: context) - guard let sublayerConfiguration = sublayerConfiguration else { return } + guard let sublayerConfiguration else { return } switch sublayerConfiguration.fill { case .solidFill(let shapeLayer): @@ -299,7 +299,7 @@ final class ShapeItemLayer: BaseAnimationLayer { // MARK: - [ShapeItem] helpers -extension Array where Element == ShapeItemLayer.Item { +extension [ShapeItemLayer.Item] { /// The first `ShapeItem` in this array of the given type func first( _: ItemType.Type, diff --git a/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift b/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift index d853b90d1d..403baa2166 100644 --- a/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +++ b/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift @@ -427,7 +427,7 @@ struct ShapeRenderGroup { var otherItems: [ShapeItemLayer.Item] = [] } -extension Array where Element == ShapeItemLayer.Item { +extension [ShapeItemLayer.Item] { /// Splits this list of `ShapeItem`s into groups that should be rendered together as individual units, /// plus the remaining items that were not included in any group. /// - groupHasChildGroupsToInheritUnusedItems: whether or not this group has child groups diff --git a/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelArrayBuilder.swift b/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelArrayBuilder.swift index 3258dcd7f6..a846ba27eb 100644 --- a/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelArrayBuilder.swift +++ b/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelArrayBuilder.swift @@ -16,7 +16,7 @@ enum EpoxyModelArrayBuilder { } static func buildExpression(_ expression: Expression?) -> Component { - if let expression = expression { + if let expression { return [expression] } return [] diff --git a/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelProperty.swift b/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelProperty.swift index 39999ee5bb..a7905cb588 100644 --- a/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelProperty.swift +++ b/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelProperty.swift @@ -93,8 +93,8 @@ extension EpoxyModelProperty.UpdateStrategy { /// calls the old closure and then subsequently calls the new closure. static func chain() -> EpoxyModelProperty<(() -> Void)?>.UpdateStrategy { .init { old, new in - guard let new = new else { return old } - guard let old = old else { return new } + guard let new else { return old } + guard let old else { return new } return { old() new() @@ -106,8 +106,8 @@ extension EpoxyModelProperty.UpdateStrategy { /// calls the old closure and then subsequently calls the new closure. static func chain() -> EpoxyModelProperty<((A) -> Void)?>.UpdateStrategy { .init { old, new in - guard let new = new else { return old } - guard let old = old else { return new } + guard let new else { return old } + guard let old else { return new } return { a in old(a) new(a) @@ -119,8 +119,8 @@ extension EpoxyModelProperty.UpdateStrategy { /// calls the old closure and then subsequently calls the new closure. static func chain() -> EpoxyModelProperty<((A, B) -> Void)?>.UpdateStrategy { .init { old, new in - guard let new = new else { return old } - guard let old = old else { return new } + guard let new else { return old } + guard let old else { return new } return { a, b in old(a, b) new(a, b) @@ -132,8 +132,8 @@ extension EpoxyModelProperty.UpdateStrategy { /// calls the old closure and then subsequently calls the new closure. static func chain() -> EpoxyModelProperty<((A, B, C) -> Void)?>.UpdateStrategy { .init { old, new in - guard let new = new else { return old } - guard let old = old else { return new } + guard let new else { return old } + guard let old else { return new } return { a, b, c in old(a, b, c) new(a, b, c) @@ -145,8 +145,8 @@ extension EpoxyModelProperty.UpdateStrategy { /// calls the old closure and then subsequently calls the new closure. static func chain() -> EpoxyModelProperty<((A, B, C, D) -> Void)?>.UpdateStrategy { .init { old, new in - guard let new = new else { return old } - guard let old = old else { return new } + guard let new else { return old } + guard let old else { return new } return { a, b, c, d in old(a, b, c, d) new(a, b, c, d) diff --git a/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift b/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift index f845205369..8253d80240 100644 --- a/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift +++ b/Sources/Private/EmbeddedLibraries/LRUCache/LRUCache.swift @@ -74,7 +74,7 @@ final class LRUCache { } deinit { - if let token = token { + if let token { notificationCenter.removeObserver(token) } } @@ -131,7 +131,7 @@ extension LRUCache { /// Insert a value into the cache with optional `cost` func setValue(_ value: Value?, forKey key: Key, cost: Int = 0) { - guard let value = value else { + guard let value else { removeValue(forKey: key) return } diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift index 826a8d5ef6..28690de5fe 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+Helpers.swift @@ -92,13 +92,13 @@ extension Archive { } case .directory: _ = try provider(0, 0) - if let progress = progress { progress.completedUnitCount = progress.totalUnitCount } + if let progress { progress.completedUnitCount = progress.totalUnitCount } case .symlink: let (linkSizeWritten, linkChecksum) = try writeSymbolicLink( size: Int(uncompressedSize), provider: provider) (sizeWritten, checksum) = (Int64(linkSizeWritten), linkChecksum) - if let progress = progress { progress.completedUnitCount = progress.totalUnitCount } + if let progress { progress.completedUnitCount = progress.totalUnitCount } } return (sizeWritten, checksum) } diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+MemoryFile.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+MemoryFile.swift index d8e6032b6c..cda58976bd 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+MemoryFile.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Archive+MemoryFile.swift @@ -102,7 +102,7 @@ private func fileFromCookie(cookie: UnsafeRawPointer) -> MemoryFile { } private func closeStub(_ cookie: UnsafeMutableRawPointer?) -> Int32 { - if let cookie = cookie { + if let cookie { Unmanaged.fromOpaque(cookie).release() } return 0 @@ -115,7 +115,7 @@ private func readStub( _ count: Int32) -> Int32 { - guard let cookie = cookie, let bytePtr = bytePtr else { return 0 } + guard let cookie, let bytePtr else { return 0 } return Int32(fileFromCookie(cookie: cookie).readData( buffer: UnsafeMutableRawBufferPointer(start: bytePtr, count: Int(count)))) } @@ -126,7 +126,7 @@ private func writeStub( _ count: Int32) -> Int32 { - guard let cookie = cookie, let bytePtr = bytePtr else { return 0 } + guard let cookie, let bytePtr else { return 0 } return Int32(fileFromCookie(cookie: cookie).writeData( buffer: UnsafeRawBufferPointer(start: bytePtr, count: Int(count)))) } @@ -137,7 +137,7 @@ private func seekStub( _ whence: Int32) -> fpos_t { - guard let cookie = cookie else { return 0 } + guard let cookie else { return 0 } return fpos_t(fileFromCookie(cookie: cookie).seek(offset: Int(offset), whence: whence)) } @@ -148,7 +148,7 @@ private func readStub( _ count: Int) -> Int { - guard let cookie = cookie, let bytePtr = bytePtr else { return 0 } + guard let cookie, let bytePtr else { return 0 } return fileFromCookie(cookie: cookie).readData( buffer: UnsafeMutableRawBufferPointer(start: bytePtr, count: count)) } @@ -159,7 +159,7 @@ private func writeStub( _ count: Int) -> Int { - guard let cookie = cookie, let bytePtr = bytePtr else { return 0 } + guard let cookie, let bytePtr else { return 0 } return fileFromCookie(cookie: cookie).writeData( buffer: UnsafeRawBufferPointer(start: bytePtr, count: count)) } @@ -170,7 +170,7 @@ private func seekStub( _ whence: Int32) -> Int32 { - guard let cookie = cookie, let offset = offset else { return 0 } + guard let cookie, let offset else { return 0 } let result = fileFromCookie(cookie: cookie).seek(offset: Int(offset.pointee), whence: whence) if result >= 0 { offset.pointee = result diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift index 4fd9800f0f..065661696a 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/Data+Compression.swift @@ -149,7 +149,7 @@ extension Data { position += Int64(stream.prepare(for: sourceData)) } catch { throw error } } - if let sourceData = sourceData { + if let sourceData { sourceData.withUnsafeBytes { rawBufferPointer in if let baseAddress = rawBufferPointer.baseAddress { let pointer = baseAddress.assumingMemoryBound(to: UInt8.self) @@ -179,7 +179,7 @@ extension Data { extension compression_stream { fileprivate mutating func prepare(for sourceData: Data?) -> Int { - guard let sourceData = sourceData else { return 0 } + guard let sourceData else { return 0 } src_size = sourceData.count return sourceData.count diff --git a/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift b/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift index d591671f19..69ea55e163 100644 --- a/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift +++ b/Sources/Private/EmbeddedLibraries/ZipFoundation/FileManager+ZIP.swift @@ -156,7 +156,7 @@ extension FileManager { if isDirectory { let subPaths = try subpathsOfDirectory(atPath: sourceURL.path) var totalUnitCount = Int64(0) - if let progress = progress { + if let progress { totalUnitCount = subPaths.reduce(Int64(0)) { let itemURL = sourceURL.appendingPathComponent($1) let itemSize = archive.totalUnitCountForAddingItem(at: itemURL) @@ -171,7 +171,7 @@ extension FileManager { for entryPath in subPaths { let finalEntryPath = shouldKeepParent ? directoryPrefix + "/" + entryPath : entryPath let finalBaseURL = shouldKeepParent ? sourceURL.deletingLastPathComponent() : sourceURL - if let progress = progress { + if let progress { let itemURL = sourceURL.appendingPathComponent(entryPath) let entryProgress = archive.makeProgressForAddingItem(at: itemURL) progress.addChild(entryProgress, withPendingUnitCount: entryProgress.totalUnitCount) @@ -233,7 +233,7 @@ extension FileManager { } } var totalUnitCount = Int64(0) - if let progress = progress { + if let progress { totalUnitCount = sortedEntries.reduce(0) { $0 + archive.totalUnitCountForReading($1) } progress.totalUnitCount = totalUnitCount } @@ -247,7 +247,7 @@ extension FileManager { userInfo: [NSFilePathErrorKey: entryURL.path]) } let crc32: CRC32 - if let progress = progress { + if let progress { let entryProgress = archive.makeProgressForReading(entry) progress.addChild(entryProgress, withPendingUnitCount: entryProgress.totalUnitCount) crc32 = try archive.extract(entry, to: entryURL, skipCRC32: skipCRC32, progress: entryProgress) @@ -349,7 +349,7 @@ extension Date { extension CocoaError { static func error(_ code: CocoaError.Code, userInfo: [AnyHashable: Any]? = nil, url: URL? = nil) -> Error { var info: [String: Any] = userInfo as? [String: Any] ?? [:] - if let url = url { + if let url { info[NSURLErrorKey] = url } return NSError(domain: NSCocoaErrorDomain, code: code.rawValue, userInfo: info) diff --git a/Sources/Private/MainThread/LayerContainers/CompLayers/CompositionLayer.swift b/Sources/Private/MainThread/LayerContainers/CompLayers/CompositionLayer.swift index bf3eae3873..ba673900dd 100644 --- a/Sources/Private/MainThread/LayerContainers/CompLayers/CompositionLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/CompLayers/CompositionLayer.swift @@ -51,7 +51,7 @@ class CompositionLayer: CALayer, KeypathSearchable { compositingFilter = layer.blendMode.filterName addSublayer(contentsLayer) - if let maskLayer = maskLayer { + if let maskLayer { contentsLayer.mask = maskLayer } diff --git a/Sources/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift b/Sources/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift index 1d8a001f91..708b8a14be 100644 --- a/Sources/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift @@ -38,7 +38,7 @@ final class ImageCompositionLayer: CompositionLayer { var image: CGImage? = nil { didSet { - if let image = image { + if let image { contentsLayer.contents = image } else { contentsLayer.contents = nil diff --git a/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift b/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift index e548e9fd49..d1182dbaff 100644 --- a/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift @@ -128,7 +128,7 @@ private class MaskLayer: CALayer { let maskLayer = CAShapeLayer() func updateWithFrame(frame: CGFloat, forceUpdates: Bool) { - guard let properties = properties else { return } + guard let properties else { return } if properties.opacity.needsUpdate(frame: frame) || forceUpdates { properties.opacity.update(frame: frame) opacity = Float(properties.opacity.value.cgFloatValue) diff --git a/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift b/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift index b9051463e3..f17025e3e7 100644 --- a/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift @@ -101,7 +101,7 @@ final class PreCompositionLayer: CompositionLayer { let remappingNode: NodeProperty? override var keypathProperties: [String: AnyNodeProperty] { - guard let remappingNode = remappingNode else { + guard let remappingNode else { return super.keypathProperties } return ["Time Remap" : remappingNode] @@ -109,7 +109,7 @@ final class PreCompositionLayer: CompositionLayer { override func displayContentsWithFrame(frame: CGFloat, forceUpdates: Bool) { let localFrame: CGFloat - if let remappingNode = remappingNode { + if let remappingNode { remappingNode.update(frame: frame) localFrame = remappingNode.value.cgFloatValue * frameRate } else { diff --git a/Sources/Private/MainThread/LayerContainers/CompLayers/SolidCompositionLayer.swift b/Sources/Private/MainThread/LayerContainers/CompLayers/SolidCompositionLayer.swift index 928283cbb6..7902770b56 100644 --- a/Sources/Private/MainThread/LayerContainers/CompLayers/SolidCompositionLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/CompLayers/SolidCompositionLayer.swift @@ -44,12 +44,12 @@ final class SolidCompositionLayer: CompositionLayer { let solidShape = CAShapeLayer() override var keypathProperties: [String: AnyNodeProperty] { - guard let colorProperty = colorProperty else { return super.keypathProperties } + guard let colorProperty else { return super.keypathProperties } return [PropertyName.color.rawValue : colorProperty] } override func displayContentsWithFrame(frame: CGFloat, forceUpdates _: Bool) { - guard let colorProperty = colorProperty else { return } + guard let colorProperty else { return } colorProperty.update(frame: frame) solidShape.fillColor = colorProperty.value.cgColorValue } diff --git a/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift b/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift index bb5edec1be..f26a51cfce 100644 --- a/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift @@ -64,7 +64,7 @@ final class TextCompositionLayer: CompositionLayer { self.textLayer.masksToBounds = false self.textLayer.isGeometryFlipped = true - if let rootNode = rootNode { + if let rootNode { childKeypaths.append(rootNode) } } @@ -97,17 +97,15 @@ final class TextCompositionLayer: CompositionLayer { var fontProvider: AnimationFontProvider weak var rootAnimationLayer: MainThreadAnimationLayer? - lazy var fullAnimationKeypath: AnimationKeypath = { - // Individual layers don't know their full keypaths, so we have to delegate + lazy var fullAnimationKeypath: AnimationKeypath = // Individual layers don't know their full keypaths, so we have to delegate // to the `MainThreadAnimationLayer` to search the layer hierarchy and find // the full keypath (which includes this layer's parent layers) rootAnimationLayer?.keypath(for: self) - // If that failed for some reason, just use the last path component (which we do have here) - ?? AnimationKeypath(keypath: keypathName) - }() + // If that failed for some reason, just use the last path component (which we do have here) + ?? AnimationKeypath(keypath: keypathName) override func displayContentsWithFrame(frame: CGFloat, forceUpdates: Bool) { - guard let textDocument = textDocument else { return } + guard let textDocument else { return } textLayer.contentsScale = renderScale diff --git a/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift b/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift index b9e0468dec..f95efbe31e 100644 --- a/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift +++ b/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift @@ -8,7 +8,7 @@ import CoreGraphics import Foundation -extension Array where Element == LayerModel { +extension [LayerModel] { func initializeCompositionLayers( assetLibrary: AssetLibrary?, @@ -41,7 +41,7 @@ extension Array where Element == LayerModel { layerMap[layer.index] = solidContainer } else if let precompLayer = layer as? PreCompLayerModel, - let assetLibrary = assetLibrary, + let assetLibrary, let precompAsset = assetLibrary.precompAssets[precompLayer.referenceID] { let precompContainer = PreCompositionLayer( @@ -58,7 +58,7 @@ extension Array where Element == LayerModel { layerMap[layer.index] = precompContainer } else if let imageLayer = layer as? ImageLayerModel, - let assetLibrary = assetLibrary, + let assetLibrary, let imageAsset = assetLibrary.imageAssets[imageLayer.referenceID] { let imageContainer = ImageCompositionLayer( diff --git a/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift b/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift index 5c6dbf76a5..db621fff6e 100644 --- a/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/Utility/CoreTextRenderLayer.swift @@ -117,7 +117,7 @@ final class CoreTextRenderLayer: CALayer { } override func draw(in ctx: CGContext) { - guard let attributedString = attributedString else { return } + guard let attributedString else { return } updateTextContent() guard fillFrameSetter != nil || strokeFrameSetter != nil else { return } @@ -155,21 +155,21 @@ final class CoreTextRenderLayer: CALayer { // For some reason some fonts, such as Helvetica draw with and ascender that is greater than the one reported by CTFontGetAscender. // I suspect this is actually an issue with the Attributed string, but cannot reproduce. - if let fillFrame = fillFrame { + if let fillFrame { ctx.adjustWithLineOrigins(in: fillFrame, with: font) - } else if let strokeFrame = strokeFrame { + } else if let strokeFrame { ctx.adjustWithLineOrigins(in: strokeFrame, with: font) } - if !strokeOnTop, let strokeFrame = strokeFrame { + if !strokeOnTop, let strokeFrame { CTFrameDraw(strokeFrame, ctx) } - if let fillFrame = fillFrame { + if let fillFrame { CTFrameDraw(fillFrame, ctx) } - if strokeOnTop, let strokeFrame = strokeFrame { + if strokeOnTop, let strokeFrame { CTFrameDraw(strokeFrame, ctx) } } @@ -186,7 +186,7 @@ final class CoreTextRenderLayer: CALayer { // Draws Debug colors for the font alignment. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) private func drawDebug(_ ctx: CGContext) { - if let font = font { + if let font { let ascent = CTFontGetAscent(font) let descent = CTFontGetDescent(font) let capHeight = CTFontGetCapHeight(font) @@ -224,7 +224,7 @@ final class CoreTextRenderLayer: CALayer { private func updateTextContent() { guard needsContentUpdate else { return } needsContentUpdate = false - guard let font = font, let text = text, text.count > 0, fillColor != nil || strokeColor != nil else { + guard let font, let text, text.count > 0, fillColor != nil || strokeColor != nil else { drawingRect = .zero drawingAnchor = .zero attributedString = nil @@ -256,7 +256,7 @@ final class CoreTextRenderLayer: CALayer { NSAttributedString.Key.paragraphStyle: paragraphStyle, ] - if let fillColor = fillColor { + if let fillColor { attributes[NSAttributedString.Key.foregroundColor] = fillColor } @@ -270,7 +270,7 @@ final class CoreTextRenderLayer: CALayer { fillFrameSetter = nil } - if let strokeColor = strokeColor { + if let strokeColor { attributes[NSAttributedString.Key.foregroundColor] = nil attributes[NSAttributedString.Key.strokeWidth] = strokeWidth attributes[NSAttributedString.Key.strokeColor] = strokeColor @@ -287,7 +287,7 @@ final class CoreTextRenderLayer: CALayer { // Calculate drawing size and anchor offset let textAnchor: CGPoint - if let preferredSize = preferredSize { + if let preferredSize { drawingRect = CGRect(origin: .zero, size: preferredSize) drawingRect.size.height += (ascent - capHeight) drawingRect.size.height += descent @@ -332,7 +332,7 @@ final class CoreTextRenderLayer: CALayer { extension CGContext { fileprivate func adjustWithLineOrigins(in frame: CTFrame, with font: CTFont?) { - guard let font = font else { return } + guard let font else { return } let count = CFArrayGetCount(CTFrameGetLines(frame)) diff --git a/Sources/Private/MainThread/LayerContainers/Utility/InvertedMatteLayer.swift b/Sources/Private/MainThread/LayerContainers/Utility/InvertedMatteLayer.swift index 8c726d1c54..c96277c1a2 100644 --- a/Sources/Private/MainThread/LayerContainers/Utility/InvertedMatteLayer.swift +++ b/Sources/Private/MainThread/LayerContainers/Utility/InvertedMatteLayer.swift @@ -45,7 +45,7 @@ final class InvertedMatteLayer: CALayer, CompositionLayerDelegate { } override func draw(in ctx: CGContext) { - guard let inputMatte = inputMatte else { return } + guard let inputMatte else { return } ctx.setFillColor(.rgb(0, 0, 0)) ctx.fill(bounds) ctx.setBlendMode(.destinationOut) diff --git a/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift b/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift index b3a9215b4a..db531f85c0 100644 --- a/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift +++ b/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift @@ -13,7 +13,7 @@ final class LayerImageProvider { init(imageProvider: AnimationImageProvider, assets: [String: ImageAsset]?) { self.imageProvider = imageProvider imageLayers = [ImageCompositionLayer]() - if let assets = assets { + if let assets { imageAssets = assets } else { imageAssets = [:] diff --git a/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift b/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift index 14582acd45..24f7930be2 100644 --- a/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift +++ b/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift @@ -15,7 +15,7 @@ final class NodeTree { var childrenNodes: [AnimatorNode] = [] } -extension Array where Element == ShapeItem { +extension [ShapeItem] { func initializeNodeTree() -> NodeTree { let nodeTree = NodeTree() diff --git a/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift b/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift index fd571443a1..6c54d4919a 100644 --- a/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift +++ b/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift @@ -57,7 +57,7 @@ class GroupOutputNode: NodeOutput { } var xform = CATransform3DGetAffineTransform(transform) if - let rootNode = rootNode, + let rootNode, let rootPath = rootNode.outputPath, let xformedPath = rootPath.copy(using: &xform) { diff --git a/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift b/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift index 07ea6c24b9..f044b7ba4b 100644 --- a/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift +++ b/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift @@ -23,7 +23,7 @@ class PassThroughOutputNode: NodeOutput { var isEnabled = true var outputPath: CGPath? { - if let parent = parent { + if let parent { return parent.outputPath } return nil diff --git a/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift b/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift index d1171f2cbe..342c5709c2 100644 --- a/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +++ b/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift @@ -131,7 +131,7 @@ final class StrokeRenderer: PassThroughOutputNode, Renderable { inContext.setMiterLimit(miterLimit) inContext.setLineCap(lineCap.cgLineCap) inContext.setLineJoin(lineJoin.cgLineJoin) - if let dashPhase = dashPhase, let lengths = dashLengths { + if let dashPhase, let lengths = dashLengths { inContext.setLineDash(phase: dashPhase, lengths: lengths) } else { inContext.setLineDash(phase: 0, lengths: []) @@ -142,7 +142,7 @@ final class StrokeRenderer: PassThroughOutputNode, Renderable { guard inContext.path != nil, inContext.path!.isEmpty == false else { return } - guard let color = color else { return } + guard let color else { return } hasUpdate = false setupForStroke(inContext) inContext.setAlpha(opacity) diff --git a/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift b/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift index 4ac2286f33..ddda7a3cc7 100644 --- a/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +++ b/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift @@ -14,7 +14,7 @@ final class GroupNodeProperties: NodePropertyMap, KeypathSearchable { // MARK: Lifecycle init(transform: ShapeTransform?) { - if let transform = transform { + if let transform { anchor = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.anchor.keyframes)) position = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.position.keyframes)) scale = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.scale.keyframes)) diff --git a/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift b/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift index 6037522bbe..c3bbb5f65f 100644 --- a/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +++ b/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift @@ -131,7 +131,7 @@ final class StrokeNode: AnimatorNode, RenderNode { // MARK: - [DashElement] + shapeLayerConfiguration -extension Array where Element == DashElement { +extension [DashElement] { typealias ShapeLayerConfiguration = ( dashPatterns: ContiguousArray>>, dashPhase: ContiguousArray>) @@ -168,7 +168,7 @@ extension Array where Element == DashElement { } } -extension Array where Element == CGFloat { +extension [CGFloat] { // If all of the items in the dash pattern are zeros, then we shouldn't attempt to render it. // This causes Core Animation to have extremely poor performance for some reason, even though // it doesn't affect the appearance of the animation. diff --git a/Sources/Private/Model/Assets/Asset.swift b/Sources/Private/Model/Assets/Asset.swift index f3c3962589..97df6b3e0c 100644 --- a/Sources/Private/Model/Assets/Asset.swift +++ b/Sources/Private/Model/Assets/Asset.swift @@ -46,4 +46,5 @@ public class Asset: Codable, DictionaryInitializable { /// Since `Asset` isn't `final`, we have to use `@unchecked Sendable` instead of `Sendable.` /// All `Asset` subclasses are immutable `Sendable` values. +// swiftlint:disable:next no_unchecked_sendable extension Asset: @unchecked Sendable { } diff --git a/Sources/Private/Model/DictionaryInitializable.swift b/Sources/Private/Model/DictionaryInitializable.swift index 7e6afc87e8..3a2c67df02 100644 --- a/Sources/Private/Model/DictionaryInitializable.swift +++ b/Sources/Private/Model/DictionaryInitializable.swift @@ -51,9 +51,9 @@ extension Dictionary { } -// MARK: - Array + AnyInitializable +// MARK: - AnyInitializable + AnyInitializable -extension Array: AnyInitializable where Element == Double { +extension [Double]: AnyInitializable { init(value: Any) throws { guard let array = value as? [Double] else { diff --git a/Sources/Private/Model/DotLottie/DotLottieUtils.swift b/Sources/Private/Model/DotLottie/DotLottieUtils.swift index 1efcd1d9c0..72994dec25 100644 --- a/Sources/Private/Model/DotLottie/DotLottieUtils.swift +++ b/Sources/Private/Model/DotLottie/DotLottieUtils.swift @@ -9,7 +9,7 @@ import Foundation // MARK: - DotLottieUtils -struct DotLottieUtils { +enum DotLottieUtils { static let dotLottieExtension = "lottie" static let jsonExtension = "json" diff --git a/Sources/Private/Model/Keyframes/KeyframeData.swift b/Sources/Private/Model/Keyframes/KeyframeData.swift index 39151608a3..753d7f0283 100644 --- a/Sources/Private/Model/Keyframes/KeyframeData.swift +++ b/Sources/Private/Model/Keyframes/KeyframeData.swift @@ -69,7 +69,7 @@ final class KeyframeData { let spatialOutTangent: LottieVector3D? var isHold: Bool { - if let hold = hold { + if let hold { return hold > 0 } return false diff --git a/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift b/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift index de4c9db39a..8cae5e599e 100644 --- a/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift +++ b/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift @@ -68,7 +68,7 @@ class EffectValue: Codable, DictionaryInitializable { } } -extension Array where Element == EffectValue { +extension [EffectValue] { static func fromDictionaries(_ dictionaries: [[String: Any]]) throws -> [EffectValue] { try dictionaries.compactMap { dictionary in let shapeType = dictionary[EffectValue.CodingKeys.type.rawValue] as? Int @@ -93,4 +93,5 @@ extension Array where Element == EffectValue { /// Since `EffectValue` isn't `final`, we have to use `@unchecked Sendable` instead of `Sendable.` /// All `EffectValue` subclasses are immutable `Sendable` values. +// swiftlint:disable:next no_unchecked_sendable extension EffectValue: @unchecked Sendable { } diff --git a/Sources/Private/Model/LayerEffects/LayerEffect.swift b/Sources/Private/Model/LayerEffects/LayerEffect.swift index 1e3cb89fd8..9bb8c27c05 100644 --- a/Sources/Private/Model/LayerEffects/LayerEffect.swift +++ b/Sources/Private/Model/LayerEffects/LayerEffect.swift @@ -79,7 +79,7 @@ class LayerEffect: Codable, DictionaryInitializable { } } -extension Array where Element == LayerEffect { +extension [LayerEffect] { static func fromDictionaries(_ dictionaries: [[String: Any]]) throws -> [LayerEffect] { try dictionaries.compactMap { dictionary in let shapeType = dictionary[LayerEffect.CodingKeys.type.rawValue] as? Int @@ -98,4 +98,5 @@ extension Array where Element == LayerEffect { /// Since `LayerEffect` isn't `final`, we have to use `@unchecked Sendable` instead of `Sendable.` /// All `LayerEffect` subclasses are immutable `Sendable` values. +// swiftlint:disable:next no_unchecked_sendable extension LayerEffect: @unchecked Sendable { } diff --git a/Sources/Private/Model/LayerStyles/LayerStyle.swift b/Sources/Private/Model/LayerStyles/LayerStyle.swift index ed55b316e8..b6ef1c32d4 100644 --- a/Sources/Private/Model/LayerStyles/LayerStyle.swift +++ b/Sources/Private/Model/LayerStyles/LayerStyle.swift @@ -61,7 +61,7 @@ class LayerStyle: Codable, DictionaryInitializable { } } -extension Array where Element == LayerStyle { +extension [LayerStyle] { static func fromDictionaries(_ dictionaries: [[String: Any]]) throws -> [LayerStyle] { try dictionaries.compactMap { dictionary in let shapeType = dictionary[LayerStyle.CodingKeys.type.rawValue] as? Int @@ -80,4 +80,5 @@ extension Array where Element == LayerStyle { /// Since `LayerStyle` isn't `final`, we have to use `@unchecked Sendable` instead of `Sendable.` /// All `LayerStyle` subclasses are immutable `Sendable` values. +// swiftlint:disable:next no_unchecked_sendable extension LayerStyle: @unchecked Sendable { } diff --git a/Sources/Private/Model/Layers/LayerModel.swift b/Sources/Private/Model/Layers/LayerModel.swift index 48978b176d..aa6e600596 100644 --- a/Sources/Private/Model/Layers/LayerModel.swift +++ b/Sources/Private/Model/Layers/LayerModel.swift @@ -224,7 +224,7 @@ class LayerModel: Codable, DictionaryInitializable { } } -extension Array where Element == LayerModel { +extension [LayerModel] { static func fromDictionaries(_ dictionaries: [[String: Any]]) throws -> [LayerModel] { try dictionaries.compactMap { dictionary in @@ -255,4 +255,5 @@ extension Array where Element == LayerModel { /// Since `LayerModel` isn't `final`, we have to use `@unchecked Sendable` instead of `Sendable.` /// All `LayerModel` subclasses are immutable `Sendable` values. +// swiftlint:disable:next no_unchecked_sendable extension LayerModel: @unchecked Sendable { } diff --git a/Sources/Private/Model/ShapeItems/ShapeItem.swift b/Sources/Private/Model/ShapeItems/ShapeItem.swift index 3e0fe551c6..5911a69147 100644 --- a/Sources/Private/Model/ShapeItems/ShapeItem.swift +++ b/Sources/Private/Model/ShapeItems/ShapeItem.swift @@ -120,7 +120,7 @@ class ShapeItem: Codable, DictionaryInitializable { } } -extension Array where Element == ShapeItem { +extension [ShapeItem] { static func fromDictionaries(_ dictionaries: [[String: Any]]) throws -> [ShapeItem] { try dictionaries.compactMap { dictionary in @@ -167,4 +167,5 @@ extension Array where Element == ShapeItem { /// Since `ShapeItem` isn't `final`, we have to use `@unchecked Sendable` instead of `Sendable.` /// All `ShapeItem` subclasses are immutable `Sendable` values. +// swiftlint:disable:next no_unchecked_sendable extension ShapeItem: @unchecked Sendable { } diff --git a/Sources/Private/Utility/Debugging/LayerDebugging.swift b/Sources/Private/Utility/Debugging/LayerDebugging.swift index 2e29b5706a..5081ee985d 100644 --- a/Sources/Private/Utility/Debugging/LayerDebugging.swift +++ b/Sources/Private/Utility/Debugging/LayerDebugging.swift @@ -53,7 +53,7 @@ extension CALayer { } string = string + "|_" + String(describing: self) LottieLogger.shared.info(string) - if let sublayers = sublayers { + if let sublayers { for sublayer in sublayers { sublayer.logLayerTree(withIndent: withIndent + 1) } @@ -79,7 +79,7 @@ extension CALayer { sublayers = cust.layerForDebugging().sublayers } - if let sublayers = sublayers { + if let sublayers { for i in 0.. AnimationKeypath? { guard - let currentKey = currentKey, + let currentKey, currentKey.equalsKeypath(keyname), keys.count > 1 else { @@ -214,7 +214,7 @@ extension AnimationKeypath { if currentKey.keyPathType == .fuzzyWildcard { /// Dont remove if current key is a fuzzy wildcard, and if the next keypath doesnt equal keypathname if - let nextKeypath = nextKeypath, + let nextKeypath, nextKeypath.equalsKeypath(keyname) { /// Remove next two keypaths. This keypath breaks the wildcard. diff --git a/Sources/Private/Utility/Helpers/AnimationContext.swift b/Sources/Private/Utility/Helpers/AnimationContext.swift index 5a54b80c80..8d6cba046c 100644 --- a/Sources/Private/Utility/Helpers/AnimationContext.swift +++ b/Sources/Private/Utility/Helpers/AnimationContext.swift @@ -70,13 +70,13 @@ class AnimationCompletionDelegate: NSObject, CAAnimationDelegate { public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { guard ignoreDelegate == false else { return } animationState = flag ? .complete : .cancelled - if let animationLayer = animationLayer, let key = animationKey { + if let animationLayer, let key = animationKey { animationLayer.removeAnimation(forKey: key) if flag { animationLayer.currentFrame = (anim as! CABasicAnimation).toValue as! CGFloat } } - if let completionBlock = completionBlock { + if let completionBlock { completionBlock(flag) } } diff --git a/Sources/Private/Utility/Primitives/VectorsExtensions.swift b/Sources/Private/Utility/Primitives/VectorsExtensions.swift index 0fb7423be9..94432847c7 100644 --- a/Sources/Private/Utility/Primitives/VectorsExtensions.swift +++ b/Sources/Private/Utility/Primitives/VectorsExtensions.swift @@ -322,7 +322,7 @@ extension CATransform3D { skewAxis: CGFloat?) -> CATransform3D { - if let skew = skew, let skewAxis = skewAxis { + if let skew, let skewAxis { return CATransform3DMakeTranslation(position.x, position.y, 0) .rotated(rotationX, axis: .x) .rotated(rotationY, axis: .y) diff --git a/Sources/Public/Animation/LottieAnimation.swift b/Sources/Public/Animation/LottieAnimation.swift index 3af4844ed8..67e9645c3e 100644 --- a/Sources/Public/Animation/LottieAnimation.swift +++ b/Sources/Public/Animation/LottieAnimation.swift @@ -37,7 +37,7 @@ public final class LottieAnimation: Codable, Sendable, DictionaryInitializable { assetLibrary = try container.decodeIfPresent(AssetLibrary.self, forKey: .assetLibrary) markers = try container.decodeIfPresent([Marker].self, forKey: .markers) - if let markers = markers { + if let markers { var markerMap: [String: Marker] = [:] for marker in markers { markerMap[marker.name] = marker @@ -107,7 +107,7 @@ public final class LottieAnimation: Codable, Sendable, DictionaryInitializable { /// Return all marker names, in order, or an empty list if none are specified public var markerNames: [String] { - guard let markers = markers else { return [] } + guard let markers else { return [] } return markers.map { $0.name } } diff --git a/Sources/Public/Animation/LottieAnimationHelpers.swift b/Sources/Public/Animation/LottieAnimationHelpers.swift index 16bd72bb91..fbfd081f8c 100644 --- a/Sources/Public/Animation/LottieAnimationHelpers.swift +++ b/Sources/Public/Animation/LottieAnimationHelpers.swift @@ -50,7 +50,7 @@ extension LottieAnimation { /// Check cache for animation if - let animationCache = animationCache, + let animationCache, let animation = animationCache.animation(forKey: cacheKey) { /// If found, return the animation. @@ -82,7 +82,7 @@ extension LottieAnimation { { /// Check cache for animation if - let animationCache = animationCache, + let animationCache, let animation = animationCache.animation(forKey: filepath) { return animation @@ -119,7 +119,7 @@ extension LottieAnimation { /// Check cache for animation if - let animationCache = animationCache, + let animationCache, let animation = animationCache.animation(forKey: cacheKey) { /// If found, return the animation. @@ -201,7 +201,7 @@ extension LottieAnimation { closure: @escaping LottieAnimation.DownloadClosure, animationCache: AnimationCacheProvider? = LottieAnimationCache.shared) { - if let animationCache = animationCache, let animation = animationCache.animation(forKey: url.absoluteString) { + if let animationCache, let animation = animationCache.animation(forKey: url.absoluteString) { closure(animation) } else { let task = session.dataTask(with: url) { data, _, error in @@ -316,4 +316,6 @@ extension LottieAnimation { /// This retroactive conformance is safe because Sendable is a marker protocol that doesn't /// include any runtime component. Multiple modules in the same package graph can provide this /// conformance without causing any conflicts. +/// +// swiftlint:disable:next no_unchecked_sendable extension Foundation.Bundle: @unchecked Sendable { } diff --git a/Sources/Public/Animation/LottieAnimationLayer.swift b/Sources/Public/Animation/LottieAnimationLayer.swift index 9f27810523..456afa9f04 100644 --- a/Sources/Public/Animation/LottieAnimationLayer.swift +++ b/Sources/Public/Animation/LottieAnimationLayer.swift @@ -31,7 +31,7 @@ public class LottieAnimationLayer: CALayer { self.logger = logger super.init() makeAnimationLayer(usingEngine: configuration.renderingEngine) - if let animation = animation { + if let animation { frame = animation.bounds } } @@ -57,7 +57,7 @@ public class LottieAnimationLayer: CALayer { loopMode = dotLottieAnimation?.configuration.loopMode ?? .playOnce animationSpeed = CGFloat(dotLottieAnimation?.configuration.speed ?? 1) makeAnimationLayer(usingEngine: configuration.renderingEngine) - if let animation = animation { + if let animation { frame = animation.bounds } } @@ -103,7 +103,7 @@ public class LottieAnimationLayer: CALayer { /// /// - Parameter completion: An optional completion closure to be called when the animation completes playing. open func play(completion: LottieCompletionBlock? = nil) { - guard let animation = animation else { return } + guard let animation else { return } defer { currentPlaybackMode = .playing(.fromProgress(nil, toProgress: 1, loopMode: loopMode)) @@ -135,7 +135,7 @@ public class LottieAnimationLayer: CALayer { loopMode: LottieLoopMode? = nil, completion: LottieCompletionBlock? = nil) { - guard let animation = animation else { return } + guard let animation else { return } defer { currentPlaybackMode = .playing(.fromProgress(fromProgress, toProgress: toProgress, loopMode: loopMode ?? self.loopMode)) @@ -147,7 +147,7 @@ public class LottieAnimationLayer: CALayer { } removeCurrentAnimationIfNecessary() - if let loopMode = loopMode { + if let loopMode { /// Set the loop mode, if one was supplied self.loopMode = loopMode } @@ -180,7 +180,7 @@ public class LottieAnimationLayer: CALayer { } removeCurrentAnimationIfNecessary() - if let loopMode = loopMode { + if let loopMode { /// Set the loop mode, if one was supplied self.loopMode = loopMode } @@ -227,12 +227,12 @@ public class LottieAnimationLayer: CALayer { return } - guard let animation = animation, let markers = animation.markerMap, let to = markers[toMarker] else { + guard let animation, let markers = animation.markerMap, let to = markers[toMarker] else { return } removeCurrentAnimationIfNecessary() - if let loopMode = loopMode { + if let loopMode { /// Set the loop mode, if one was supplied self.loopMode = loopMode } @@ -330,7 +330,7 @@ public class LottieAnimationLayer: CALayer { // If the completion handler is called with `completed: false` (which typically means // that another animation was played by calling some `play` method), // we should cancel the marker sequence and not play the next marker. - guard completed, let self = self else { + guard completed, let self else { completion?(false) return } @@ -487,7 +487,7 @@ public class LottieAnimationLayer: CALayer { /// A closure called when the animation layer has been loaded. /// Will inform the receiver the type of rendering engine that is used for the layer. - public var animationLayerDidLoad:((_ animationLayer: LottieAnimationLayer, _ renderingEngine: RenderingEngineOption) -> Void)? + public var animationLayerDidLoad: ((_ animationLayer: LottieAnimationLayer, _ renderingEngine: RenderingEngineOption) -> Void)? /// The configuration that this `LottieAnimationView` uses when playing its animation public var configuration: LottieConfiguration { @@ -548,7 +548,7 @@ public class LottieAnimationLayer: CALayer { didSet { makeAnimationLayer(usingEngine: configuration.renderingEngine) - if let animation = animation { + if let animation { animationLoaded?(self, animation) } } @@ -583,7 +583,7 @@ public class LottieAnimationLayer: CALayer { /// ``` public var animationLoaded: ((_ animationLayer: LottieAnimationLayer, _ animation: LottieAnimation) -> Void)? { didSet { - if let animation = animation { + if let animation { animationLoaded?(self, animation) } } @@ -661,7 +661,7 @@ public class LottieAnimationLayer: CALayer { /// Note 2: If `animation` is nil, setting this will fallback to 0 public var currentProgress: AnimationProgressTime { set { - if let animation = animation { + if let animation { currentFrame = animation.frameTime(forProgress: newValue) currentPlaybackMode = .paused(at: .progress(newValue)) } else { @@ -669,7 +669,7 @@ public class LottieAnimationLayer: CALayer { } } get { - if let animation = animation { + if let animation { return animation.progressTime(forFrame: currentFrame) } else { return 0 @@ -683,7 +683,7 @@ public class LottieAnimationLayer: CALayer { /// Note 2: If `animation` is nil, setting this will fallback to 0 public var currentTime: TimeInterval { set { - if let animation = animation { + if let animation { currentFrame = animation.frameTime(forTime: newValue) currentPlaybackMode = .paused(at: .time(newValue)) } else { @@ -691,7 +691,7 @@ public class LottieAnimationLayer: CALayer { } } get { - if let animation = animation { + if let animation { return animation.time(forFrame: currentFrame) } else { return 0 @@ -720,7 +720,7 @@ public class LottieAnimationLayer: CALayer { /// Returns the current animation frame while an animation is playing. public var realtimeAnimationProgress: AnimationProgressTime { - if let animation = animation { + if let animation { return animation.progressTime(forFrame: realtimeAnimationFrame) } return 0 @@ -753,7 +753,7 @@ public class LottieAnimationLayer: CALayer { return engine case .automatic: - guard let animationLayer = animationLayer else { + guard let animationLayer else { return nil } @@ -892,7 +892,7 @@ public class LottieAnimationLayer: CALayer { /// - Parameter toLayerAt: The keypath used to find the layer. public func convert(_ rect: CGRect, toLayerAt keypath: AnimationKeypath?) -> CGRect? { guard let animationLayer = rootAnimationLayer else { return nil } - guard let keypath = keypath else { + guard let keypath else { return convert(rect, to: animationLayer) } guard let sublayer = animationLayer.layer(for: keypath) else { @@ -913,7 +913,7 @@ public class LottieAnimationLayer: CALayer { /// - Parameter toLayerAt: The keypath used to find the layer. public func convert(_ point: CGPoint, toLayerAt keypath: AnimationKeypath?) -> CGPoint? { guard let animationLayer = rootAnimationLayer else { return nil } - guard let keypath = keypath else { + guard let keypath else { return convert(point, to: animationLayer) } guard let sublayer = animationLayer.layer(for: keypath) else { @@ -933,7 +933,7 @@ public class LottieAnimationLayer: CALayer { public func setNodeIsEnabled(isEnabled: Bool, keypath: AnimationKeypath) { guard let animationLayer = rootAnimationLayer else { return } let nodes = animationLayer.animatorNodes(for: keypath) - if let nodes = nodes { + if let nodes { for node in nodes { node.isEnabled = isEnabled } @@ -950,7 +950,7 @@ public class LottieAnimationLayer: CALayer { /// /// Returns the Progress Time for the marker named. Returns nil if no marker found. public func progressTime(forMarker named: String) -> AnimationProgressTime? { - guard let animation = animation else { + guard let animation else { return nil } return animation.progressTime(forMarker: named) @@ -965,7 +965,7 @@ public class LottieAnimationLayer: CALayer { /// /// Returns the Frame Time for the marker named. Returns nil if no marker found. public func frameTime(forMarker named: String) -> AnimationFrameTime? { - guard let animation = animation else { + guard let animation else { return nil } return animation.frameTime(forMarker: named) @@ -980,7 +980,7 @@ public class LottieAnimationLayer: CALayer { /// /// - Returns: The duration frame time for the marker, or `nil` if no marker found. public func durationFrameTime(forMarker named: String) -> AnimationFrameTime? { - guard let animation = animation else { + guard let animation else { return nil } return animation.durationFrameTime(forMarker: named) @@ -1073,7 +1073,7 @@ public class LottieAnimationLayer: CALayer { /// Updates an in flight animation. func updateInFlightAnimation() { - guard let animationContext = animationContext else { return } + guard let animationContext else { return } guard animationContext.closure.animationState != .complete else { // Tried to re-add an already completed animation. Cancel. @@ -1145,7 +1145,7 @@ public class LottieAnimationLayer: CALayer { rootAnimationLayer = nil } - guard let animation = animation else { + guard let animation else { return } let rootAnimationLayer: RootAnimationLayer? @@ -1293,7 +1293,7 @@ public class LottieAnimationLayer: CALayer { // was being used by the previous Core Animation layer self.currentFrame = currentFrame - if let animationContext = animationContext { + if let animationContext { // `AnimationContext.closure` (`AnimationCompletionDelegate`) is a reference type // that is the animation layer's `CAAnimationDelegate`, and holds a reference to // the animation layer. Reusing a single instance across different animation layers @@ -1327,7 +1327,7 @@ public class LottieAnimationLayer: CALayer { /// Adds animation to animation layer and sets the delegate. If animation layer or animation are nil, exits. fileprivate func addNewAnimationForContext(_ animationContext: AnimationContext) { - guard let animationlayer = rootAnimationLayer, let animation = animation else { + guard let animationlayer = rootAnimationLayer, let animation else { return } @@ -1494,7 +1494,7 @@ public class LottieAnimationLayer: CALayer { /// Plays the marker that corresponds to the current "reduced motion" mode if present. private func playReducedMotionAnimation(completion: LottieCompletionBlock?) { - guard let reducedMotionMarker = reducedMotionMarker else { return } + guard let reducedMotionMarker else { return } // `play(marker:)` calls the `play(fromFrame:toFrame:)` method which calls this // `playReducedMotionAnimation` method when `shouldOverrideWithReducedMotionAnimation` diff --git a/Sources/Public/Animation/LottieAnimationView.swift b/Sources/Public/Animation/LottieAnimationView.swift index d34c07a752..09e225a0d3 100644 --- a/Sources/Public/Animation/LottieAnimationView.swift +++ b/Sources/Public/Animation/LottieAnimationView.swift @@ -114,7 +114,7 @@ open class LottieAnimationView: LottieAnimationViewBase { self.logger = logger super.init(frame: .zero) commonInit() - if let animation = animation { + if let animation { frame = animation.bounds } } @@ -138,7 +138,7 @@ open class LottieAnimationView: LottieAnimationViewBase { self.logger = logger super.init(frame: .zero) commonInit() - if let animation = animation { + if let animation { frame = animation.bounds } } @@ -437,7 +437,7 @@ open class LottieAnimationView: LottieAnimationViewBase { /// ``` public var animationLoaded: ((_ animationView: LottieAnimationView, _ animation: LottieAnimation) -> Void)? { didSet { - if let animation = animation { + if let animation { animationLoaded?(self, animation) } } @@ -834,14 +834,14 @@ open class LottieAnimationView: LottieAnimationViewBase { viewLayer?.addSublayer(lottieAnimationLayer) lottieAnimationLayer.animationLoaded = { [weak self] _, animation in - guard let self = self else { return } + guard let self else { return } self.animationLoaded?(self, animation) self.invalidateIntrinsicContentSize() self.setNeedsLayout() } lottieAnimationLayer.animationLayerDidLoad = { [weak self] _, _ in - guard let self = self else { return } + guard let self else { return } self.invalidateIntrinsicContentSize() self.setNeedsLayout() } @@ -854,7 +854,7 @@ open class LottieAnimationView: LottieAnimationViewBase { let xform: CATransform3D var shouldForceUpdates = false - if let viewportFrame = viewportFrame { + if let viewportFrame { setNeedsLayout() shouldForceUpdates = contentMode == .redraw diff --git a/Sources/Public/Animation/LottieAnimationViewInitializers.swift b/Sources/Public/Animation/LottieAnimationViewInitializers.swift index aa8aa02f95..a2bc01dbd8 100644 --- a/Sources/Public/Animation/LottieAnimationViewInitializers.swift +++ b/Sources/Public/Animation/LottieAnimationViewInitializers.swift @@ -62,14 +62,14 @@ extension LottieAnimationView { animationCache: AnimationCacheProvider? = LottieAnimationCache.shared, configuration: LottieConfiguration = .shared) { - if let animationCache = animationCache, let animation = animationCache.animation(forKey: url.absoluteString) { + if let animationCache, let animation = animationCache.animation(forKey: url.absoluteString) { self.init(animation: animation, imageProvider: imageProvider, configuration: configuration) closure(nil) } else { self.init(animation: nil, imageProvider: imageProvider, configuration: configuration) LottieAnimation.loadedFrom(url: url, session: session, closure: { animation in - if let animation = animation { + if let animation { self.animation = animation closure(nil) } else { @@ -166,7 +166,7 @@ extension LottieAnimationView { session: URLSession = .shared, completion: ((LottieAnimationView, Error?) -> Void)? = nil) { - if let dotLottieCache = dotLottieCache, let lottie = dotLottieCache.file(forKey: url.absoluteString) { + if let dotLottieCache, let lottie = dotLottieCache.file(forKey: url.absoluteString) { self.init(dotLottie: lottie, animationId: animationId, configuration: configuration) completion?(self, nil) } else { diff --git a/Sources/Public/Animation/LottieView.swift b/Sources/Public/Animation/LottieView.swift index 6eb5640253..a610c177b8 100644 --- a/Sources/Public/Animation/LottieView.swift +++ b/Sources/Public/Animation/LottieView.swift @@ -116,7 +116,7 @@ public struct LottieView: UIViewConfiguringSwiftUIView { public var body: some View { ZStack { - if let animationSource = animationSource { + if let animationSource { LottieAnimationView.swiftUIView { defer { animationDidLoad?(animationSource) } return LottieAnimationView( @@ -138,7 +138,7 @@ public struct LottieView: UIViewConfiguringSwiftUIView { } if - let playbackMode = playbackMode, + let playbackMode, playbackMode != context.view.currentPlaybackMode { context.view.setPlaybackMode(playbackMode, completion: animationCompletionHandler) @@ -351,7 +351,7 @@ public struct LottieView: UIViewConfiguringSwiftUIView { /// - If the `animationProgress` is `nil`, no changes will be made and any existing animations /// will continue playing uninterrupted. public func currentProgress(_ currentProgress: AnimationProgressTime?) -> Self { - guard let currentProgress = currentProgress else { return self } + guard let currentProgress else { return self } var copy = self copy.playbackMode = .paused(at: .progress(currentProgress)) return copy @@ -363,7 +363,7 @@ public struct LottieView: UIViewConfiguringSwiftUIView { /// - If the `currentFrame` is `nil`, no changes will be made and any existing animations /// will continue playing uninterrupted. public func currentFrame(_ currentFrame: AnimationFrameTime?) -> Self { - guard let currentFrame = currentFrame else { return self } + guard let currentFrame else { return self } var copy = self copy.playbackMode = .paused(at: .frame(currentFrame)) return copy @@ -375,7 +375,7 @@ public struct LottieView: UIViewConfiguringSwiftUIView { /// - If the `currentTime` is `nil`, no changes will be made and any existing animations /// will continue playing uninterrupted. public func currentTime(_ currentTime: TimeInterval?) -> Self { - guard let currentTime = currentTime else { return self } + guard let currentTime else { return self } var copy = self copy.playbackMode = .paused(at: .time(currentTime)) return copy @@ -391,7 +391,7 @@ public struct LottieView: UIViewConfiguringSwiftUIView { /// - showPlaceholder: When `true`, the current animation will be removed before invoking `loadAnimation`, /// displaying the `Placeholder` until the new animation loads. /// When `false`, the previous animation remains visible while the new one loads. - public func reloadAnimationTrigger(_ value: Value, showPlaceholder: Bool = true) -> Self { + public func reloadAnimationTrigger(_ value: some Equatable, showPlaceholder: Bool = true) -> Self { var copy = self copy.reloadAnimationTrigger = AnyEquatable(value) copy.showPlaceholderWhileReloading = showPlaceholder @@ -409,7 +409,7 @@ public struct LottieView: UIViewConfiguringSwiftUIView { public func getRealtimeAnimationProgress(_ realtimeAnimationProgress: Binding?) -> some View { TimelineView(.animation(paused: realtimeAnimationProgress == nil)) { _ in configure { view in - if let realtimeAnimationProgress = realtimeAnimationProgress { + if let realtimeAnimationProgress { DispatchQueue.main.async { realtimeAnimationProgress.wrappedValue = view.realtimeAnimationProgress } @@ -429,7 +429,7 @@ public struct LottieView: UIViewConfiguringSwiftUIView { public func getRealtimeAnimationFrame(_ realtimeAnimationFrame: Binding?) -> some View { TimelineView(.animation(paused: realtimeAnimationFrame == nil)) { _ in configure { view in - if let realtimeAnimationFrame = realtimeAnimationFrame { + if let realtimeAnimationFrame { DispatchQueue.main.async { realtimeAnimationFrame.wrappedValue = view.realtimeAnimationFrame } @@ -460,7 +460,7 @@ public struct LottieView: UIViewConfiguringSwiftUIView { private let placeholder: (() -> Placeholder)? private func loadAnimationIfNecessary() { - guard let loadAnimation = loadAnimation else { return } + guard let loadAnimation else { return } Task { do { diff --git a/Sources/Public/AnimationCache/DefaultAnimationCache.swift b/Sources/Public/AnimationCache/DefaultAnimationCache.swift index 575810ef20..57f2a9b4c8 100644 --- a/Sources/Public/AnimationCache/DefaultAnimationCache.swift +++ b/Sources/Public/AnimationCache/DefaultAnimationCache.swift @@ -7,13 +7,15 @@ import Foundation +// MARK: - DefaultAnimationCache + /// A thread-safe Animation Cache that will store animations up to `cacheSize`. /// /// Once `cacheSize` is reached, animations can be ejected. /// The default size of the cache is 100. /// /// This cache implementation also responds to memory pressure. -public class DefaultAnimationCache: AnimationCacheProvider, @unchecked Sendable { +public class DefaultAnimationCache: AnimationCacheProvider { // MARK: Lifecycle @@ -55,3 +57,11 @@ public class DefaultAnimationCache: AnimationCacheProvider, @unchecked Sendable /// only when the app receives a memory warning notification. private let cache = LRUCache() } + +// MARK: Sendable + +// LottieAnimationCache has a Sendable requirement, but we can't +// redesign DefaultAnimationCache to be properly Sendable without +// making breaking changes. +// swiftlint:disable:next no_unchecked_sendable +extension DefaultAnimationCache: @unchecked Sendable { } diff --git a/Sources/Public/Controls/AnimatedButton.swift b/Sources/Public/Controls/AnimatedButton.swift index 2f09d4826c..1e91c67acd 100644 --- a/Sources/Public/Controls/AnimatedButton.swift +++ b/Sources/Public/Controls/AnimatedButton.swift @@ -66,7 +66,7 @@ open class AnimatedButton: AnimatedControl { open override func endTracking(_ touch: UITouch?, with event: UIEvent?) { super.endTracking(touch, with: event) let touchEvent: UIControl.Event - if let touch = touch, bounds.contains(touch.location(in: self)) { + if let touch, bounds.contains(touch.location(in: self)) { touchEvent = UIControl.Event.touchUpInside performAction?() } else { @@ -121,7 +121,7 @@ open class AnimatedButton: AnimatedControl { // MARK: Private - private var rangesForEvents: [AnyHashable : (from: CGFloat, to: CGFloat)] = { - [LottieControlEvent.touchUpInside.id: (from: 0, to: 1)] - }() + private var rangesForEvents: [AnyHashable: (from: CGFloat, to: CGFloat)] = [LottieControlEvent.touchUpInside.id: ( + from: 0, + to: 1)] } diff --git a/Sources/Public/Controls/AnimatedControl.swift b/Sources/Public/Controls/AnimatedControl.swift index 595814eab2..ae2cdd563f 100644 --- a/Sources/Public/Controls/AnimatedControl.swift +++ b/Sources/Public/Controls/AnimatedControl.swift @@ -109,7 +109,7 @@ open class AnimatedControl: LottieControlType { #elseif canImport(AppKit) open override func mouseDown(with mouseDownEvent: NSEvent) { - guard let window = window else { return } + guard let window else { return } currentState = .highlighted updateForState() diff --git a/Sources/Public/Controls/AnimatedSwitch.swift b/Sources/Public/Controls/AnimatedSwitch.swift index 726297f928..899e2bd823 100644 --- a/Sources/Public/Controls/AnimatedSwitch.swift +++ b/Sources/Public/Controls/AnimatedSwitch.swift @@ -209,7 +209,7 @@ open class AnimatedSwitch: AnimatedControl { toProgress: endProgress, loopMode: LottieLoopMode.playOnce, completion: { [weak self] finished in - guard let self = self else { return } + guard let self else { return } // 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. diff --git a/Sources/Public/DotLottie/DotLottieFile.swift b/Sources/Public/DotLottie/DotLottieFile.swift index 3e121218a9..f29f418edd 100644 --- a/Sources/Public/DotLottie/DotLottieFile.swift +++ b/Sources/Public/DotLottie/DotLottieFile.swift @@ -55,7 +55,7 @@ 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 = id { + if let id { return animations.first(where: { $0.configuration.id == id }) } else { return animations.first @@ -150,4 +150,5 @@ extension String { // Mark `DotLottieFile` as `@unchecked Sendable` to allow it to be used when strict concurrency is enabled. // In the future, it may be necessary to make changes to the internal implementation of `DotLottieFile` // to make it truly thread-safe. +// swiftlint:disable:next no_unchecked_sendable extension DotLottieFile: @unchecked Sendable { } diff --git a/Sources/Public/DotLottie/DotLottieFileHelpers.swift b/Sources/Public/DotLottie/DotLottieFileHelpers.swift index 020bcbae74..bd9c09f38a 100644 --- a/Sources/Public/DotLottie/DotLottieFileHelpers.swift +++ b/Sources/Public/DotLottie/DotLottieFileHelpers.swift @@ -26,7 +26,7 @@ extension DotLottieFile { /// Check cache for lottie if - let dotLottieCache = dotLottieCache, + let dotLottieCache, let lottie = dotLottieCache.file(forKey: filepath) { return .success(lottie) @@ -68,7 +68,7 @@ extension DotLottieFile { /// Check cache for lottie if - let dotLottieCache = dotLottieCache, + let dotLottieCache, let lottie = dotLottieCache.file(forKey: cacheKey) { return .success(lottie) @@ -237,7 +237,7 @@ extension DotLottieFile { /// Check cache for lottie if - let dotLottieCache = dotLottieCache, + let dotLottieCache, let lottie = dotLottieCache.file(forKey: cacheKey) { /// If found, return the lottie. @@ -295,15 +295,15 @@ extension DotLottieFile { dotLottieCache: DotLottieCacheProvider? = DotLottieCache.sharedCache, handleResult: @escaping (Result) -> Void) { - if let dotLottieCache = dotLottieCache, let lottie = dotLottieCache.file(forKey: url.absoluteString) { + if let dotLottieCache, let lottie = dotLottieCache.file(forKey: url.absoluteString) { handleResult(.success(lottie)) } else { let task = session.dataTask(with: url) { data, _, error in do { - if let error = error { + if let error { throw error } - guard let data = data else { + guard let data else { throw DotLottieError.noDataLoaded } let lottie = try DotLottieFile(data: data, filename: url.deletingPathExtension().lastPathComponent) diff --git a/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift b/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift index 3e7e182852..a8680986c9 100644 --- a/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +++ b/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift @@ -60,12 +60,12 @@ public final class ColorValueProvider: ValueProvider { } public var storage: ValueProviderStorage { - if let block = block { + if let block { return .closure { frame in self.hasUpdate = false return block(frame) } - } else if let keyframes = keyframes { + } else if let keyframes { return .keyframes(keyframes) } else { hasUpdate = false diff --git a/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift b/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift index d00cb83842..fb22c2b9ef 100644 --- a/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +++ b/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift @@ -48,7 +48,7 @@ public final class FloatValueProvider: ValueProvider { } public var storage: ValueProviderStorage { - if let block = block { + if let block { return .closure { frame in self.hasUpdate = false return LottieVector1D(Double(block(frame))) diff --git a/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift b/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift index 1a837ada52..d15891b5d3 100644 --- a/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +++ b/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift @@ -69,7 +69,7 @@ public final class GradientValueProvider: ValueProvider { } public var storage: ValueProviderStorage<[Double]> { - if let block = block { + if let block { return .closure { [self] frame in hasUpdate = false diff --git a/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift b/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift index e7e799b92e..8b9703bfe8 100644 --- a/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +++ b/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift @@ -48,7 +48,7 @@ public final class PointValueProvider: ValueProvider { } public var storage: ValueProviderStorage { - if let block = block { + if let block { return .closure { frame in self.hasUpdate = false return block(frame).vector3dValue diff --git a/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift b/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift index e993a3e3bf..aa5cac9498 100644 --- a/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +++ b/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift @@ -48,7 +48,7 @@ public final class SizeValueProvider: ValueProvider { } public var storage: ValueProviderStorage { - if let block = block { + if let block { return .closure { frame in self.hasUpdate = false return block(frame).vector3dValue diff --git a/Sources/Public/iOS/BundleImageProvider.swift b/Sources/Public/iOS/BundleImageProvider.swift index 98de9c5f9f..5136a7acc5 100644 --- a/Sources/Public/iOS/BundleImageProvider.swift +++ b/Sources/Public/iOS/BundleImageProvider.swift @@ -41,7 +41,7 @@ public class BundleImageProvider: AnimationImageProvider { let imagePath: String? /// Try to find the image in the bundle. - if let searchPath = searchPath { + if let searchPath { /// Search in the provided search path for the image var directoryPath = URL(fileURLWithPath: searchPath) directoryPath.appendPathComponent(asset.directory) diff --git a/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift b/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift index 87a8cb2a9c..4e6acdc17c 100644 --- a/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +++ b/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift @@ -201,29 +201,25 @@ public final class CompatibleAnimationView: UIView { // MARK: Public - @objc - public var compatibleAnimation: CompatibleAnimation? { + @objc public var compatibleAnimation: CompatibleAnimation? { didSet { animationView.animation = compatibleAnimation?.animation } } - @objc - public var loopAnimationCount: CGFloat = 0 { + @objc public var loopAnimationCount: CGFloat = 0 { didSet { animationView.loopMode = loopAnimationCount == -1 ? .loop : .repeat(Float(loopAnimationCount)) } } - @objc - public var compatibleDictionaryTextProvider: CompatibleDictionaryTextProvider? { + @objc public var compatibleDictionaryTextProvider: CompatibleDictionaryTextProvider? { didSet { animationView.textProvider = compatibleDictionaryTextProvider?.textProvider ?? DefaultTextProvider() } } - @objc - public override var contentMode: UIView.ContentMode { + @objc public override var contentMode: UIView.ContentMode { set { animationView.contentMode = newValue } get { animationView.contentMode } } diff --git a/Sources/Public/macOS/BundleImageProvider.macOS.swift b/Sources/Public/macOS/BundleImageProvider.macOS.swift index ce84812c5a..f4cf9b8cd7 100644 --- a/Sources/Public/macOS/BundleImageProvider.macOS.swift +++ b/Sources/Public/macOS/BundleImageProvider.macOS.swift @@ -40,7 +40,7 @@ public class BundleImageProvider: AnimationImageProvider { let imagePath: String? /// Try to find the image in the bundle. - if let searchPath = searchPath { + if let searchPath { /// Search in the provided search path for the image var directoryPath = URL(fileURLWithPath: searchPath) directoryPath.appendPathComponent(asset.directory) diff --git a/Tests/AutomaticEngineTests.swift b/Tests/AutomaticEngineTests.swift index af6692a429..e179dc592f 100644 --- a/Tests/AutomaticEngineTests.swift +++ b/Tests/AutomaticEngineTests.swift @@ -18,7 +18,7 @@ final class AutomaticEngineTests: XCTestCase { animation = await Samples.dotLottie(named: sampleAnimationName)?.animations.first?.animation } - guard let animation = animation else { + guard let animation else { XCTFail("Couldn't load animation named \(sampleAnimationName)") continue } diff --git a/Tests/PerformanceTests.swift b/Tests/PerformanceTests.swift index 5da0db59ae..090250c83b 100644 --- a/Tests/PerformanceTests.swift +++ b/Tests/PerformanceTests.swift @@ -217,7 +217,7 @@ final class PerformanceTests: XCTestCase { return animationView } - private func measurePerformance(_ block : () throws -> Void) rethrows -> TimeInterval { + private func measurePerformance(_ block: () throws -> Void) rethrows -> TimeInterval { let start = DispatchTime.now() try block() let end = DispatchTime.now() diff --git a/lottie-ios.podspec b/lottie-ios.podspec index db239beb8f..ea4c259e34 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.6' + s.swift_version = '5.7' s.ios.deployment_target = '11.0' s.osx.deployment_target = '10.12' s.tvos.deployment_target = '11.0'