use std::time::Duration;
use crate::core::{grapheme::StyledGraphemes, render::SharedRenderer};
pub mod frame;
use frame::Frame;
pub trait State {
fn is_idle(&self) -> impl Future<Output = bool> + Send;
}
#[derive(Clone, Debug)]
pub struct Spinner {
pub frames: Frame,
pub suffix: String,
pub duration: Duration,
}
impl Default for Spinner {
fn default() -> Self {
Self {
frames: frame::DOTS,
suffix: String::new(),
duration: Duration::from_millis(100),
}
}
}
impl Spinner {
pub fn frames(mut self, frames: Frame) -> Self {
self.frames = frames;
self
}
pub fn suffix(mut self, suffix: impl Into<String>) -> Self {
self.suffix = suffix.into();
self
}
pub fn duration(mut self, duration: Duration) -> Self {
self.duration = duration;
self
}
}
pub async fn run<S, I>(
spinner: &Spinner,
state: S,
index: I,
renderer: SharedRenderer<I>,
) -> anyhow::Result<()>
where
S: State,
I: Clone + Ord + Send + Sync + 'static,
{
let mut frame_index = 0;
let mut interval = tokio::time::interval(spinner.duration);
loop {
interval.tick().await;
if !state.is_idle().await {
frame_index = (frame_index + 1) % spinner.frames.len();
renderer
.update([(
index.clone(),
StyledGraphemes::from(format!(
"{} {}",
spinner.frames[frame_index], spinner.suffix
)),
)])
.render()
.await?;
}
}
}