use indicatif::{MultiProgress, ProgressBar, ProgressState, ProgressStyle};
use remozipsy::{Error, Progress};
use std::fmt::{Debug, Write};
pub(crate) struct Bar {
mp: MultiProgress,
evaluating: Option<ProgressBar>,
download_bar: ProgressBar,
unzip_bar: ProgressBar,
delete_bar: ProgressBar,
}
impl Default for Bar {
fn default() -> Self {
let sty_download = ProgressStyle::with_template(
"{msg:<8}: [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})",
)
.unwrap()
.with_key("eta", |state: &ProgressState, w: &mut dyn Write| {
write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap()
})
.progress_chars("##-");
let sty = ProgressStyle::with_template("[{elapsed_precise}] {wide_bar:.cyan/blue} {msg}")
.unwrap()
.progress_chars("##-");
let mp = MultiProgress::new();
let evaluating = mp.add(ProgressBar::new(1));
evaluating.set_style(sty.clone());
evaluating.set_message("evaluating");
evaluating.tick();
let evaluating = Some(evaluating);
let download_bar = mp.add(ProgressBar::no_length());
download_bar.set_style(sty_download.clone());
download_bar.set_message("download");
let unzip_bar = mp.add(ProgressBar::no_length());
unzip_bar.set_style(sty_download.clone());
unzip_bar.set_message("unzip");
let delete_bar = mp.add(ProgressBar::no_length());
delete_bar.set_style(sty_download.clone());
delete_bar.set_message("delete");
Self {
mp,
evaluating,
download_bar,
unzip_bar,
delete_bar,
}
}
}
impl Bar {
fn finish_evaluating(&mut self) {
if let Some(bar) = self.evaluating.take() {
bar.tick();
bar.set_message("done");
bar.finish();
}
}
pub fn display<RE: Debug, FE: Debug>(&mut self, progress: Progress<RE, FE>) -> Result<(), Error<RE, FE>> {
match progress {
Progress::Incomplete {
download,
unzip,
delete,
} => {
self.finish_evaluating();
self.download_bar.set_length(download.total_bytes());
self.download_bar.set_position(download.processed_bytes());
if download.is_finished() {
self.download_bar.finish();
}
self.unzip_bar.set_length(unzip.total_bytes());
self.unzip_bar.set_position(unzip.processed_bytes());
if unzip.is_finished() {
self.unzip_bar.finish();
}
self.delete_bar.set_length(delete.total_bytes());
self.delete_bar.set_position(delete.processed_bytes());
if delete.is_finished() {
self.delete_bar.finish();
}
},
Progress::Successful => {},
Progress::Errored(e) => return Err(e),
};
Ok(())
}
pub fn cleanup(mut self) {
if let Some(bar) = self.evaluating.take() {
bar.finish()
};
drop(self.download_bar);
drop(self.unzip_bar);
drop(self.delete_bar);
drop(self.mp);
}
}
#[cfg(test)]
mod tests {
use super::*;
use remozipsy::{Error, Progress};
#[test]
fn test_evaluating_finish() {
let mut bar = Bar::default();
bar.finish_evaluating();
assert!(bar.evaluating.is_none());
}
#[test]
fn verify_bar_doesnt_crash() { let _bar = Bar::default(); }
#[test]
fn verify_display_doesnt_crash() {
let mut bar = Bar::default();
bar.display(Progress::<(), ()>::Successful).unwrap();
bar.display(Progress::<(), ()>::Errored(Error::JoinError)).unwrap_err();
}
}