scarb_ui/components/
spinner.rs

1use std::time::Duration;
2
3use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle, WeakProgressBar};
4
5use crate::{Widget, WidgetHandle};
6
7/// Spinner widget informing about an ongoing process.
8pub struct Spinner {
9    message: String,
10}
11
12impl Spinner {
13    /// Create a new [`Spinner`] with the given message.
14    pub fn new(message: impl Into<String>) -> Self {
15        Self {
16            message: message.into(),
17        }
18    }
19
20    fn default_style() -> ProgressStyle {
21        ProgressStyle::with_template("{spinner:.cyan} {wide_msg} {elapsed}").unwrap()
22    }
23}
24
25/// Finishes the associated [`Spinner`] when dropped.
26pub struct SpinnerHandle {
27    pb: ProgressBar,
28}
29
30impl Drop for SpinnerHandle {
31    fn drop(&mut self) {
32        self.pb.finish_and_clear()
33    }
34}
35
36impl WidgetHandle for SpinnerHandle {
37    fn weak_progress_bar(&self) -> Option<WeakProgressBar> {
38        Some(self.pb.downgrade())
39    }
40}
41
42impl Widget for Spinner {
43    type Handle = SpinnerHandle;
44
45    fn text(self) -> Self::Handle {
46        let pb = ProgressBar::with_draw_target(None, ProgressDrawTarget::stdout())
47            .with_style(Spinner::default_style())
48            .with_message(self.message);
49        pb.enable_steady_tick(Duration::from_millis(120));
50        SpinnerHandle { pb }
51    }
52}