use crate::integrations::lottie::LottieAssetVariant;
use bevy::platform::collections::HashMap;
use bevy::platform::time::Instant;
use bevy::prelude::*;
use std::{ops::Range, time::Duration};
pub(super) mod events;
pub(super) mod hooks;
mod state;
pub use state::PlayerState;
#[derive(Component, Clone, Debug)]
pub struct LottiePlayer<A: LottieAssetVariant> {
pub(crate) started: bool,
pub(crate) playing: bool,
pub(crate) stopped: bool,
pub(crate) current_state: Option<&'static str>,
pub(crate) next_state: Option<&'static str>,
pub(crate) states: HashMap<&'static str, PlayerState<A>>,
}
impl<A: LottieAssetVariant> Default for LottiePlayer<A> {
fn default() -> Self {
let mut states = HashMap::new();
states.insert("default", PlayerState::<A>::new("default"));
Self {
current_state: Some("default"),
next_state: None,
states,
started: false,
playing: true,
stopped: false,
}
}
}
impl<A: LottieAssetVariant> LottiePlayer<A> {
pub fn new(initial_state: &'static str) -> LottiePlayer<A> {
LottiePlayer::<A> {
current_state: None,
next_state: Some(initial_state),
states: HashMap::new(),
started: false,
playing: false,
stopped: false,
}
}
pub fn with_state(mut self, state: PlayerState<A>) -> Self {
self.states.insert(state.id, state);
self
}
pub fn state(&self) -> &PlayerState<A> {
self.states
.get(
self.current_state
.or(self.next_state)
.expect("expected state"),
)
.unwrap_or_else(|| panic!("state not found: '{}'", self.current_state.unwrap()))
}
pub fn state_mut(&mut self) -> &mut PlayerState<A> {
self.states
.get_mut(
self.current_state
.or(self.next_state)
.expect("expected state"),
)
.unwrap_or_else(|| panic!("state not found: '{}'", self.current_state.unwrap()))
}
pub fn states(&self) -> impl Iterator<Item = &PlayerState<A>> {
self.states.values()
}
pub fn states_mut(&mut self) -> impl Iterator<Item = &mut PlayerState<A>> {
self.states.values_mut()
}
pub fn transition(&mut self, state: &'static str) {
self.next_state.replace(state);
}
pub fn toggle_play(&mut self) {
if self.stopped || !self.playing {
self.play();
} else {
self.pause();
}
}
pub fn play(&mut self) {
self.playing = true;
self.stopped = false;
}
pub fn pause(&mut self) {
self.playing = false;
}
pub fn stop(&mut self) {
self.stopped = true;
}
pub fn is_playing(&self) -> bool {
self.playing
}
pub fn is_stopped(&self) -> bool {
self.stopped
}
}
#[derive(PartialEq, Component, Clone, Debug, Reflect)]
#[reflect(Component)]
pub struct PlaybackOptions {
pub autoplay: bool,
pub direction: PlaybackDirection,
pub speed: f64,
pub intermission: Duration,
pub play_mode: PlaybackPlayMode,
pub looping: PlaybackLoopBehavior,
pub segments: Range<f64>,
}
impl Default for PlaybackOptions {
fn default() -> Self {
Self {
autoplay: true,
direction: Default::default(),
speed: 1.0,
intermission: Duration::ZERO,
play_mode: Default::default(),
looping: Default::default(),
segments: f64::MIN..f64::MAX,
}
}
}
#[derive(PartialEq, Component, Default, Clone, Copy, Debug, Reflect)]
#[reflect(Component)]
pub enum PlaybackDirection {
#[default]
Normal = 1,
Reverse = -1,
}
#[derive(PartialEq, Component, Default, Clone, Copy, Debug, Reflect)]
#[reflect(Component)]
pub enum PlaybackLoopBehavior {
DoNotLoop,
Amount(usize),
#[default]
Loop,
}
#[derive(PartialEq, Component, Default, Clone, Copy, Debug, Reflect)]
#[reflect(Component)]
pub enum PlaybackPlayMode {
#[default]
Normal,
Bounce,
}
#[derive(Debug, Clone)]
#[allow(clippy::enum_variant_names)]
pub enum PlayerTransition {
OnAfter { state: &'static str, secs: f32 },
OnComplete { state: &'static str },
OnMouseEnter { state: &'static str },
OnMouseClick { state: &'static str },
OnMouseLeave { state: &'static str },
OnShow { state: &'static str },
}
#[derive(PartialEq, Component, Clone, Debug)]
pub struct Playhead {
pub(crate) first_render: Option<Instant>,
pub(crate) frame: f64,
pub(crate) intermission: Option<Timer>,
pub(crate) loops_completed: usize,
pub(crate) playmode_dir: f64,
}
impl Default for Playhead {
fn default() -> Self {
Self::new(0.0)
}
}
impl Playhead {
pub fn frame(&self) -> f64 {
self.frame
}
pub fn seek(&mut self, frame: f64) {
self.frame = frame;
}
pub fn new(frame: f64) -> Self {
Self {
frame,
first_render: None,
intermission: None,
loops_completed: 0,
playmode_dir: 1.0,
}
}
}