use crate::{
runtime::{Motion, MotionError, MotionEvent, MotionRuntime, PlaybackId},
timing::Timing,
traits::{Animatable, IntoMotionAnimation},
};
pub struct Presence<T: Animatable> {
motion: Motion<T>,
visible: T,
hidden: T,
mounted: bool,
shown: bool,
exit_playback: Option<PlaybackId>,
}
impl<T: Animatable> Presence<T> {
#[must_use]
pub fn new(runtime: &mut MotionRuntime, hidden: T, visible: T, timing: Timing) -> Self {
Self {
motion: runtime.motion_with(hidden.clone(), timing),
visible,
hidden,
mounted: false,
shown: false,
exit_playback: None,
}
}
pub fn motion(&self) -> Motion<T> {
self.motion
}
pub fn value<'a>(&self, runtime: &'a MotionRuntime) -> Result<&'a T, MotionError> {
self.motion.value_ref(runtime)
}
#[must_use]
pub const fn is_mounted(&self) -> bool {
self.mounted
}
#[must_use]
pub const fn is_visible(&self) -> bool {
self.shown
}
pub fn set_visible(
&mut self,
visible: bool,
runtime: &mut MotionRuntime,
) -> Result<bool, MotionError> {
if self.shown == visible {
#[cfg(feature = "tracing")]
tracing::trace!(
target: "aura_anim::presence",
value_type = std::any::type_name::<T>(),
mounted = self.mounted,
shown = self.shown,
"presence visibility is unchanged"
);
return Ok(false);
}
if visible {
self.show(runtime)?;
} else {
self.hide(runtime)?;
}
Ok(true)
}
pub fn toggle(&mut self, runtime: &mut MotionRuntime) -> Result<bool, MotionError> {
self.set_visible(!self.shown, runtime)
}
pub fn show(&mut self, runtime: &mut MotionRuntime) -> Result<(), MotionError> {
self.motion
.transition_to_tracked(self.visible.clone(), runtime)?;
self.mounted = true;
self.shown = true;
self.exit_playback = None;
#[cfg(feature = "tracing")]
tracing::debug!(
target: "aura_anim::presence",
value_type = std::any::type_name::<T>(),
mounted = self.mounted,
shown = self.shown,
"showing presence"
);
Ok(())
}
pub fn hide(&mut self, runtime: &mut MotionRuntime) -> Result<(), MotionError> {
let playback = self
.motion
.transition_to_tracked(self.hidden.clone(), runtime)?;
self.shown = false;
self.exit_playback = Some(playback);
#[cfg(feature = "tracing")]
tracing::debug!(
target: "aura_anim::presence",
value_type = std::any::type_name::<T>(),
mounted = self.mounted,
shown = self.shown,
"hiding presence"
);
Ok(())
}
pub fn show_with<P, Kind>(
&mut self,
animation: P,
runtime: &mut MotionRuntime,
) -> Result<(), MotionError>
where
P: IntoMotionAnimation<T, Kind>,
{
self.motion.play_tracked(animation, runtime)?;
self.mounted = true;
self.shown = true;
self.exit_playback = None;
#[cfg(feature = "tracing")]
tracing::debug!(
target: "aura_anim::presence",
value_type = std::any::type_name::<T>(),
mounted = self.mounted,
shown = self.shown,
"showing presence with custom animation"
);
Ok(())
}
pub fn hide_with<P, Kind>(
&mut self,
animation: P,
runtime: &mut MotionRuntime,
) -> Result<(), MotionError>
where
P: IntoMotionAnimation<T, Kind>,
{
let playback = self.motion.play_tracked(animation, runtime)?;
self.shown = false;
self.exit_playback = Some(playback);
#[cfg(feature = "tracing")]
tracing::debug!(
target: "aura_anim::presence",
value_type = std::any::type_name::<T>(),
mounted = self.mounted,
shown = self.shown,
"hiding presence with custom animation"
);
Ok(())
}
pub fn handle_event(&mut self, event: &MotionEvent) -> bool {
let Some(exit_playback) = self.exit_playback else {
return false;
};
if self.shown || !event.is_completed_for(exit_playback) {
return false;
}
let changed = self.mounted;
self.mounted = false;
self.exit_playback = None;
#[cfg(feature = "tracing")]
tracing::debug!(
target: "aura_anim::presence",
value_type = std::any::type_name::<T>(),
"unmounted completed hidden presence from runtime event"
);
changed
}
pub fn sync(&mut self, runtime: &MotionRuntime) -> Result<(), MotionError> {
if !self.shown && self.motion.is_completed(runtime)? {
self.mounted = false;
self.exit_playback = None;
#[cfg(feature = "tracing")]
tracing::debug!(
target: "aura_anim::presence",
value_type = std::any::type_name::<T>(),
"unmounted completed hidden presence"
);
}
Ok(())
}
}