#![allow(non_snake_case)]
use crate::composable;
use crate::modifier::{GraphicsLayer, Modifier};
use crate::widgets::box_widget::{Box, BoxSpec};
use crate::widgets::crossfade::animate_float_with_initial;
use cranpose_animation::AnimationType;
const VISIBILITY_PROGRESS_EPSILON: f32 = 0.001;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct EnterTransition {
fade: bool,
slide_vertical_fraction: Option<f32>,
animation: Option<AnimationType>,
}
impl EnterTransition {
pub fn none() -> Self {
Self {
fade: false,
slide_vertical_fraction: None,
animation: None,
}
}
pub fn with_animation(mut self, animation: AnimationType) -> Self {
self.animation = Some(animation);
self
}
pub(crate) fn has_fade(&self) -> bool {
self.fade
}
pub(crate) fn slide_vertical_fraction(&self) -> Option<f32> {
self.slide_vertical_fraction
}
pub(crate) fn animation(&self) -> AnimationType {
self.animation.unwrap_or_default()
}
}
impl std::ops::Add for EnterTransition {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
fade: self.fade || other.fade,
slide_vertical_fraction: self
.slide_vertical_fraction
.or(other.slide_vertical_fraction),
animation: self.animation.or(other.animation),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ExitTransition {
fade: bool,
slide_vertical_fraction: Option<f32>,
animation: Option<AnimationType>,
}
impl ExitTransition {
pub fn none() -> Self {
Self {
fade: false,
slide_vertical_fraction: None,
animation: None,
}
}
pub fn with_animation(mut self, animation: AnimationType) -> Self {
self.animation = Some(animation);
self
}
pub(crate) fn has_fade(&self) -> bool {
self.fade
}
pub(crate) fn slide_vertical_fraction(&self) -> Option<f32> {
self.slide_vertical_fraction
}
pub(crate) fn animation(&self) -> AnimationType {
self.animation.unwrap_or_default()
}
}
impl std::ops::Add for ExitTransition {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
fade: self.fade || other.fade,
slide_vertical_fraction: self
.slide_vertical_fraction
.or(other.slide_vertical_fraction),
animation: self.animation.or(other.animation),
}
}
}
pub fn fade_in() -> EnterTransition {
EnterTransition {
fade: true,
..EnterTransition::none()
}
}
pub fn fade_out() -> ExitTransition {
ExitTransition {
fade: true,
..ExitTransition::none()
}
}
pub fn slide_in_vertically(initial_offset_fraction: f32) -> EnterTransition {
EnterTransition {
slide_vertical_fraction: Some(initial_offset_fraction),
..EnterTransition::none()
}
}
pub fn slide_out_vertically(target_offset_fraction: f32) -> ExitTransition {
ExitTransition {
slide_vertical_fraction: Some(target_offset_fraction),
..ExitTransition::none()
}
}
#[composable]
pub fn AnimatedVisibility<F>(
visible: bool,
enter: EnterTransition,
exit: ExitTransition,
content: F,
) where
F: FnMut() + 'static,
{
let target = if visible { 1.0 } else { 0.0 };
let animation = if visible {
enter.animation()
} else {
exit.animation()
};
let progress_state = animate_float_with_initial(target, target, animation);
let progress = progress_state.value();
let composed = visible || progress > VISIBILITY_PROGRESS_EPSILON;
if composed {
let fade = if visible {
enter.has_fade()
} else {
exit.has_fade()
};
let slide_fraction = if visible {
enter.slide_vertical_fraction()
} else {
exit.slide_vertical_fraction()
};
let alpha = if fade { progress.clamp(0.0, 1.0) } else { 1.0 };
let mut modifier = Modifier::empty().graphics_layer_value(GraphicsLayer {
alpha,
..Default::default()
});
if let Some(fraction) = slide_fraction {
modifier = modifier.offset_fraction(0.0, fraction * (1.0 - progress));
}
Box(modifier, BoxSpec::new(), content);
}
}