use colored::Colorize;
use indicatif::{ProgressBar, ProgressStyle};
use tokio::time::Duration;
use crate::consts::TICK_STRING;
const CUBE_HALF_FRAMES: [&str; 4] = ["⬒", "◨", "⬓", "◧"];
const SHIMMER_DIM: (u8, u8, u8) = (120, 128, 140);
const SHIMMER_BRIGHT: (u8, u8, u8) = (170, 225, 255);
fn lerp_rgb(a: (u8, u8, u8), b: (u8, u8, u8), t: f32) -> (u8, u8, u8) {
let l = |x: u8, y: u8| (x as f32 + (y as f32 - x as f32) * t).round() as u8;
(l(a.0, b.0), l(a.1, b.1), l(a.2, b.2))
}
pub fn create_shimmer_spinner(label: &str) -> ProgressBar {
let chars: Vec<char> = label.chars().collect();
let n = chars.len();
let sweep = n + 6;
let frames: Vec<String> = (0..sweep)
.map(|i| {
let center = i as isize - 3;
let cube = CUBE_HALF_FRAMES[i % 4];
let dots = ".".repeat((i / 2) % 4); let mut text = String::new();
for (c, ch) in chars.iter().enumerate() {
let dist = (c as isize - center).abs();
let intensity = (1.0 - dist as f32 / 3.0).clamp(0.0, 1.0);
let (r, g, b) = lerp_rgb(SHIMMER_DIM, SHIMMER_BRIGHT, intensity);
text.push_str(&ch.to_string().truecolor(r, g, b).to_string());
}
let (cr, cg, cb) = SHIMMER_BRIGHT;
format!("{} {text}{dots}", cube.truecolor(cr, cg, cb))
})
.chain(std::iter::once(label.to_string()))
.collect();
let frame_refs: Vec<&str> = frames.iter().map(String::as_str).collect();
let spinner = ProgressBar::new_spinner().with_style(
ProgressStyle::default_spinner()
.tick_strings(&frame_refs)
.template("{spinner}")
.expect("Failed to create shimmer spinner template"),
);
spinner.enable_steady_tick(Duration::from_millis(90));
spinner
}
pub fn create_spinner(message: String) -> ProgressBar {
let spinner = ProgressBar::new_spinner()
.with_style(
ProgressStyle::default_spinner()
.tick_chars(TICK_STRING)
.template("{spinner:.green} {msg}")
.expect("Failed to create spinner template"),
)
.with_message(message);
spinner.enable_steady_tick(Duration::from_millis(100));
spinner
}
pub fn create_spinner_if(show: bool, message: String) -> Option<ProgressBar> {
if show {
Some(create_spinner(message))
} else {
None
}
}
pub fn fail_spinner(spinner: &mut ProgressBar, message: String) {
spinner.set_style(
ProgressStyle::default_spinner()
.template("{msg:.red}")
.expect("Failed to create error spinner template"),
);
spinner.finish_with_message(format!("✗ {message}"));
}
pub fn success_spinner(spinner: &mut ProgressBar, message: String) {
spinner.set_style(
ProgressStyle::default_spinner()
.template("{msg:.green}")
.expect("Failed to create success spinner template"),
);
spinner.finish_with_message(format!("✓ {message}"));
}