From b7f83b4810d115c2986e5c24b83473f0b4ee0acd Mon Sep 17 00:00:00 2001 From: Mahesh Asolkar Date: Sun, 11 May 2025 16:02:14 -0700 Subject: [PATCH] Refactoring of bar modules * Moved debug functions to separate trait * Broke up module actions and moved assembling of icon and content in main instead of module itself. This will enable disabling of icon or content via options in the future --- src/bar_modules/bar_module_music.rs | 51 +++++++++++++++---- src/bar_modules/bar_module_weather.rs | 73 ++++++++++++++++++--------- src/bar_modules/mod.rs | 17 ++++++- src/common/mod.rs | 2 +- src/main.rs | 49 +++++++++++++----- 5 files changed, 140 insertions(+), 52 deletions(-) diff --git a/src/bar_modules/bar_module_music.rs b/src/bar_modules/bar_module_music.rs index 5f2a560..135d4d9 100644 --- a/src/bar_modules/bar_module_music.rs +++ b/src/bar_modules/bar_module_music.rs @@ -5,15 +5,26 @@ use crate::bar_modules; #[derive(Clone)] pub struct UnibarModuleMusic { - pub opts: common::AppOptions, + opts: common::AppOptions, + current_stdout :String, + progress_stdout :String, +} + +impl UnibarModuleMusic { + // -------------------- + pub fn new(o :common::AppOptions) -> UnibarModuleMusic { + UnibarModuleMusic { + opts: o, + current_stdout: "".to_string(), + progress_stdout: "".to_string(), + } + } } impl bar_modules::BarModuleActions for UnibarModuleMusic { // -------------------- - fn get(&self) -> String { - let mut parts = Vec::new(); - + fn generate_data(&mut self) { // MPD format options here: // https://manpages.ubuntu.com/manpages/plucky/man1/mpc.1.html let current_output = Command::new("mpc") @@ -23,9 +34,8 @@ impl bar_modules::BarModuleActions for UnibarModuleMusic { .stdout(Stdio::piped()) .output() .unwrap(); - let mut current_stdout = String::from_utf8(current_output.stdout).unwrap(); - current_stdout.pop(); - parts.push(format!("{}", current_stdout)); + self.current_stdout = String::from_utf8(current_output.stdout).unwrap(); + self.current_stdout.pop(); if self.opts.music_progress { let progress_output = Command::new("mpc") @@ -34,11 +44,32 @@ impl bar_modules::BarModuleActions for UnibarModuleMusic { .stdout(Stdio::piped()) .output() .unwrap(); - let mut progress_stdout = String::from_utf8(progress_output.stdout).unwrap(); - progress_stdout.pop(); - parts.push(format!("[{}]", progress_stdout)); + self.progress_stdout = String::from_utf8(progress_output.stdout).unwrap(); + self.progress_stdout.pop(); + } + } + + // -------------------- + fn get_content(&self) -> String { + let mut parts = Vec::new(); + parts.push(format!("{}", self.current_stdout)); + + if self.opts.music_progress { + parts.push(format!("[{}]", self.progress_stdout)); } return format!("{}", parts.join(" ")); } + + // -------------------- + fn get_icon(&self) -> String { + return "".to_string(); + } +} + +impl bar_modules::BarModuleDebug for UnibarModuleMusic { + + // -------------------- + fn post_debug(&self) { + } } diff --git a/src/bar_modules/bar_module_weather.rs b/src/bar_modules/bar_module_weather.rs index 6aaf607..b5df2d7 100644 --- a/src/bar_modules/bar_module_weather.rs +++ b/src/bar_modules/bar_module_weather.rs @@ -1,5 +1,6 @@ use std::str; use curl::easy::{Easy, List}; +use serde_json::json; use serde_json::Value; use regex::Regex; @@ -8,15 +9,24 @@ use crate::bar_modules; #[derive(Clone)] pub struct UnibarModuleWeather { - pub opts: common::AppOptions, + opts: common::AppOptions, + weather_info: Value, } impl UnibarModuleWeather { // -------------------- - fn get_current_temperature(&self, v: Value) -> f32 { - let deg_c :f32 = v["features"][0]["properties"]["temperature"]["value"] - .to_string().parse().unwrap(); + pub fn new(o :common::AppOptions) -> UnibarModuleWeather { + UnibarModuleWeather { + opts: o, + weather_info: json!(serde_json::Value::Null), + } + } + + // -------------------- + fn get_current_temperature(&self) -> f32 { + let deg_c :f32 = self.weather_info["features"][0]["properties"]["temperature"]["value"] + .to_string().parse().unwrap(); match self.opts.weather_units { common::TemperatureUnits::Metric => return deg_c, @@ -31,19 +41,8 @@ impl UnibarModuleWeather { } // -------------------- - fn get_icon(&self, v: Value) -> String { - // "icon": "https://api.weather.gov/icons/land/night/ovc?size=medium", - let re = Regex::new(r"(\w+)\?size").unwrap(); - let json_val = v["features"][0]["properties"]["icon"].to_string(); - let caps = re.captures(&json_val).unwrap(); - - // println!("{}", caps.get(1).unwrap().as_str()); - return self.get_unicode_symbol(caps.get(1).unwrap().as_str()); - } - - // -------------------- - fn get_unicode_symbol(&self, v: &str) -> String { - match v { + fn get_unicode_symbol(&self, condition: &str) -> String { + match condition { "skc" => { return "☀️".to_string(); } // Fair/clear "few" => { return "🌥️".to_string(); } // A few clouds "sct" => { return "🌥️".to_string(); } // Partly cloudy @@ -83,7 +82,7 @@ impl UnibarModuleWeather { } // -------------------- - pub fn get_icons(&self) { + fn get_icons(&self) { // Print a web page onto stdout let mut curl = Easy::new(); let mut url_string = Vec::new(); @@ -109,7 +108,7 @@ impl UnibarModuleWeather { } // -------------------- - pub fn show_icons(&self) { + fn show_icons(&self) { println!("{} skc Fair/clear", self.get_unicode_symbol("skc")); println!("{} few A few clouds", self.get_unicode_symbol("few")); println!("{} sct Partly cloudy", self.get_unicode_symbol("sct")); @@ -152,7 +151,7 @@ impl UnibarModuleWeather { impl bar_modules::BarModuleActions for UnibarModuleWeather { // -------------------- - fn get(&self) -> String { + fn generate_data(&mut self) { // Print a web page onto stdout let mut curl = Easy::new(); let mut url_string = Vec::new(); @@ -180,11 +179,35 @@ impl bar_modules::BarModuleActions for UnibarModuleWeather { println!("-----> curl_data - [{}]", std::str::from_utf8(&curl_ret).unwrap()); } - let v: Value = serde_json::from_str(str::from_utf8(&curl_ret).unwrap()).unwrap(); - let temperature_value :f32 = self.get_current_temperature(v.clone()); - let temperature_unit :String = self.get_temperature_unit(); - let temperature_icon :String = self.get_icon(v.clone()); + self.weather_info = serde_json::from_str(str::from_utf8(&curl_ret).unwrap()).unwrap(); + } - return format!("{} {:.2}{}", temperature_icon, temperature_value, temperature_unit); + // -------------------- + fn get_content(&self) -> String { + let temperature_value :f32 = self.get_current_temperature(); + let temperature_unit :String = self.get_temperature_unit(); + // let temperature_icon :String = self.get_icon(v.clone()); + + return format!("{:.2}{}", temperature_value, temperature_unit); + } + + // -------------------- + fn get_icon(&self) -> String { + // "icon": "https://api.weather.gov/icons/land/night/ovc?size=medium", + let re = Regex::new(r"(\w+)\?size").unwrap(); + let json_val = self.weather_info["features"][0]["properties"]["icon"].to_string(); + let caps = re.captures(&json_val).unwrap(); + + // println!("{}", caps.get(1).unwrap().as_str()); + return self.get_unicode_symbol(caps.get(1).unwrap().as_str()); + } +} + +impl bar_modules::BarModuleDebug for UnibarModuleWeather { + + // -------------------- + fn post_debug(&self) { + self.get_icons(); + self.show_icons(); } } diff --git a/src/bar_modules/mod.rs b/src/bar_modules/mod.rs index c6744ee..96e934e 100644 --- a/src/bar_modules/mod.rs +++ b/src/bar_modules/mod.rs @@ -1,7 +1,20 @@ // -------------------- -// All Bar modules must implement the actions +/// All Bar modules must implement the actions pub trait BarModuleActions { - fn get(&self) -> String; + /// Do necessary processing to generate data for this bar module + fn generate_data(&mut self); + + /// Return String content to be displayed in the bar + fn get_content(&self) -> String; + + /// Return a Unicode icon to display before content in the bar. + /// This icon may differ based on content of the data + fn get_icon(&self) -> String; +} + +pub trait BarModuleDebug { + /// Print debug information at the end + fn post_debug(&self); } pub mod bar_module_weather; diff --git a/src/common/mod.rs b/src/common/mod.rs index 9a1efbc..5988d3c 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -27,5 +27,5 @@ pub struct AppOptions { pub weather_station: String, pub music_progress: bool, pub debug_json: bool, - pub debug_icons: bool, + pub debug_modules: bool, } diff --git a/src/main.rs b/src/main.rs index 530e690..86833eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,7 +32,7 @@ struct CommandlineArgs { /// Show ICON debug information #[arg(short = 'I', long)] - debug_icons: bool, + debug_modules: bool, } // @@ -51,24 +51,45 @@ impl Unibar { self.debug_msg("Debugging ..."); } self.check_options(); - let mut parts = Vec::new(); + // Set up a list of all modules to be used let bar_modules_enabled: Vec> = vec! [ - Box::new(bar_modules::bar_module_weather::UnibarModuleWeather { opts: self.opts.clone() }), - Box::new(bar_modules::bar_module_music::UnibarModuleMusic { opts: self.opts.clone() }), + Box::new(bar_modules::bar_module_weather::UnibarModuleWeather::new(self.opts.clone())), + Box::new(bar_modules::bar_module_music::UnibarModuleMusic::new(self.opts.clone())), ]; - for md in bar_modules_enabled { - parts.push(md.get()); + // Get module's part to be displayed in the bar + let mut parts = Vec::new(); + for mut md in bar_modules_enabled { + let mut mod_parts = Vec::new(); + + // Each bar module implements following 3 steps: + // * Generate raw data with pertinent information + // * Return a unicode icon to be displayed + // * Return a String content to be displayed after the icon + // + // Following generates ICON+CONTENT string for a module to be displayed + // in the bar + md.generate_data(); + mod_parts.push(md.get_icon()); + mod_parts.push(md.get_content()); + + parts.push(mod_parts.join(" ")); } + + // Show module debug information if enabled + if self.opts.debug_modules { + let bar_modules_debugged: Vec> = vec! [ + Box::new(bar_modules::bar_module_weather::UnibarModuleWeather::new(self.opts.clone())), + Box::new(bar_modules::bar_module_music::UnibarModuleMusic::new(self.opts.clone())), + ]; + for md in bar_modules_debugged { + md.post_debug(); + } + } + + // Print parts provided by each module println!("{}", parts.join(" | ")); - - if self.opts.debug_icons { - let w = bar_modules::bar_module_weather::UnibarModuleWeather { opts: self.opts.clone() }; - w.get_icons(); - w.show_icons(); - } - } // -------------------- @@ -99,7 +120,7 @@ fn main() { weather_station: cmd_args.weather_station, music_progress: cmd_args.music_progress, debug_json: cmd_args.debug_json, - debug_icons: cmd_args.debug_icons + debug_modules: cmd_args.debug_modules }, };