use std::sync::Arc;
use crate::{
Component,
Event,
InputResult,
RenderError,
Rendered,
components::Loader,
};
pub struct CancellableLoader {
loader: Loader,
signal: Arc<std::sync::atomic::AtomicBool>,
}
impl CancellableLoader {
pub fn new(
message: impl Into<String>,
spinner_color: Option<String>,
message_color: Option<String>,
) -> Self {
Self {
loader: Loader::new(message, spinner_color, message_color),
signal: Arc::new(std::sync::atomic::AtomicBool::new(false)),
}
}
pub fn cancel(&self) {
self.signal
.store(true, std::sync::atomic::Ordering::Relaxed);
}
pub fn is_cancelled(&self) -> bool {
self.signal.load(std::sync::atomic::Ordering::Relaxed)
}
pub fn tick(&mut self) {
self.loader.tick();
}
}
impl Component for CancellableLoader {
fn render(&self, width: u16) -> Result<Rendered, RenderError> {
self.loader.render(width)
}
fn handle_input(&mut self, event: &Event) -> InputResult {
use crate::events::matches_key;
if matches_key(event, &crate::events::Key::ctrl('c')) {
self.cancel();
InputResult::Handled
} else {
InputResult::Ignored
}
}
}
#[cfg(test)]
mod tests {
use crossterm::event::{
KeyCode,
KeyEvent,
KeyModifiers,
};
use super::*;
#[test]
fn render_delegates() {
let cl = CancellableLoader::new("test", None, None);
let r = cl.render(80).unwrap();
assert!(r.lines[0].contains("test"));
}
#[test]
fn ignored_key() {
let mut cl = CancellableLoader::new("test", None, None);
let result = cl.handle_input(&Event::Key(KeyEvent::new(
KeyCode::Char('x'),
KeyModifiers::empty(),
)));
assert!(matches!(result, InputResult::Ignored));
assert!(!cl.is_cancelled());
}
}