1use crate::cleaners::cleaned_item::{CleanerFn, CleaningResult};
7use crate::cleaners::{system_cleaners, user_cleaners};
8
9#[derive(Debug, Clone)]
11pub enum Status {
12 Pending,
14 Running,
16 Success(String),
18 Error(String),
20}
21
22impl Status {
23 pub fn get_animation_frame(&self, frame: usize) -> &'static str {
26 match self {
27 Status::Running => {
28 const SPINNER: &[&str] = &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
29 SPINNER[frame % SPINNER.len()]
30 }
31 Status::Success(_) => "✓",
32 Status::Error(_) => "✗",
33 Status::Pending => "•",
34 }
35 }
36}
37
38pub struct CleanerItem {
40 pub name: String,
42 pub description: String,
44 pub requires_root: bool,
46 pub selected: bool,
48 pub function: CleanerFn,
54 pub bytes_cleaned: u64,
56 pub last_result: Option<CleaningResult>,
59 pub status: Option<Status>,
61}
62
63pub struct CleanerCategory {
65 pub name: String,
67 pub description: String,
69 pub items: Vec<CleanerItem>,
71}
72
73pub fn load_categories() -> Vec<CleanerCategory> {
79 let mut user_items = Vec::new();
80 for cleaner in user_cleaners::get_cleaners() {
81 user_items.push(CleanerItem {
82 name: cleaner.name.to_string(),
83 description: cleaner.description.to_string(),
84 requires_root: false,
85 selected: false,
86 function: cleaner.function,
87 bytes_cleaned: 0,
88 last_result: None,
89 status: None,
90 });
91 }
92
93 let mut system_items = Vec::new();
94 for cleaner in system_cleaners::get_cleaners() {
95 system_items.push(CleanerItem {
96 name: cleaner.name.to_string(),
97 description: cleaner.description.to_string(),
98 requires_root: cleaner.requires_root,
99 selected: false,
100 function: cleaner.function,
101 bytes_cleaned: 0,
102 last_result: None,
103 status: None,
104 });
105 }
106
107 vec![
108 CleanerCategory {
109 name: "User Land Cleaners".to_string(),
110 description: "Clean user-specific files and caches".to_string(),
111 items: user_items,
112 },
113 CleanerCategory {
114 name: "System Cleaners".to_string(),
115 description: "Clean system files and caches (requires root)".to_string(),
116 items: system_items,
117 },
118 ]
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn load_categories_has_user_and_system() {
127 let categories = load_categories();
128 assert_eq!(categories.len(), 2);
129 assert_eq!(categories[0].name, "User Land Cleaners");
130 assert_eq!(categories[1].name, "System Cleaners");
131 assert!(!categories[0].items.is_empty());
132 assert!(!categories[1].items.is_empty());
133 assert!(categories[0].items.iter().all(|i| !i.requires_root));
137 }
138
139 #[test]
140 fn status_animation_frames() {
141 assert_eq!(Status::Pending.get_animation_frame(0), "•");
142 assert_eq!(Status::Success("ok".into()).get_animation_frame(0), "✓");
143 assert_eq!(Status::Error("bad".into()).get_animation_frame(0), "✗");
144 let running = Status::Running;
145 assert_eq!(running.get_animation_frame(0), "⠋");
146 assert_eq!(running.get_animation_frame(1), "⠙");
147 }
148}