Skip to main content

cranpose_animation/
unit_animation.rs

1//! Animation over Cranpose's density/scale unit types.
2//!
3//! Layers [`Lerp`] and [`SpringScalar`] onto [`Dp`] and [`Sp`] so they plug
4//! into the same generic [`animateValueAsState`] core that
5//! [`animateFloatAsState`](crate::animateFloatAsState) and
6//! [`animateColorAsState`](crate::animateColorAsState) already use.
7//!
8//! Note: This module uses camelCase for function names to maintain 1:1 API
9//! parity with Jetpack Compose.
10
11#![allow(non_snake_case)]
12
13use cranpose_core::State;
14use cranpose_ui_graphics::{Dp, Sp};
15
16use crate::animation::{AnimationType, Lerp, SpringScalar, animateValueAsState};
17
18impl Lerp for Dp {
19    fn lerp(&self, target: &Self, fraction: f32) -> Self {
20        Dp(self.0.lerp(&target.0, fraction))
21    }
22}
23
24impl SpringScalar for Dp {
25    const DIMENSIONS: usize = 1;
26
27    fn dimension(&self, _index: usize) -> f32 {
28        self.0
29    }
30
31    fn from_dimensions(dimensions: [f32; crate::animation::SPRING_MAX_DIMENSIONS]) -> Self {
32        Dp(dimensions[0])
33    }
34}
35
36impl Lerp for Sp {
37    fn lerp(&self, target: &Self, fraction: f32) -> Self {
38        Sp(self.0.lerp(&target.0, fraction))
39    }
40}
41
42impl SpringScalar for Sp {
43    const DIMENSIONS: usize = 1;
44
45    fn dimension(&self, _index: usize) -> f32 {
46        self.0
47    }
48
49    fn from_dimensions(dimensions: [f32; crate::animation::SPRING_MAX_DIMENSIONS]) -> Self {
50        Sp(dimensions[0])
51    }
52}
53
54/// Fire-and-forget animation of a density-independent length.
55///
56/// Mirrors Jetpack Compose: `animateDpAsState(targetValue, animationSpec, label)`.
57#[track_caller]
58pub fn animateDpAsState(target: Dp, animation: AnimationType, label: &str) -> State<Dp> {
59    animateValueAsState(target, animation, label)
60}
61
62#[cfg(test)]
63#[path = "tests/unit_animation_tests.rs"]
64mod tests;