turbo_cdn/
cli_progress.rs1use indicatif::{ProgressBar, ProgressStyle};
9use std::io::{self, Write};
10use std::time::Duration;
11
12pub fn create_spinner(message: &str) -> ProgressBar {
14 let pb = ProgressBar::new_spinner();
15 pb.set_style(
16 ProgressStyle::default_spinner()
17 .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
18 .template("{spinner:.blue} {msg}")
19 .unwrap(),
20 );
21 pb.set_message(message.to_string());
22 pb.enable_steady_tick(Duration::from_millis(100));
23 pb
24}
25
26pub fn create_download_progress(total_size: u64, message: &str) -> ProgressBar {
28 let pb = ProgressBar::new(total_size);
29 pb.set_style(
30 ProgressStyle::default_bar()
31 .template("{msg} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
32 .unwrap()
33 .progress_chars("#>-")
34 );
35 pb.set_message(message.to_string());
36 pb
37}
38
39pub fn create_progress_bar(total: u64, message: &str) -> ProgressBar {
41 let pb = ProgressBar::new(total);
42 pb.set_style(
43 ProgressStyle::default_bar()
44 .template("{msg} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})")
45 .unwrap()
46 .progress_chars("#>-"),
47 );
48 pb.set_message(message.to_string());
49 pb
50}
51
52pub async fn show_quick_spinner(message: &str) {
54 let spinner = create_spinner(message);
55 tokio::time::sleep(Duration::from_secs(1)).await;
56 spinner.finish_and_clear();
57}
58
59pub fn status_message(icon: &str, message: &str) {
61 println!("{icon} {message}");
62}
63
64pub fn info_message(message: &str, verbose: bool) {
66 if verbose {
67 println!("ℹ️ {message}");
68 }
69}
70
71pub fn success_message(message: &str) {
73 println!("✅ {message}");
74}
75
76pub fn error_message(message: &str) {
78 println!("❌ {message}");
79}
80
81pub fn warning_message(message: &str) {
83 println!("⚠️ {message}");
84}
85
86pub fn clear_line() {
88 print!("\r{:width$}\r", "", width = 80);
89 io::stdout().flush().unwrap();
90}
91
92pub fn display_download_result(
94 path: &std::path::Path,
95 size_mb: f64,
96 speed_mbps: f64,
97 duration_secs: f64,
98 verbose: bool,
99) {
100 success_message(&format!(
101 "Downloaded {size_mb:.1} MB in {duration_secs:.1}s ({speed_mbps:.1} MB/s)"
102 ));
103
104 if verbose {
105 info_message(&format!("Saved to: {}", path.display()), true);
106 } else {
107 let path_display = path.display();
108 println!("📁 {path_display}");
109 }
110}
111
112pub fn display_speed_test_results(
114 results: &[(String, f64, bool)], verbose: bool,
116) {
117 if verbose {
118 println!("🚀 Speed test results:");
119 for (method, speed, selected) in results {
120 let status = if *selected { " ✓ (selected)" } else { "" };
121 if *speed > 0.0 {
122 println!(" ├─ {method}: {speed:.2} MB/s{status}");
123 } else {
124 println!(" ├─ {method}: failed{status}");
125 }
126 }
127
128 if let Some((selected_method, _, _)) = results.iter().find(|(_, _, selected)| *selected) {
129 println!(" └─ Using {selected_method} method");
130 }
131 println!();
132 } else {
133 if let Some((selected_method, speed, _)) = results.iter().find(|(_, _, selected)| *selected)
135 {
136 if *speed > 0.0 {
137 status_message("⚡", &format!("Using {selected_method} ({speed:.1} MB/s)"));
138 } else {
139 status_message("⚡", &format!("Using {selected_method}"));
140 }
141 }
142 }
143}
144
145pub fn create_multi_progress() -> indicatif::MultiProgress {
147 indicatif::MultiProgress::new()
148}
149
150pub fn finish_progress_with_message(pb: &ProgressBar, message: &str) {
152 pb.finish_with_message(format!("✅ {message}"));
153}
154
155pub fn finish_progress_with_error(pb: &ProgressBar, message: &str) {
157 pb.finish_with_message(format!("❌ {message}"));
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_spinner_creation() {
166 let spinner = create_spinner("Loading...");
167 assert!(!spinner.is_finished());
168 }
169
170 #[test]
171 fn test_progress_bar_creation() {
172 let pb = create_progress_bar(100, "Testing");
173 assert_eq!(pb.length(), Some(100));
174 }
175
176 #[test]
177 fn test_download_progress_creation() {
178 let pb = create_download_progress(1024 * 1024, "Downloading");
179 assert_eq!(pb.length(), Some(1024 * 1024));
180 }
181}