Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require Xcode 15 / Swift 5.9 #2400

Merged
merged 6 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading