fcrypt 0.3.2

Cross-platform CLI for password-based file encryption and decryption
Documentation
use indicatif::{ProgressBar, ProgressStyle};
use std::cell::Cell;
use std::io::IsTerminal;

pub struct OperationProgress {
    progress: ProgressBar,
    total: u64,
    message: String,
    started_payload: Cell<bool>,
}

pub fn create_progress(total: u64, message: &str, enabled: bool) -> OperationProgress {
    if !enabled || !std::io::stderr().is_terminal() {
        return OperationProgress {
            progress: ProgressBar::hidden(),
            total,
            message: message.to_owned(),
            started_payload: Cell::new(true),
        };
    }
    let progress = ProgressBar::new_spinner();
    progress.set_style(
        ProgressStyle::with_template("{spinner:.cyan} {msg}")
            .expect("spinner template must be valid"),
    );
    progress.set_message(format!("{message}: preparing keys"));
    progress.enable_steady_tick(std::time::Duration::from_millis(100));
    OperationProgress {
        progress,
        total,
        message: message.to_owned(),
        started_payload: Cell::new(false),
    }
}

impl OperationProgress {
    pub fn inc(&self, bytes: u64) {
        if !self.started_payload.replace(true) {
            self.progress.disable_steady_tick();
            self.progress.set_length(self.total);
            self.progress.set_style(
                ProgressStyle::with_template(
                    "{msg:>10} [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})",
                )
                .expect("progress template must be valid")
                .progress_chars("##-"),
            );
            self.progress.set_message(self.message.clone());
        }
        self.progress.inc(bytes);
    }

    pub fn finish(&self) {
        self.progress.finish_and_clear();
    }
}