Skip to content

Commit

Permalink
Fix .speed modifier for CocoaAnimations
Browse files Browse the repository at this point in the history
- Align with SwiftUI animations
- Add issue reporting
  • Loading branch information
maximkrouk committed Mar 4, 2025
1 parent db6bc9d commit d863edb
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 8 deletions.
33 changes: 32 additions & 1 deletion Sources/AppKitNavigation/AppKitAnimation.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
import AppKit
import SwiftNavigation
import IssueReporting

#if canImport(SwiftUI)
import SwiftUI
Expand Down Expand Up @@ -43,7 +44,7 @@
var result: Swift.Result<Result, Error>?
NSAnimationContext.runAnimationGroup { context in
context.allowsImplicitAnimation = true
context.duration = animation.duration
context.duration = animation.duration / animation.speed
context.timingFunction = animation.timingFunction
result = Swift.Result(catching: body)
} completionHandler: {
Expand Down Expand Up @@ -74,6 +75,7 @@

fileprivate struct AppKit: Hashable, @unchecked Sendable {
fileprivate var duration: TimeInterval
fileprivate var speed: TimeInterval
fileprivate var timingFunction: CAMediaTimingFunction?

func hash(into hasher: inout Hasher) {
Expand All @@ -84,6 +86,35 @@
}

extension AppKitAnimation {
/// Changes the duration of an animation by adjusting its speed.
///
/// - Parameter speed: The speed at which SwiftUI performs the animation.
/// - Returns: An animation with the adjusted speed.
public func speed(
_ speed: Double
) -> Self {
switch framework {
case let .swiftUI(animation):
return AppKitAnimation(
framework: .swiftUI(animation.speed(speed))
)
case var .appKit(animation):
if speed != 0 {
animation.speed = speed
} else {
reportIssue(
"""
Setting animation speed to zero is not supported for AppKit animations.
Replacing with `.ulpOfOne` to avoid division by zero.
"""
)
animation.speed = .ulpOfOne
}
return AppKitAnimation(framework: .appKit(animation))
}
}


/// Animates changes with the specified duration and timing function.
///
/// A value description of `UIView.runAnimationGroup` that can be used with
Expand Down
25 changes: 18 additions & 7 deletions Sources/UIKitNavigation/UIKitAnimation.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#if canImport(UIKit) && !os(watchOS)
import UIKit
import IssueReporting

#if canImport(SwiftUI)
import SwiftUI
Expand Down Expand Up @@ -71,8 +72,8 @@
var result: Swift.Result<Result, Error>?
withoutActuallyEscaping(animations) { animations in
UIView.animate(
withDuration: animation.duration * animation.speed,
delay: animation.delay * animation.speed,
withDuration: animation.duration / animation.speed,
delay: animation.delay / animation.speed,
options: animation.options,
animations: { result = Swift.Result(catching: animations) },
completion: completion
Expand All @@ -84,8 +85,8 @@
var result: Swift.Result<Result, Error>?
withoutActuallyEscaping(animations) { animations in
UIView.animate(
withDuration: animation.duration * animation.speed,
delay: animation.delay * animation.speed,
withDuration: animation.duration / animation.speed,
delay: animation.delay / animation.speed,
usingSpringWithDamping: dampingRatio,
initialSpringVelocity: velocity,
options: animation.options,
Expand All @@ -99,10 +100,10 @@
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) {
var result: Swift.Result<Result, Error>?
UIView.animate(
springDuration: animation.duration * animation.speed,
springDuration: animation.duration / animation.speed,
bounce: bounce,
initialSpringVelocity: initialSpringVelocity,
delay: animation.delay * animation.speed,
delay: animation.delay / animation.speed,
options: animation.options,
animations: { result = Swift.Result(catching: animations) },
completion: completion
Expand Down Expand Up @@ -220,7 +221,17 @@
framework: .swiftUI(animation.speed(speed))
)
case var .uiKit(animation):
animation.speed = speed
if speed != 0 {
animation.speed = speed
} else {
reportIssue(
"""
Setting animation speed to zero is not supported for UIKit animations.
Replacing with `.ulpOfOne` to avoid division by zero.
"""
)
animation.speed = .ulpOfOne
}
return UIKitAnimation(framework: .uiKit(animation))
}
}
Expand Down

0 comments on commit d863edb

Please sign in to comment.