use crate::constants::time_function;
use crate::{error, info, usage};
use indicatif::{ProgressBar, ProgressStyle};
use std::io::{self, Write};
pub fn handle_time(function: &str, arg: &str) {
if function != time_function::COUNTDOWN {
error!("✖️ 未知的功能: {},目前仅支持 countdown", function);
usage!("j time countdown <duration>");
info!(" duration 格式: 30s(秒), 5m(分钟), 1h(小时), 不带单位默认为分钟");
return;
}
let duration_secs = parse_duration(arg);
if duration_secs <= 0 {
error!("✖️ 无效的时长: {}", arg);
return;
}
info!(
"⌛️ 倒计时开始:{}",
format_duration_display(duration_secs as u64)
);
run_countdown(duration_secs as u64);
}
fn format_duration_display(secs: u64) -> String {
if secs >= 3600 {
let h = secs / 3600;
let m = (secs % 3600) / 60;
if m > 0 {
format!("{}小时{}分钟", h, m)
} else {
format!("{}小时", h)
}
} else if secs >= 60 {
let m = secs / 60;
let s = secs % 60;
if s > 0 {
format!("{}分{}秒", m, s)
} else {
format!("{}分钟", m)
}
} else {
format!("{}秒", secs)
}
}
fn parse_duration(s: &str) -> i64 {
let s = s.trim();
if let Some(stripped) = s.strip_suffix('s') {
stripped.parse::<i64>().unwrap_or(-1)
} else if let Some(stripped) = s.strip_suffix('m') {
stripped.parse::<i64>().map(|m| m * 60).unwrap_or(-1)
} else if let Some(stripped) = s.strip_suffix('h') {
stripped.parse::<i64>().map(|h| h * 3600).unwrap_or(-1)
} else {
s.parse::<i64>().map(|m| m * 60).unwrap_or(-1)
}
}
fn format_remaining(secs: u64) -> String {
if secs >= 3600 {
format!(
"{:02}:{:02}:{:02}",
secs / 3600,
(secs % 3600) / 60,
secs % 60
)
} else {
format!("{:02}:{:02}", secs / 60, secs % 60)
}
}
fn run_countdown(total_secs: u64) {
let pb = ProgressBar::new(total_secs);
pb.set_style(
ProgressStyle::default_bar()
.template(" {spinner:.cyan} ⏱️ {msg} {wide_bar:.cyan/dark_gray} {percent}%")
.expect("进度条模板格式错误")
.progress_chars("━╸─"),
);
pb.set_message(format_remaining(total_secs));
let start = std::time::Instant::now();
for elapsed in 1..=total_secs {
let next_tick = start + std::time::Duration::from_secs(elapsed);
let now = std::time::Instant::now();
if next_tick > now {
std::thread::sleep(next_tick - now);
}
let remaining = total_secs - elapsed;
pb.set_position(elapsed);
pb.set_message(format_remaining(remaining));
}
pb.finish_and_clear();
println!(" 🎉 Time's up! 倒计时结束!");
println!();
display_celebration();
}
fn display_celebration() {
let frames = [
" 🔔 Ding Ding! Time's Up! 🔔",
" 💢😤💢 Stop! Stop! Stop! 💢😤💢",
" 🔥😠🔥 How dare you don't stop! 🔥😠🔥",
];
#[cfg(target_os = "macos")]
{
let _ = std::process::Command::new("afplay")
.arg("/System/Library/Sounds/Glass.aiff")
.spawn();
}
for i in 0..6 {
print!("\r{:<60}", frames[i % frames.len()]);
let _ = io::stdout().flush();
std::thread::sleep(std::time::Duration::from_millis(600));
}
println!();
}