Skip to main content

graphrag_cli/ui/
spinner.rs

1//! Animated spinner for progress indication
2
3use std::time::{Duration, Instant};
4
5/// Animated spinner with various styles
6pub struct Spinner {
7    /// Current frame index
8    frame_index: usize,
9    /// Frames for animation
10    frames: Vec<&'static str>,
11    /// Last update time
12    last_update: Instant,
13    /// Animation speed (milliseconds per frame)
14    speed_ms: u64,
15}
16
17impl Spinner {
18    /// Create a new spinner with default animation
19    pub fn new() -> Self {
20        Self {
21            frame_index: 0,
22            frames: vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
23            last_update: Instant::now(),
24            speed_ms: 80,
25        }
26    }
27
28    /// Create a dots spinner
29    #[allow(dead_code)]
30    pub fn dots() -> Self {
31        Self {
32            frame_index: 0,
33            frames: vec!["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"],
34            last_update: Instant::now(),
35            speed_ms: 80,
36        }
37    }
38
39    /// Create a simple spinner
40    #[allow(dead_code)]
41    pub fn simple() -> Self {
42        Self {
43            frame_index: 0,
44            frames: vec!["|", "/", "-", "\\"],
45            last_update: Instant::now(),
46            speed_ms: 100,
47        }
48    }
49
50    /// Update animation and get current frame
51    pub fn tick(&mut self) -> &'static str {
52        let now = Instant::now();
53        if now.duration_since(self.last_update) >= Duration::from_millis(self.speed_ms) {
54            self.frame_index = (self.frame_index + 1) % self.frames.len();
55            self.last_update = now;
56        }
57        self.frames[self.frame_index]
58    }
59
60    /// Reset to first frame
61    #[allow(dead_code)]
62    pub fn reset(&mut self) {
63        self.frame_index = 0;
64        self.last_update = Instant::now();
65    }
66}
67
68impl Default for Spinner {
69    fn default() -> Self {
70        Self::new()
71    }
72}