winbrew_ui/
progress.rs

1use super::{Ui, theme::SPINNER_TICK_MS};
2use indicatif::{ProgressBar, ProgressStyle};
3use std::io::Write;
4use std::time::Duration;
5
6#[must_use = "progress handles must be held until the operation completes"]
7pub struct ProgressHandle(ProgressBar);
8
9impl ProgressHandle {
10    fn progress(&self) -> &ProgressBar {
11        &self.0
12    }
13
14    pub fn set_length(&self, length: u64) {
15        self.progress().set_length(length);
16    }
17
18    pub fn set_message(&self, message: impl Into<String>) {
19        self.progress().set_message(message.into());
20    }
21
22    pub fn inc(&self, amount: u64) {
23        self.progress().inc(amount);
24    }
25}
26
27impl Drop for ProgressHandle {
28    fn drop(&mut self) {
29        self.0.finish_and_clear();
30    }
31}
32
33#[must_use = "spinner guards must be held until the phase ends"]
34pub struct SpinnerGuard(ProgressBar);
35
36impl SpinnerGuard {
37    pub fn update_message(&self, msg: impl Into<String>) {
38        self.0.set_message(msg.into());
39    }
40}
41
42impl Drop for SpinnerGuard {
43    fn drop(&mut self) {
44        self.0.finish_and_clear();
45    }
46}
47
48impl<W: Write> Ui<W> {
49    pub fn progress_bar(&self) -> ProgressHandle {
50        let pb = ProgressBar::new(0);
51        pb.set_style(ProgressStyle::clone(&self.progress_style));
52        ProgressHandle(pb)
53    }
54
55    pub fn start_spinner(&self, message: impl Into<String>) -> SpinnerGuard {
56        let spinner = ProgressBar::new_spinner();
57        spinner.set_style(ProgressStyle::clone(&self.spinner_style));
58        spinner.set_message(message.into());
59        spinner.enable_steady_tick(Duration::from_millis(SPINNER_TICK_MS));
60        SpinnerGuard(spinner)
61    }
62
63    pub fn spinner<T, F: FnOnce() -> T>(&self, message: impl Into<String>, f: F) -> T {
64        let _guard = self.start_spinner(message);
65        f()
66    }
67}