/// Timeline visualization data structure use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; /// Timeline of activities #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Timeline { pub entries: Vec, pub start: DateTime, pub end: DateTime, } impl Timeline { pub fn new(start: DateTime, end: DateTime) -> Self { Self { entries: Vec::new(), start, end, } } pub fn add_entry(&mut self, entry: TimelineEntry) { self.entries.push(entry); } pub fn sort_by_time(&mut self) { self.entries.sort_by_key(|e| e.timestamp); } pub fn duration_seconds(&self) -> i64 { (self.end - self.start).num_seconds() } } /// Single timeline entry #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TimelineEntry { pub timestamp: DateTime, pub category: String, pub activity: String, pub duration_seconds: i64, pub color: String, // For visualization } impl TimelineEntry { pub fn new( timestamp: DateTime, category: String, activity: String, duration_seconds: i64, ) -> Self { let color = Self::category_color(&category); Self { timestamp, category, activity, duration_seconds, color, } } fn category_color(category: &str) -> String { match category { "Development" => "#4CAF50".to_string(), // Green "Meeting" => "#2196F3".to_string(), // Blue "Research" => "#FF9800".to_string(), // Orange "Design" => "#9C27B0".to_string(), // Purple _ => "#9E9E9E".to_string(), // Gray } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_timeline_creation() { let start = Utc::now(); let end = start + chrono::Duration::hours(8); let mut timeline = Timeline::new(start, end); assert_eq!(timeline.entries.len(), 0); assert_eq!(timeline.duration_seconds(), 8 * 3600); let entry = TimelineEntry::new( start, "Development".to_string(), "Coding".to_string(), 3600, ); timeline.add_entry(entry); assert_eq!(timeline.entries.len(), 1); assert_eq!(timeline.entries[0].color, "#4CAF50"); } }