toon_format/tui/state/
file_state.rs

1//! File management and conversion history.
2
3use std::path::PathBuf;
4
5use chrono::{
6    DateTime,
7    Local,
8};
9
10/// A file or directory entry.
11#[derive(Debug, Clone)]
12pub struct FileEntry {
13    pub path: PathBuf,
14    pub is_dir: bool,
15    pub size: u64,
16    pub modified: Option<DateTime<Local>>,
17}
18
19impl FileEntry {
20    pub fn name(&self) -> String {
21        self.path
22            .file_name()
23            .and_then(|n| n.to_str())
24            .unwrap_or("")
25            .to_string()
26    }
27
28    pub fn is_json(&self) -> bool {
29        !self.is_dir && self.path.extension().and_then(|e| e.to_str()) == Some("json")
30    }
31
32    pub fn is_toon(&self) -> bool {
33        !self.is_dir && self.path.extension().and_then(|e| e.to_str()) == Some("toon")
34    }
35}
36
37/// Record of a conversion operation.
38#[derive(Debug, Clone)]
39pub struct ConversionHistory {
40    pub timestamp: DateTime<Local>,
41    pub mode: String,
42    pub input_file: Option<PathBuf>,
43    pub output_file: Option<PathBuf>,
44    pub token_savings: f64,
45    pub byte_savings: f64,
46}
47
48/// File browser and conversion history state.
49pub struct FileState {
50    pub current_file: Option<PathBuf>,
51    pub current_dir: PathBuf,
52    pub selected_files: Vec<PathBuf>,
53    pub history: Vec<ConversionHistory>,
54    pub is_modified: bool,
55}
56
57impl FileState {
58    pub fn new() -> Self {
59        Self {
60            current_file: None,
61            current_dir: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
62            selected_files: Vec::new(),
63            history: Vec::new(),
64            is_modified: false,
65        }
66    }
67
68    pub fn set_current_file(&mut self, path: PathBuf) {
69        self.current_file = Some(path.clone());
70        self.current_dir = path
71            .parent()
72            .map(|p| p.to_path_buf())
73            .unwrap_or_else(|| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")));
74        self.is_modified = false;
75    }
76
77    pub fn clear_current_file(&mut self) {
78        self.current_file = None;
79        self.is_modified = false;
80    }
81
82    pub fn mark_modified(&mut self) {
83        self.is_modified = true;
84    }
85
86    pub fn add_to_history(&mut self, entry: ConversionHistory) {
87        self.history.push(entry);
88        if self.history.len() > 50 {
89            self.history.remove(0);
90        }
91    }
92
93    pub fn toggle_file_selection(&mut self, path: PathBuf) {
94        if let Some(pos) = self.selected_files.iter().position(|p| p == &path) {
95            self.selected_files.remove(pos);
96        } else {
97            self.selected_files.push(path);
98        }
99    }
100
101    pub fn clear_selection(&mut self) {
102        self.selected_files.clear();
103    }
104
105    pub fn is_selected(&self, path: &PathBuf) -> bool {
106        self.selected_files.contains(path)
107    }
108}
109
110impl Default for FileState {
111    fn default() -> Self {
112        Self::new()
113    }
114}