|
|
@ -20,12 +20,20 @@ use crate::module::BarModuleFn; |
|
|
|
use crate::shared::fmt::format_placeholders; |
|
|
|
use crate::shared::fmt::format_placeholders; |
|
|
|
use battery as bat; |
|
|
|
use battery as bat; |
|
|
|
use std::collections::HashSet; |
|
|
|
use std::collections::HashSet; |
|
|
|
|
|
|
|
use std::sync::Mutex; |
|
|
|
use swaybar_types as s; |
|
|
|
use swaybar_types as s; |
|
|
|
|
|
|
|
|
|
|
|
const NAME: &str = "battery"; |
|
|
|
const NAME: &str = "battery"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct State { |
|
|
|
|
|
|
|
state_of_charge: f32, |
|
|
|
|
|
|
|
state_of_health: f32, |
|
|
|
|
|
|
|
state: String, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub struct BarModuleBattery { |
|
|
|
pub struct BarModuleBattery { |
|
|
|
config: config::ModuleConfig, |
|
|
|
config: config::ModuleConfig, |
|
|
|
|
|
|
|
state: Mutex<State>, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn get_refreshed_batteries( |
|
|
|
fn get_refreshed_batteries( |
|
|
@ -42,56 +50,70 @@ fn get_refreshed_batteries( |
|
|
|
Ok(bats) |
|
|
|
Ok(bats) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn get_text(cfg: &config::ModuleConfig) -> String { |
|
|
|
fn set_state(state: &Mutex<State>) { |
|
|
|
// FIXME: Creating the Manager on every refresh is bad but internally
|
|
|
|
// FIXME: Creating the Manager on every refresh is bad but internally
|
|
|
|
// it uses an Rc so if I keep it as a field of BarModuleBattery, that
|
|
|
|
// it uses an Rc so if I keep it as a field of BarModuleBattery, that
|
|
|
|
// cannot be Sync.
|
|
|
|
// cannot be Sync.
|
|
|
|
let manager = battery::Manager::new().unwrap(); |
|
|
|
let manager = battery::Manager::new().unwrap(); |
|
|
|
match get_refreshed_batteries(&manager) { |
|
|
|
match get_refreshed_batteries(&manager) { |
|
|
|
Ok(bats) => { |
|
|
|
Ok(bats) => { |
|
|
|
if bats.is_empty() { |
|
|
|
let mut state = state.lock().expect("Could not lock state."); |
|
|
|
return String::new(); |
|
|
|
state.state_of_charge = |
|
|
|
} |
|
|
|
bats.iter().map(|b| b.state_of_charge().value).sum::<f32>() |
|
|
|
format_placeholders!(&cfg.format, cfg.is_html_escape(), { |
|
|
|
/ bats.len() as f32 |
|
|
|
"state_of_charge" => bats.iter() |
|
|
|
* 100_f32; |
|
|
|
.map(|b| b.state_of_charge().value) |
|
|
|
state.state_of_health = |
|
|
|
.sum::<f32>() |
|
|
|
bats.iter().map(|b| b.state_of_health().value).sum::<f32>() |
|
|
|
/ bats.len() as f32 * 100_f32, |
|
|
|
/ bats.len() as f32 |
|
|
|
"state_of_health" => bats.iter() |
|
|
|
* 100_f32; |
|
|
|
.map(|b| b.state_of_health().value) |
|
|
|
state.state = { |
|
|
|
.sum::<f32>() |
|
|
|
let states = bats |
|
|
|
/ bats.len() as f32 * 100_f32, |
|
|
|
.iter() |
|
|
|
"state" => { |
|
|
|
.map(|b| format!("{:?}", b.state())) |
|
|
|
let states = bats.iter() |
|
|
|
.collect::<HashSet<String>>(); |
|
|
|
.map(|b| format!("{:?}", b.state())) |
|
|
|
if states.len() == 1 { |
|
|
|
.collect::<HashSet<String>>(); |
|
|
|
states.iter().next().unwrap().to_owned() |
|
|
|
if states.len() == 1 { |
|
|
|
} else { |
|
|
|
states.iter().next().unwrap().to_owned() |
|
|
|
let mut comma_sep_string = String::from("["); |
|
|
|
} else { |
|
|
|
let mut first = true; |
|
|
|
let mut comma_sep_string = String::from("["); |
|
|
|
for state in states { |
|
|
|
let mut first = true; |
|
|
|
if first { |
|
|
|
for state in states { |
|
|
|
comma_sep_string = comma_sep_string + &state; |
|
|
|
if first { |
|
|
|
first = false; |
|
|
|
comma_sep_string = comma_sep_string + &state; |
|
|
|
} else { |
|
|
|
first = false; |
|
|
|
comma_sep_string = comma_sep_string + ", " + &state; |
|
|
|
} else { |
|
|
|
|
|
|
|
comma_sep_string = comma_sep_string |
|
|
|
|
|
|
|
+ ", " + &state; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
comma_sep_string += "]"; |
|
|
|
|
|
|
|
comma_sep_string |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
comma_sep_string += "]"; |
|
|
|
}) |
|
|
|
comma_sep_string |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Err(err) => { |
|
|
|
|
|
|
|
log::error!("Could not update battery state: {}", err); |
|
|
|
} |
|
|
|
} |
|
|
|
Err(err) => format!("{}", err), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn get_text(fmt: &str, html_escape: bool, state: &Mutex<State>) -> String { |
|
|
|
|
|
|
|
let state = state.lock().expect("Could not lock state."); |
|
|
|
|
|
|
|
format_placeholders!(fmt, html_escape, { |
|
|
|
|
|
|
|
"state_of_charge" => state.state_of_charge, |
|
|
|
|
|
|
|
"state_of_health" => state.state_of_health, |
|
|
|
|
|
|
|
"state" => state.state.as_str(), |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl BarModuleFn for BarModuleBattery { |
|
|
|
impl BarModuleFn for BarModuleBattery { |
|
|
|
fn create(config: config::ModuleConfig) -> Box<dyn BarModuleFn> { |
|
|
|
fn create(config: config::ModuleConfig) -> Box<dyn BarModuleFn> { |
|
|
|
Box::new(BarModuleBattery { config }) |
|
|
|
Box::new(BarModuleBattery { |
|
|
|
|
|
|
|
config, |
|
|
|
|
|
|
|
state: Mutex::new(State { |
|
|
|
|
|
|
|
state_of_charge: 0.0, |
|
|
|
|
|
|
|
state_of_health: 0.0, |
|
|
|
|
|
|
|
state: "Unknown".to_owned(), |
|
|
|
|
|
|
|
}), |
|
|
|
|
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn default_config(instance: String) -> config::ModuleConfig { |
|
|
|
fn default_config(instance: String) -> config::ModuleConfig { |
|
|
@ -109,7 +131,12 @@ impl BarModuleFn for BarModuleBattery { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn build(&self) -> s::Block { |
|
|
|
fn build(&self) -> s::Block { |
|
|
|
let text = get_text(&self.config); |
|
|
|
set_state(&self.state); |
|
|
|
|
|
|
|
let text = get_text( |
|
|
|
|
|
|
|
&self.config.format, |
|
|
|
|
|
|
|
self.config.is_html_escape(), |
|
|
|
|
|
|
|
&self.state, |
|
|
|
|
|
|
|
); |
|
|
|
s::Block { |
|
|
|
s::Block { |
|
|
|
name: Some(NAME.to_owned()), |
|
|
|
name: Some(NAME.to_owned()), |
|
|
|
instance: Some(self.config.instance.clone()), |
|
|
|
instance: Some(self.config.instance.clone()), |
|
|
@ -130,4 +157,12 @@ impl BarModuleFn for BarModuleBattery { |
|
|
|
separator_block_width: None, |
|
|
|
separator_block_width: None, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn subst_args<'a>(&'a self, cmd: &'a [String]) -> Option<Vec<String>> { |
|
|
|
|
|
|
|
Some( |
|
|
|
|
|
|
|
cmd.iter() |
|
|
|
|
|
|
|
.map(|arg| get_text(arg, false, &self.state)) |
|
|
|
|
|
|
|
.collect(), |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|