use crate::agent::ui::theme::RabTheme;
use crate::tui::Component;
#[derive(Clone)]
pub struct IndicatorOptions {
pub frames: Vec<String>,
pub interval_ms: u64,
}
impl Default for IndicatorOptions {
fn default() -> Self {
Self {
frames: vec![
"⠋".into(),
"⠙".into(),
"⠹".into(),
"⠸".into(),
"⠼".into(),
"⠴".into(),
"⠦".into(),
"⠧".into(),
"⠇".into(),
"⠏".into(),
],
interval_ms: 80,
}
}
}
pub struct WorkingIndicator {
options: IndicatorOptions,
frame: usize,
last_tick: std::time::Instant,
theme: RabTheme,
pub active: bool,
message: String,
show_once: bool,
}
impl WorkingIndicator {
pub fn new() -> Self {
let theme = crate::agent::ui::theme::current_theme().clone();
Self {
options: IndicatorOptions::default(),
frame: 0,
last_tick: std::time::Instant::now(),
theme,
active: false,
show_once: false,
message: "Working...".into(),
}
}
pub fn start(&mut self) {
self.active = true;
self.show_once = true;
self.last_tick = std::time::Instant::now();
}
pub fn stop(&mut self) {
self.active = false;
}
pub fn set_message(&mut self, message: String) {
self.message = message;
}
pub fn should_show(&self) -> bool {
(self.active || self.show_once) && !self.options.frames.is_empty()
}
pub fn set_indicator(&mut self, options: Option<IndicatorOptions>) {
self.options = options.unwrap_or_default();
self.frame = 0;
}
pub fn tick(&mut self) -> bool {
if !self.active || self.options.frames.is_empty() {
return false;
}
let elapsed = self.last_tick.elapsed();
if elapsed.as_millis() >= self.options.interval_ms as u128 {
self.frame = (self.frame + 1) % self.options.frames.len();
self.last_tick = std::time::Instant::now();
return true;
}
false
}
}
impl Default for WorkingIndicator {
fn default() -> Self {
Self::new()
}
}
impl Component for WorkingIndicator {
fn render(&mut self, _width: usize) -> Vec<String> {
if (!self.active && !self.show_once) || self.options.frames.is_empty() {
return vec![];
}
let frame = &self.options.frames[self.frame % self.options.frames.len()];
let line = format!(
" {} {} ",
self.theme.accent(frame),
self.theme.muted(&self.message)
);
self.show_once = false;
vec![String::new(), line]
}
}