Skip to content

Update Animatable API and implementation #309

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

Merged
merged 1 commit into from
Jun 2, 2025
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
4 changes: 2 additions & 2 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

119 changes: 119 additions & 0 deletions Sources/OpenSwiftUICore/View/Animation/Animation/Animatable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//
// Animatable.swift
// OpenSwiftUICore
//
// Status: Complete

public import Foundation
package import OpenGraphShims

// MARK: - Animatable [6.4.41]

/// A type that describes how to animate a property of a view.
public protocol Animatable {
/// The type defining the data to animate.
associatedtype AnimatableData: VectorArithmetic

/// The data to animate.
var animatableData: AnimatableData { get set }

/// Replaces `value` with an animated version of the value, using
/// `inputs`.
static func _makeAnimatable(value: inout _GraphValue<Self>, inputs: _GraphInputs)
}

// MARK: - Animateble + Extension [6.4.41]

extension Animatable where Self: VectorArithmetic {
public var animatableData: Self {
get { self }
set { self = newValue }
}
}

extension Animatable where AnimatableData == EmptyAnimatableData {
public var animatableData: EmptyAnimatableData {
@inlinable
get { EmptyAnimatableData() }
@inlinable
set {}
}

public static func _makeAnimatable(value _: inout _GraphValue<Self>, inputs _: _GraphInputs) {}
}

extension Animatable {
package static func makeAnimatable(value: inout _GraphValue<Self>, inputs: _GraphInputs) {
_makeAnimatable(value: &value, inputs: inputs)
}
}

extension Attribute where Value: Animatable {
package func animated(inputs: _GraphInputs) -> Attribute<Value> {
var value = _GraphValue(self)
Value._makeAnimatable(value: &value, inputs: inputs)
return value.value
}
}

extension Animatable {
public static func _makeAnimatable(value: inout _GraphValue<Self>, inputs: _GraphInputs) {
guard MemoryLayout<AnimatableData>.size != 0,
!inputs.animationsDisabled else {
return
}
let animatable = AnimatableAttribute(
source: value.value,
phase: inputs.phase,
time: inputs.time,
transaction: inputs.transaction,
environment: inputs.environment
)
let newValue = _GraphValue(animatable)
value = newValue
value.value.setFlags(.active, mask: .mask)
}
}

// MARK: - EmptyAnimatableData [6.4.41]

/// An empty type for animatable data.
///
/// This type is suitable for use as the `animatableData` property of
/// types that do not have any animatable properties.
@frozen
public struct EmptyAnimatableData: VectorArithmetic {
@inlinable
public init() {}

@inlinable
public static var zero: EmptyAnimatableData { .init() }

@inlinable
public static func += (_: inout EmptyAnimatableData, _: EmptyAnimatableData) {}

@inlinable
public static func -= (_: inout EmptyAnimatableData, _: EmptyAnimatableData) {}

@inlinable
public static func + (_: EmptyAnimatableData, _: EmptyAnimatableData) -> EmptyAnimatableData { .zero }

@inlinable
public static func - (_: EmptyAnimatableData, _: EmptyAnimatableData) -> EmptyAnimatableData { .zero }

@inlinable
public mutating func scale(by _: Double) {}

@inlinable
public var magnitudeSquared: Double { 0 }

public static func == (_: EmptyAnimatableData, _: EmptyAnimatableData) -> Bool { true }
}

extension Double: Animatable {
public typealias AnimatableData = Double
}

extension CGFloat: Animatable {
public typealias AnimatableData = CGFloat
}
63 changes: 63 additions & 0 deletions Sources/OpenSwiftUICore/View/Animation/Animation/Animation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package import OpenGraphShims

@frozen
public struct Animation: Equatable {
// var box: AnimationBoxBase
public static func == (lhs: Animation, rhs: Animation) -> Bool {
// TODO
true
}

public static var `default` = Animation()
}

// MARK: - AnimatableAttribute [6.4.41] [TODO]

package struct AnimatableAttribute<Value>: StatefulRule, AsyncAttribute, ObservedAttribute, CustomStringConvertible where Value: Animatable {
@Attribute var source: Value
@Attribute var environment: EnvironmentValues
var helper: AnimatableAttributeHelper<Value>

package init(
source: Attribute<Value>,
phase: Attribute<_GraphInputs.Phase>,
time: Attribute<Time>,
transaction: Attribute<Transaction>,
environment: Attribute<EnvironmentValues>
) {
_source = source
_environment = environment
helper = .init(phase: phase, time: time, transaction: transaction)
}

package mutating func updateValue() {
// TODO
}

package var description: String { "Animatable<\(Value.self)>" }

package mutating func destroy() {
// helper.animatorState?.removeListeners()
}
}

// MARK: - AnimatableAttributeHelper [FIXME]

package struct AnimatableAttributeHelper<Value> where Value: Animatable {
@Attribute var phase: _GraphInputs.Phase
@Attribute var time: Time
@Attribute var transaction: Transaction
var previousModelData: Value.AnimatableData?
// var animatorState: AnimatorState<Value.AnimatableData>?
var resetSeed: UInt32 = 0

init(
phase: Attribute<_GraphInputs.Phase>,
time: Attribute<Time>,
transaction: Attribute<Transaction>
) {
_phase = phase
_time = time
_transaction = transaction
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,3 @@
// Audited for iOS 18.0
// Status: Complete

/// An empty type for animatable data.
///
/// This type is suitable for use as the `animatableData` property of
/// types that do not have any animatable properties.
@frozen
public struct EmptyAnimatableData: VectorArithmetic {
@inlinable
public init() {}

@inlinable
public static var zero: EmptyAnimatableData { .init() }

@inlinable
public static func += (_: inout EmptyAnimatableData, _: EmptyAnimatableData) {}

@inlinable
public static func -= (_: inout EmptyAnimatableData, _: EmptyAnimatableData) {}

@inlinable
public static func + (_: EmptyAnimatableData, _: EmptyAnimatableData) -> EmptyAnimatableData { .zero }

@inlinable
public static func - (_: EmptyAnimatableData, _: EmptyAnimatableData) -> EmptyAnimatableData { .zero }

@inlinable
public mutating func scale(by _: Double) {}

@inlinable
public var magnitudeSquared: Double { 0 }

public static func == (_: EmptyAnimatableData, _: EmptyAnimatableData) -> Bool { true }
}

public import Foundation

extension Double: Animatable {
public typealias AnimatableData = Swift.Double
}

extension CGFloat: Animatable {
public typealias AnimatableData = CGFloat
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//
// _VectorMath.swift
// VectorMath.swift
// OpenSwiftUICore
//
// Audited for iOS 18.0
// Status: Complete

// MARK: - VectorMath [6.4.41]

/// Adds the "vector space" numeric operations for any type that
/// conforms to Animatable.
public protocol _VectorMath: Animatable {}
Expand Down