1#![allow(dead_code)]
4
5use indicatif::{ProgressBar, ProgressStyle};
6use std::time::Duration;
7
8pub fn file_progress(total: u64, message: &str) -> ProgressBar {
10 let pb = ProgressBar::new(total);
11 pb.set_style(
12 ProgressStyle::default_bar()
13 .template("{spinner:.green} {msg} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec})")
14 .expect("valid template")
15 .progress_chars("=>-"),
16 );
17 pb.set_message(message.to_string());
18 pb.enable_steady_tick(Duration::from_millis(100));
19 pb
20}
21
22pub fn block_progress(total: u64, message: &str) -> ProgressBar {
24 let pb = ProgressBar::new(total);
25 pb.set_style(
26 ProgressStyle::default_bar()
27 .template("{spinner:.green} {msg} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} blocks")
28 .expect("valid template")
29 .progress_chars("=>-"),
30 );
31 pb.set_message(message.to_string());
32 pb.enable_steady_tick(Duration::from_millis(100));
33 pb
34}
35
36pub fn spinner(message: &str) -> ProgressBar {
38 let pb = ProgressBar::new_spinner();
39 pb.set_style(
40 ProgressStyle::default_spinner()
41 .template("{spinner:.green} {msg} [{elapsed_precise}]")
42 .expect("valid template"),
43 );
44 pb.set_message(message.to_string());
45 pb.enable_steady_tick(Duration::from_millis(100));
46 pb
47}
48
49pub fn download_progress(total: u64, filename: &str) -> ProgressBar {
51 let pb = ProgressBar::new(total);
52 pb.set_style(
53 ProgressStyle::default_bar()
54 .template("{spinner:.green} Downloading {msg} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
55 .expect("valid template")
56 .progress_chars("=>-"),
57 );
58 pb.set_message(filename.to_string());
59 pb.enable_steady_tick(Duration::from_millis(100));
60 pb
61}
62
63pub fn upload_progress(total: u64, filename: &str) -> ProgressBar {
65 let pb = ProgressBar::new(total);
66 pb.set_style(
67 ProgressStyle::default_bar()
68 .template("{spinner:.green} Uploading {msg} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
69 .expect("valid template")
70 .progress_chars("=>-"),
71 );
72 pb.set_message(filename.to_string());
73 pb.enable_steady_tick(Duration::from_millis(100));
74 pb
75}
76
77pub fn batch_progress(total: u64, message: &str) -> ProgressBar {
79 let pb = ProgressBar::new(total);
80 pb.set_style(
81 ProgressStyle::default_bar()
82 .template("{spinner:.green} {msg} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({percent}%)")
83 .expect("valid template")
84 .progress_chars("=>-"),
85 );
86 pb.set_message(message.to_string());
87 pb.enable_steady_tick(Duration::from_millis(100));
88 pb
89}
90
91pub fn finish_success(pb: &ProgressBar, message: &str) {
93 pb.set_style(
94 ProgressStyle::default_bar()
95 .template("{msg}")
96 .expect("valid template"),
97 );
98 pb.finish_with_message(format!("\x1b[32m✓\x1b[0m {}", message));
99}
100
101pub fn finish_error(pb: &ProgressBar, message: &str) {
103 pb.set_style(
104 ProgressStyle::default_bar()
105 .template("{msg}")
106 .expect("valid template"),
107 );
108 pb.finish_with_message(format!("\x1b[31m✗\x1b[0m {}", message));
109}
110
111pub fn finish_spinner_success(pb: &ProgressBar, message: &str) {
113 pb.finish_with_message(format!("\x1b[32m✓\x1b[0m {}", message));
114}
115
116pub fn finish_spinner_error(pb: &ProgressBar, message: &str) {
118 pb.finish_with_message(format!("\x1b[31m✗\x1b[0m {}", message));
119}
120
121pub struct StreamProgress {
123 pb: ProgressBar,
124 total: u64,
125 current: u64,
126}
127
128impl StreamProgress {
129 pub fn new(total: u64, message: &str) -> Self {
131 let pb = file_progress(total, message);
132 Self {
133 pb,
134 total,
135 current: 0,
136 }
137 }
138
139 pub fn update(&mut self, bytes: u64) {
141 self.current += bytes;
142 self.pb.set_position(self.current);
143 }
144
145 pub fn set_position(&mut self, pos: u64) {
147 self.current = pos;
148 self.pb.set_position(pos);
149 }
150
151 pub fn percentage(&self) -> f64 {
153 if self.total == 0 {
154 100.0
155 } else {
156 (self.current as f64 / self.total as f64) * 100.0
157 }
158 }
159
160 pub fn finish(self, message: &str) {
162 finish_success(&self.pb, message);
163 }
164
165 pub fn finish_error(self, message: &str) {
167 finish_error(&self.pb, message);
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174
175 #[test]
176 fn test_spinner_creation() {
177 let pb = spinner("Testing...");
178 pb.finish_with_message("Done");
179 }
180
181 #[test]
182 fn test_progress_creation() {
183 let pb = file_progress(1000, "Processing");
184 pb.set_position(500);
185 pb.finish_with_message("Complete");
186 }
187
188 #[test]
189 fn test_stream_progress() {
190 let mut sp = StreamProgress::new(100, "Streaming");
191 sp.update(25);
192 assert_eq!(sp.percentage(), 25.0);
193 sp.update(25);
194 assert_eq!(sp.percentage(), 50.0);
195 sp.finish("Done");
196 }
197}