pub mod agent_avatar;
pub mod message_flow;
pub mod particles;
pub mod progress;
pub mod token_stream;
pub use agent_avatar::{ActivityLevel, AgentAvatar, AgentRole};
pub use message_flow::{MessageFlow, MessageFlowManager, MessageType};
pub use particles::{EmitConfig, Particle, ParticleSystem};
pub use progress::AnimatedProgressBar;
pub use token_stream::{TokenSize, TokenStream};
use std::time::Instant;
pub struct AnimationManager {
animations: Vec<Box<dyn Animation>>,
_last_update: Instant,
paused: bool,
}
pub trait Animation: Send + Sync {
fn update(&mut self, delta_time: f32);
fn is_complete(&self) -> bool;
}
impl AnimationManager {
pub fn new() -> Self {
Self {
animations: Vec::new(),
_last_update: Instant::now(),
paused: false,
}
}
pub fn add<A: Animation + 'static>(&mut self, animation: A) {
self.animations.push(Box::new(animation));
}
pub fn update(&mut self, delta_time: f32) {
if self.paused {
return;
}
for animation in &mut self.animations {
animation.update(delta_time);
}
self.animations.retain(|a| !a.is_complete());
}
pub fn toggle_pause(&mut self) {
self.paused = !self.paused;
}
pub fn is_paused(&self) -> bool {
self.paused
}
pub fn animation_count(&self) -> usize {
self.animations.len()
}
}
impl Default for AnimationManager {
fn default() -> Self {
Self::new()
}
}
pub mod timing {
use std::time::Duration;
pub const MICRO: Duration = Duration::from_millis(100);
pub const STANDARD: Duration = Duration::from_millis(300);
pub const EMPHASIS: Duration = Duration::from_millis(500);
pub const DRAMATIC: Duration = Duration::from_millis(1000);
pub const AMBIENT_MIN: Duration = Duration::from_millis(2000);
pub const AMBIENT_MAX: Duration = Duration::from_millis(5000);
}
pub mod colors {
use ratatui::style::Color;
pub const BACKGROUND: Color = Color::Rgb(0x1A, 0x1A, 0x2E);
pub const PRIMARY: Color = Color::Rgb(0xFF, 0x6B, 0x6B);
pub const SECONDARY: Color = Color::Rgb(0x4E, 0xC5, 0xF1);
pub const ACCENT: Color = Color::Rgb(0x95, 0xE1, 0xD3);
pub const WARNING: Color = Color::Rgb(0xFF, 0xD9, 0x3D);
pub const ERROR: Color = Color::Rgb(0xFF, 0x5F, 0x5F);
pub const SUCCESS: Color = Color::Rgb(0x52, 0xD6, 0x81);
pub const PURPLE: Color = Color::Rgb(0x6B, 0x7A, 0xF7);
pub const ORANGE: Color = Color::Rgb(0xFF, 0x9F, 0x43);
pub const GRADIENT: [Color; 4] = [
Color::Rgb(0x52, 0xD6, 0x81), Color::Rgb(0x95, 0xE1, 0xD3), Color::Rgb(0x4E, 0xC5, 0xF1), Color::Rgb(0x6B, 0x7A, 0xF7), ];
}
#[cfg(test)]
mod tests {
use super::*;
struct TestAnimation {
updates: u32,
complete_after: u32,
}
impl Animation for TestAnimation {
fn update(&mut self, _delta_time: f32) {
self.updates += 1;
}
fn is_complete(&self) -> bool {
self.updates >= self.complete_after
}
}
#[test]
fn test_animation_manager_new() {
let manager = AnimationManager::new();
assert_eq!(manager.animation_count(), 0);
assert!(!manager.is_paused());
}
#[test]
fn test_animation_manager_add() {
let mut manager = AnimationManager::new();
manager.add(TestAnimation {
updates: 0,
complete_after: 5,
});
assert_eq!(manager.animation_count(), 1);
}
#[test]
fn test_animation_manager_update() {
let mut manager = AnimationManager::new();
manager.add(TestAnimation {
updates: 0,
complete_after: 3,
});
manager.update(0.016);
assert_eq!(manager.animation_count(), 1);
manager.update(0.016);
manager.update(0.016);
assert_eq!(manager.animation_count(), 0); }
#[test]
fn test_animation_manager_pause() {
let mut manager = AnimationManager::new();
manager.add(TestAnimation {
updates: 0,
complete_after: 10,
});
manager.toggle_pause();
assert!(manager.is_paused());
manager.update(0.016);
assert_eq!(manager.animation_count(), 1);
manager.toggle_pause();
assert!(!manager.is_paused());
}
}