use std::env; use chrono::{DateTime, Local, Locale}; use color_eyre::Result; use gtk::prelude::*; use gtk::{Align, Button, Calendar, Label, Orientation}; use serde::Deserialize; use tokio::sync::{broadcast, mpsc}; use tokio::time::sleep; use crate::config::{CommonConfig, ModuleOrientation}; use crate::gtk_helpers::IronbarGtkExt; use crate::modules::{ Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext, }; use crate::{glib_recv, module_impl, send_async, spawn, try_send}; #[derive(Debug, Deserialize, Clone)] pub struct ClockModule { /// Date/time format string. /// Default: `%d/%m/%Y %H:%M` /// /// Detail on available tokens can be found here: /// #[serde(default = "default_format")] format: String, #[serde(default = "default_popup_format")] format_popup: String, #[serde(default = "default_locale")] locale: String, #[serde(default)] orientation: ModuleOrientation, #[serde(flatten)] pub common: Option, } impl Default for ClockModule { fn default() -> Self { ClockModule { format: default_format(), format_popup: default_popup_format(), locale: default_locale(), orientation: ModuleOrientation::Horizontal, common: Some(CommonConfig::default()), } } } fn default_format() -> String { String::from("%d/%m/%Y %H:%M") } fn default_popup_format() -> String { String::from("%H:%M:%S") } fn default_locale() -> String { env::var("LC_TIME") .or_else(|_| env::var("LANG")) .map_or_else(|_| "POSIX".to_string(), strip_tail) } fn strip_tail(string: String) -> String { string .split_once('.') .map(|(head, _)| head.to_string()) .unwrap_or(string) } impl Module