use crossterm::event::{KeyCode, KeyEvent};
pub const REPO: &str = "github.com/raghavenderreddygrudhanti/sweep";
#[derive(Debug, Clone, PartialEq)]
pub enum NavAction {
Up,
Down,
Select, Back, Quit, Toggle, Delete, SelectAll, ClearAll, Char(char), None, }
pub fn map_key(key: KeyEvent) -> NavAction {
match key.code {
KeyCode::Up | KeyCode::Char('k') => NavAction::Up,
KeyCode::Down | KeyCode::Char('j') => NavAction::Down,
KeyCode::Enter | KeyCode::Right | KeyCode::Char('l') => NavAction::Select,
KeyCode::Esc | KeyCode::Backspace => NavAction::Back,
KeyCode::Left | KeyCode::Char('h') => NavAction::Back,
KeyCode::Char('q') => NavAction::Quit,
KeyCode::Char(' ') => NavAction::Toggle,
KeyCode::Char('d') | KeyCode::Char('D') => NavAction::Delete,
KeyCode::Delete => NavAction::Delete,
KeyCode::Char('a') => NavAction::SelectAll,
KeyCode::Char('n') => NavAction::ClearAll,
KeyCode::Char(c) => NavAction::Char(c),
_ => NavAction::None,
}
}
pub fn footer_sep() -> &'static str {
" \x1b[90m─────────────────────────────────────────────\x1b[0m\r\n"
}
pub fn footer_browse() -> &'static str {
" \x1b[90m↑↓ nav · →Enter open · ←Esc back · Space select · d del · q quit\x1b[0m\r\n"
}
pub fn footer_selected(count: usize) -> String {
format!(" \x1b[32m{} selected\x1b[0m · \x1b[90mD delete · Space toggle · n clear · Esc back · q quit\x1b[0m\r\n", count)
}
pub fn footer_list() -> &'static str {
" \x1b[90m↑↓ nav · Space select · Enter confirm · Esc back · q quit\x1b[0m\r\n"
}
pub fn footer_simple() -> &'static str {
" \x1b[90mEsc/q back\x1b[0m\r\n"
}
pub fn wait_any_key() {
print!("\n \x1b[90mPress any key to return...\x1b[0m ");
let _ = std::io::Write::flush(&mut std::io::stdout());
let _ = crossterm::terminal::enable_raw_mode();
std::thread::sleep(std::time::Duration::from_millis(200));
while crossterm::event::poll(std::time::Duration::from_millis(100)).unwrap_or(false) {
let _ = crossterm::event::read();
}
let _ = crossterm::event::read();
let _ = crossterm::terminal::disable_raw_mode();
println!();
}
pub fn action_name(op: &str) -> &'static str {
match op {
"clean" => "🧹 Sweeping away junk...",
"delete" | "trash" => "🗑 Tossing to the void...",
"scan" => "🔍 Hunting disk hogs...",
"uninstall" => "💀 Evicting app...",
"optimize" => "⚡ Turbocharging system...",
"ai" => "🤖 Purging AI leftovers...",
"docker" => "🐳 Draining containers...",
"dev" => "🔨 Demolishing build artifacts...",
"installer" => "📦 Shredding installers...",
_ => "⏳ Working...",
}
}
const SPINNERS: &[&str] = &["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];
const SWEEP_FRAMES: &[&str] = &["🧹 ", " 🧹 ", " 🧹 ", " 🧹 ", " 🧹", " 🧹 ", " 🧹 ", " 🧹 "];
pub fn spinner(frame: usize) -> &'static str {
SPINNERS[frame % SPINNERS.len()]
}
pub fn sweep_anim(frame: usize) -> &'static str {
SWEEP_FRAMES[frame % SWEEP_FRAMES.len()]
}
pub fn logo_tui_animated(frame: usize) -> String {
let colors = ["\x1b[36m", "\x1b[32m", "\x1b[35m", "\x1b[33m", "\x1b[34m"];
let c = colors[frame % colors.len()];
let r = "\x1b[0m";
let mut s = String::new();
s.push_str("\r\n");
s.push_str(&format!(" {}____{} \r\n", c, r));
s.push_str(&format!(" {}/ ___|\x1b[0m_ _____ ___ _ __\r\n", c));
s.push_str(&format!(" {}\\___ \\{}\\ \\ /\\ / / _ \\/ _ \\ '_ \\\r\n", c, r));
s.push_str(&format!(" {}___) |{}\\ V V / __/ __/ |_) |\r\n", c, r));
s.push_str(&format!(" {}|____/{} \\_/\\_/ \\___|\\___| .__/\r\n", c, r));
s.push_str(" |_|\r\n");
s.push_str(&format!(" \x1b[32m{}\x1b[0m\r\n", REPO));
s.push_str(" \x1b[90mFast system cleaner · Rust · macOS + Linux\x1b[0m\r\n");
s
}
fn logo_tui() -> String {
logo_tui_animated(0)
}
fn logo_print() {
println!();
println!(" \x1b[36m____\x1b[0m");
println!(" \x1b[36m/ ___|\x1b[0m_ _____ ___ _ __");
println!(" \x1b[36m\\___ \\\x1b[0m\\ \\ /\\ / / _ \\/ _ \\ '_ \\");
println!(" \x1b[36m___) |\x1b[0m\\ V V / __/ __/ |_) |");
println!(" \x1b[36m|____/\x1b[0m \\_/\\_/ \\___|\\___| .__/");
println!(" |_|");
println!(" \x1b[32m{}\x1b[0m", REPO);
println!(" \x1b[90mFast system cleaner · Rust · macOS + Linux\x1b[0m");
}
pub fn print_header(subtitle: &str) {
logo_print();
println!();
println!(" \x1b[90m›\x1b[0m {}", subtitle);
println!(" \x1b[90m─────────────────────────────────────────────\x1b[0m");
println!();
}
pub fn tui_header(subtitle: &str) -> String {
let mut out = logo_tui();
out.push_str("\r\n");
if !subtitle.is_empty() {
out.push_str(&format!(" \x1b[90m›\x1b[0m {}\r\n", subtitle));
}
out.push_str(" \x1b[90m─────────────────────────────────────────────\x1b[0m\r\n");
out.push_str("\r\n");
out
}
pub fn tui_header_animated(subtitle: &str, frame: usize) -> String {
let mut out = logo_tui_animated(frame);
out.push_str("\r\n");
if !subtitle.is_empty() {
out.push_str(&format!(" \x1b[90m›\x1b[0m {}\r\n", subtitle));
}
out.push_str(" \x1b[90m─────────────────────────────────────────────\x1b[0m\r\n");
out.push_str("\r\n");
out
}