diff --git a/Cargo.lock b/Cargo.lock index 0a253bd6..fc011fa0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2729,6 +2729,7 @@ dependencies = [ "image", "komorebi-client", "komorebi-themes", + "lazy_static", "netdev", "num", "num-derive", diff --git a/komorebi-bar/Cargo.toml b/komorebi-bar/Cargo.toml index bb9c9abd..05b66423 100644 --- a/komorebi-bar/Cargo.toml +++ b/komorebi-bar/Cargo.toml @@ -21,6 +21,7 @@ egui-phosphor = "0.9" font-loader = "0.11" hotwatch = { workspace = true } image = "0.25" +lazy_static = { workspace = true } netdev = "0.32" num = "0.4" num-derive = "0.4" diff --git a/komorebi-bar/src/date.rs b/komorebi-bar/src/date.rs index e1259eb1..586f7820 100644 --- a/komorebi-bar/src/date.rs +++ b/komorebi-bar/src/date.rs @@ -2,6 +2,7 @@ use crate::config::LabelPrefix; use crate::render::RenderConfig; use crate::selected_frame::SelectableFrame; use crate::widget::BarWidget; +use chrono::Local; use chrono_tz::Tz; use eframe::egui::text::LayoutJob; use eframe::egui::Align; @@ -39,7 +40,7 @@ impl CustomModifiers { } // get the strftime value of modifier - let formatted_modifier = chrono::Local::now().format(modifier).to_string(); + let formatted_modifier = Local::now().format(modifier).to_string(); // find the gotten value in the original output if let Some(pos) = modified_output.find(&formatted_modifier) { @@ -143,7 +144,7 @@ impl Date { fn output(&mut self) -> String { let formatted = match &self.timezone { Some(timezone) => match timezone.parse::() { - Ok(tz) => chrono::Local::now() + Ok(tz) => Local::now() .with_timezone(&tz) .format(&self.format.fmt_string()) .to_string() @@ -151,7 +152,7 @@ impl Date { .to_string(), Err(_) => format!("Invalid timezone: {}", timezone), }, - None => chrono::Local::now() + None => Local::now() .format(&self.format.fmt_string()) .to_string() .trim() diff --git a/komorebi-bar/src/time.rs b/komorebi-bar/src/time.rs index 37f4a89d..ef4e3a87 100644 --- a/komorebi-bar/src/time.rs +++ b/komorebi-bar/src/time.rs @@ -3,6 +3,8 @@ use crate::config::LabelPrefix; use crate::render::RenderConfig; use crate::selected_frame::SelectableFrame; use crate::widget::BarWidget; +use chrono::Local; +use chrono::NaiveTime; use chrono_tz::Tz; use eframe::egui::text::LayoutJob; use eframe::egui::Align; @@ -15,9 +17,57 @@ use eframe::egui::TextFormat; use eframe::egui::Ui; use eframe::egui::Vec2; use eframe::epaint::StrokeKind; +use lazy_static::lazy_static; use serde::Deserialize; use serde::Serialize; +lazy_static! { + static ref TIME_RANGES: Vec<(&'static str, NaiveTime)> = { + vec![ + ( + egui_phosphor::regular::MOON, + NaiveTime::from_hms_opt(0, 0, 0).expect("invalid"), + ), + ( + egui_phosphor::regular::ALARM, + NaiveTime::from_hms_opt(6, 0, 0).expect("invalid"), + ), + ( + egui_phosphor::regular::BREAD, + NaiveTime::from_hms_opt(6, 1, 0).expect("invalid"), + ), + ( + egui_phosphor::regular::BARBELL, + NaiveTime::from_hms_opt(6, 30, 0).expect("invalid"), + ), + ( + egui_phosphor::regular::COFFEE, + NaiveTime::from_hms_opt(8, 0, 0).expect("invalid"), + ), + ( + egui_phosphor::regular::CLOCK, + NaiveTime::from_hms_opt(8, 30, 0).expect("invalid"), + ), + ( + egui_phosphor::regular::HAMBURGER, + NaiveTime::from_hms_opt(12, 0, 0).expect("invalid"), + ), + ( + egui_phosphor::regular::CLOCK_AFTERNOON, + NaiveTime::from_hms_opt(12, 30, 0).expect("invalid"), + ), + ( + egui_phosphor::regular::FORK_KNIFE, + NaiveTime::from_hms_opt(18, 0, 0).expect("invalid"), + ), + ( + egui_phosphor::regular::MOON_STARS, + NaiveTime::from_hms_opt(18, 30, 0).expect("invalid"), + ), + ] + }; +} + #[derive(Clone, Debug, Serialize, Deserialize)] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct TimeConfig { @@ -40,6 +90,8 @@ pub struct TimeConfig { ///} /// ``` pub timezone: Option, + /// Change the icon depending on the time. The default icon is used between 8:30 and 12:00. (default: false) + pub changing_icon: Option, } impl From for Time { @@ -49,6 +101,7 @@ impl From for Time { format: value.format, label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon), timezone: value.timezone, + changing_icon: value.changing_icon.unwrap_or_default(), } } } @@ -104,26 +157,55 @@ pub struct Time { pub format: TimeFormat, label_prefix: LabelPrefix, timezone: Option, + changing_icon: bool, } impl Time { - fn output(&mut self) -> String { - match &self.timezone { + fn output(&mut self) -> (String, String) { + let (formatted, current_time) = match &self.timezone { Some(timezone) => match timezone.parse::() { - Ok(tz) => chrono::Local::now() - .with_timezone(&tz) - .format(&self.format.fmt_string()) - .to_string() - .trim() - .to_string(), - Err(_) => format!("Invalid timezone: {}", timezone), + Ok(tz) => { + let dt = Local::now().with_timezone(&tz); + ( + dt.format(&self.format.fmt_string()) + .to_string() + .trim() + .to_string(), + Some(dt.time()), + ) + } + Err(_) => (format!("Invalid timezone: {:?}", timezone), None), }, - None => chrono::Local::now() - .format(&self.format.fmt_string()) - .to_string() - .trim() - .to_string(), + None => { + let dt = Local::now(); + ( + dt.format(&self.format.fmt_string()) + .to_string() + .trim() + .to_string(), + Some(dt.time()), + ) + } + }; + + if current_time.is_none() { + return ( + formatted, + egui_phosphor::regular::WARNING_CIRCLE.to_string(), + ); } + + let current_range = match &self.changing_icon { + true => TIME_RANGES + .iter() + .rev() + .find(|&(_, start)| current_time.unwrap() > *start) + .cloned(), + false => None, + } + .unwrap_or((egui_phosphor::regular::CLOCK, NaiveTime::default())); + + (formatted, current_range.0.to_string()) } fn paint_binary_circle( @@ -306,15 +388,13 @@ impl BarWidget for Time { fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) { if self.enable { let mut output = self.output(); - if !output.is_empty() { - let use_binary_circle = output.starts_with('c'); - let use_binary_rectangle = output.starts_with('r'); + if !output.0.is_empty() { + let use_binary_circle = output.0.starts_with('c'); + let use_binary_rectangle = output.0.starts_with('r'); let mut layout_job = LayoutJob::simple( match self.label_prefix { - LabelPrefix::Icon | LabelPrefix::IconAndText => { - egui_phosphor::regular::CLOCK.to_string() - } + LabelPrefix::Icon | LabelPrefix::IconAndText => output.1, LabelPrefix::None | LabelPrefix::Text => String::new(), }, config.icon_font_id.clone(), @@ -323,12 +403,12 @@ impl BarWidget for Time { ); if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix { - output.insert_str(0, "TIME: "); + output.0.insert_str(0, "TIME: "); } if !use_binary_circle && !use_binary_rectangle { layout_job.append( - &output, + &output.0, 10.0, TextFormat { font_id: config.text_font_id.clone(), @@ -351,9 +431,9 @@ impl BarWidget for Time { if use_binary_circle || use_binary_rectangle { let ordered_output = if is_reversed { - output.chars().rev().collect() + output.0.chars().rev().collect() } else { - output + output.0 }; for (section_index, section) in diff --git a/schema.bar.json b/schema.bar.json index 28a747c5..530304a8 100644 --- a/schema.bar.json +++ b/schema.bar.json @@ -896,6 +896,10 @@ "format" ], "properties": { + "changing_icon": { + "description": "Change the icon depending on the time. The default icon is used between 8:30 and 12:00. (default: false)", + "type": "boolean" + }, "enable": { "description": "Enable the Time widget", "type": "boolean" @@ -2302,6 +2306,10 @@ "format" ], "properties": { + "changing_icon": { + "description": "Change the icon depending on the time. The default icon is used between 8:30 and 12:00. (default: false)", + "type": "boolean" + }, "enable": { "description": "Enable the Time widget", "type": "boolean" @@ -3641,6 +3649,10 @@ "format" ], "properties": { + "changing_icon": { + "description": "Change the icon depending on the time. The default icon is used between 8:30 and 12:00. (default: false)", + "type": "boolean" + }, "enable": { "description": "Enable the Time widget", "type": "boolean"