Skip to content

Commit

Permalink
Require Xcode 15 / Swift 5.9 (#2400)
Browse files Browse the repository at this point in the history
  • Loading branch information
calda authored May 7, 2024
1 parent f01bc5f commit 1910aef
Show file tree
Hide file tree
Showing 74 changed files with 517 additions and 498 deletions.
40 changes: 6 additions & 34 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -88,44 +87,17 @@ jobs:

build-xcframework-minimum-supported-version:
name: "Build XCFramework"
runs-on: macos-13
runs-on: macos-14
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.
# 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
Expand Down
22 changes: 11 additions & 11 deletions Example/Example/AnimationListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}

Expand All @@ -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
}
}

Expand Down Expand Up @@ -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"
}
}
}
Expand All @@ -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
}
}
}
15 changes: 8 additions & 7 deletions Example/Example/AnimationPreviewView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand All @@ -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
}
}
}
Expand Down Expand Up @@ -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))
}
}

Expand Down Expand Up @@ -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
}
}

Expand Down
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.7
// swift-tools-version:5.9
import PackageDescription

let package = Package(
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,12 +280,12 @@ extension CALayer {
anchor, position, positionX, positionY, scale, rotationX, rotationY, rotationZ, skew, skewAxis
-> Hold<CATransform3D> 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,
Expand Down
12 changes: 6 additions & 6 deletions Sources/Private/CoreAnimation/CoreAnimationLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
14 changes: 7 additions & 7 deletions Sources/Private/CoreAnimation/Layers/AnimationLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down
24 changes: 12 additions & 12 deletions Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Loading

0 comments on commit 1910aef

Please sign in to comment.