use std::collections::HashMap;
#[derive(Clone, Debug, PartialEq)]
pub enum EasingKind {
Linear,
EaseIn,
EaseOut,
EaseInOut,
CubicBezier(f32, f32, f32, f32),
}
#[derive(Clone, Debug, PartialEq)]
pub struct TransitionSpec {
pub duration_ms: u64,
pub delay_ms: u64,
pub easing: EasingKind,
}
#[derive(Clone, Debug, PartialEq)]
pub struct AnimationKeyframe {
pub offset: f32,
pub props: HashMap<String, String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FillMode {
None,
Forwards,
Backwards,
Both,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum IterationCount {
Count(u32),
Infinite,
}
#[derive(Clone, Debug, PartialEq)]
pub struct AnimationSpec {
pub keyframes: Vec<AnimationKeyframe>,
pub duration_ms: u64,
pub fill_mode: FillMode,
pub iteration_count: IterationCount,
}
pub fn fade_in() -> TransitionSpec {
TransitionSpec {
duration_ms: 150,
delay_ms: 0,
easing: EasingKind::EaseInOut,
}
}
pub fn slide_in() -> TransitionSpec {
TransitionSpec {
duration_ms: 200,
delay_ms: 0,
easing: EasingKind::EaseOut,
}
}
pub fn scale_up() -> TransitionSpec {
TransitionSpec {
duration_ms: 150,
delay_ms: 0,
easing: EasingKind::EaseInOut,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fade_in_preset_present() {
let t = fade_in();
assert!(t.duration_ms > 0, "fade_in must have a positive duration");
assert_eq!(t.easing, EasingKind::EaseInOut);
}
#[test]
fn slide_in_preset_present() {
let t = slide_in();
assert!(t.duration_ms > 0, "slide_in must have a positive duration");
assert_eq!(t.easing, EasingKind::EaseOut);
}
#[test]
fn scale_up_preset_present() {
let t = scale_up();
assert!(t.duration_ms > 0, "scale_up must have a positive duration");
assert_eq!(t.easing, EasingKind::EaseInOut);
}
#[test]
fn easing_kind_cubic_bezier_stores_values() {
let e = EasingKind::CubicBezier(0.25, 0.1, 0.25, 1.0);
if let EasingKind::CubicBezier(x1, y1, x2, y2) = e {
assert_eq!(x1, 0.25);
assert_eq!(y1, 0.1);
assert_eq!(x2, 0.25);
assert_eq!(y2, 1.0);
} else {
panic!("unexpected variant");
}
}
#[test]
fn animation_spec_builds() {
let mut props = HashMap::new();
props.insert("opacity".to_string(), "0".to_string());
let spec = AnimationSpec {
keyframes: vec![
AnimationKeyframe {
offset: 0.0,
props: props.clone(),
},
AnimationKeyframe {
offset: 1.0,
props: {
let mut p = HashMap::new();
p.insert("opacity".to_string(), "1".to_string());
p
},
},
],
duration_ms: 300,
fill_mode: FillMode::Forwards,
iteration_count: IterationCount::Count(1),
};
assert_eq!(spec.keyframes.len(), 2);
assert_eq!(spec.duration_ms, 300);
}
#[test]
fn iteration_count_infinite() {
let ic = IterationCount::Infinite;
assert_eq!(ic, IterationCount::Infinite);
}
}