refactor: remove battery conversion step (#1652)

* refactor: remove battery conversion step

* also fix a bug with margins in battery

* fixes
This commit is contained in:
Clement Tsang 2024-12-22 22:54:19 -05:00 committed by GitHub
parent 4a4d53dafb
commit cd6c60c054
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 154 additions and 159 deletions

View File

@ -124,7 +124,7 @@ pub struct DataCollection {
pub io_labels: Vec<(String, String)>,
pub temp_harvest: Vec<temperature::TempHarvest>,
#[cfg(feature = "battery")]
pub battery_harvest: Vec<batteries::BatteryHarvest>,
pub battery_harvest: Vec<batteries::BatteryData>,
#[cfg(feature = "zfs")]
pub arc_harvest: memory::MemHarvest,
#[cfg(feature = "gpu")]
@ -451,7 +451,7 @@ impl DataCollection {
}
#[cfg(feature = "battery")]
fn eat_battery(&mut self, list_of_batteries: Vec<batteries::BatteryHarvest>) {
fn eat_battery(&mut self, list_of_batteries: Vec<batteries::BatteryData>) {
self.battery_harvest = list_of_batteries;
}

View File

@ -21,7 +21,7 @@ pub struct AppWidgetStates {
pub proc_state: ProcState,
pub temp_state: TempState,
pub disk_state: DiskState,
pub battery_state: BatteryState,
pub battery_state: AppBatteryState,
pub basic_table_widget_state: Option<BasicTableWidgetState>,
}
@ -381,13 +381,13 @@ pub struct BasicTableWidgetState {
pub right_brc: Option<(u16, u16)>,
}
pub struct BatteryState {
pub struct AppBatteryState {
pub widget_states: HashMap<u64, BatteryWidgetState>,
}
impl BatteryState {
impl AppBatteryState {
pub fn init(widget_states: HashMap<u64, BatteryWidgetState>) -> Self {
BatteryState { widget_states }
AppBatteryState { widget_states }
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut BatteryWidgetState> {

View File

@ -133,11 +133,10 @@ where
&mut self, f: &mut Frame<'_>, draw_info: &DrawInfo, widget: Option<&mut BottomWidget>,
painter: &Painter,
) {
let draw_horizontal = !self.props.is_basic || draw_info.is_on_widget();
let draw_loc = draw_info.loc;
let margined_draw_loc = Layout::default()
.constraints([Constraint::Percentage(100)])
.horizontal_margin(u16::from(!draw_horizontal))
.horizontal_margin(u16::from(self.props.is_basic && !draw_info.is_on_widget()))
.direction(Direction::Horizontal)
.split(draw_loc)[0];

View File

@ -13,7 +13,7 @@ use crate::{
Painter,
},
constants::*,
data_conversion::BatteryDuration,
data_collection::batteries::BatteryState,
};
impl Painter {
@ -27,8 +27,8 @@ impl Painter {
.widget_states
.get_mut(&widget_id)
{
let is_on_widget = widget_id == app_state.current_widget.widget_id;
let border_style = if is_on_widget {
let is_selected = widget_id == app_state.current_widget.widget_id;
let border_style = if is_selected {
self.styles.highlighted_border_style
} else {
self.styles.border_style
@ -42,7 +42,7 @@ impl Painter {
let block = {
let mut block = widget_block(
app_state.app_config_fields.use_basic_mode,
is_on_widget,
is_selected,
self.styles.border_type,
)
.border_style(border_style)
@ -113,7 +113,7 @@ impl Painter {
let margined_draw_loc = Layout::default()
.constraints([Constraint::Percentage(100)])
.horizontal_margin(u16::from(!(is_on_widget || is_basic)))
.horizontal_margin(u16::from(is_basic && !is_selected))
.direction(Direction::Horizontal)
.split(draw_loc)[0];
@ -124,13 +124,14 @@ impl Painter {
{
let full_width = draw_loc.width.saturating_sub(2);
let bar_length = usize::from(full_width.saturating_sub(6));
let charge_percentage = battery_details.charge_percentage;
let num_bars = calculate_basic_use_bars(charge_percentage, bar_length);
let charge_percent = battery_details.charge_percent;
let num_bars = calculate_basic_use_bars(charge_percent, bar_length);
let bars = format!(
"[{}{}{:3.0}%]",
"|".repeat(num_bars),
" ".repeat(bar_length - num_bars),
charge_percentage,
charge_percent,
);
let mut battery_charge_rows = Vec::with_capacity(2);
@ -138,9 +139,9 @@ impl Painter {
Cell::from("Charge").style(self.styles.text_style)
]));
battery_charge_rows.push(Row::new([Cell::from(bars).style(
if charge_percentage < 10.0 {
if charge_percent < 10.0 {
self.styles.low_battery
} else if charge_percentage < 50.0 {
} else if charge_percent < 50.0 {
self.styles.medium_battery
} else {
self.styles.high_battery
@ -148,31 +149,25 @@ impl Painter {
)]));
let mut battery_rows = Vec::with_capacity(3);
let watt_consumption = battery_details.watt_consumption();
let health = battery_details.health();
battery_rows.push(Row::new([""]).bottom_margin(table_gap + 1));
battery_rows.push(
Row::new(["Rate", &battery_details.watt_consumption])
.style(self.styles.text_style),
);
battery_rows
.push(Row::new(["Rate", &watt_consumption]).style(self.styles.text_style));
battery_rows.push(
Row::new(["State", &battery_details.state]).style(self.styles.text_style),
Row::new(["State", battery_details.state.as_str()])
.style(self.styles.text_style),
);
let mut time: String; // Keep string lifetime in scope.
{
let style = self.styles.text_style;
match &battery_details.battery_duration {
BatteryDuration::ToEmpty(secs) => {
time = long_time(*secs);
if full_width as usize > time.len() {
battery_rows.push(Row::new(["Time to empty", &time]).style(style));
} else {
time = short_time(*secs);
battery_rows.push(Row::new(["To empty", &time]).style(style));
}
}
BatteryDuration::ToFull(secs) => {
match &battery_details.state {
BatteryState::Charging {
time_to_full: Some(secs),
} => {
time = long_time(*secs);
if full_width as usize > time.len() {
@ -182,15 +177,23 @@ impl Painter {
battery_rows.push(Row::new(["To full", &time]).style(style));
}
}
BatteryDuration::Empty
| BatteryDuration::Full
| BatteryDuration::Unknown => {}
BatteryState::Discharging {
time_to_empty: Some(secs),
} => {
time = long_time(*secs);
if full_width as usize > time.len() {
battery_rows.push(Row::new(["Time to empty", &time]).style(style));
} else {
time = short_time(*secs);
battery_rows.push(Row::new(["To empty", &time]).style(style));
}
}
_ => {}
}
}
battery_rows.push(
Row::new(["Health", &battery_details.health]).style(self.styles.text_style),
);
battery_rows.push(Row::new(["Health", &health]).style(self.styles.text_style));
let header = if app_state.converted_data.battery_data.len() > 1 {
Row::new([""]).bottom_margin(table_gap)
@ -241,7 +244,7 @@ impl Painter {
}
}
fn get_hms(secs: i64) -> (i64, i64, i64) {
fn get_hms(secs: u32) -> (u32, u32, u32) {
let hours = secs / (60 * 60);
let minutes = (secs / 60) - hours * 60;
let seconds = secs - minutes * 60 - hours * 60 * 60;
@ -249,7 +252,7 @@ fn get_hms(secs: i64) -> (i64, i64, i64) {
(hours, minutes, seconds)
}
fn long_time(secs: i64) -> String {
fn long_time(secs: u32) -> String {
let (hours, minutes, seconds) = get_hms(secs);
if hours > 0 {
@ -266,7 +269,7 @@ fn long_time(secs: i64) -> String {
}
}
fn short_time(secs: i64) -> String {
fn short_time(secs: u32) -> String {
let (hours, minutes, seconds) = get_hms(secs);
if hours > 0 {

View File

@ -6,9 +6,7 @@ pub mod nvidia;
#[cfg(all(target_os = "linux", feature = "gpu"))]
pub mod amd;
#[cfg(feature = "battery")]
pub mod batteries;
pub mod cpu;
pub mod disks;
pub mod error;
@ -45,7 +43,7 @@ pub struct Data {
pub disks: Option<Vec<disks::DiskHarvest>>,
pub io: Option<disks::IoHarvest>,
#[cfg(feature = "battery")]
pub list_of_batteries: Option<Vec<batteries::BatteryHarvest>>,
pub list_of_batteries: Option<Vec<batteries::BatteryData>>,
#[cfg(feature = "zfs")]
pub arc: Option<memory::MemHarvest>,
#[cfg(feature = "gpu")]

View File

@ -1,11 +1,104 @@
//! Data collection for batteries.
//! Uses the battery crate.
//!
//! For Linux, macOS, Windows, FreeBSD, Dragonfly, and iOS, this is handled by
//! the battery crate.
//! Covers battery usage for:
//! - Linux 2.6.39+
//! - MacOS 10.10+
//! - iOS
//! - Windows 7+
//! - FreeBSD
//! - DragonFlyBSD
//!
//! For more information, refer to the [starship_battery](https://github.com/starship/rust-battery) repo/docs.
cfg_if::cfg_if! {
if #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "ios"))] {
pub mod battery;
pub use self::battery::*;
#[cfg(feature = "battery")]
use starship_battery::{
units::{power::watt, ratio::percent, time::second},
Battery, Manager, State,
};
/// Battery state.
#[derive(Debug, Default, Clone)]
pub enum BatteryState {
Charging {
/// Time to full in seconds.
time_to_full: Option<u32>,
},
Discharging {
/// Time to empty in seconds.
time_to_empty: Option<u32>,
},
Empty,
Full,
#[default]
Unknown,
}
impl BatteryState {
/// Return the string representation.
pub fn as_str(&self) -> &'static str {
match self {
BatteryState::Charging { .. } => "Charging",
BatteryState::Discharging { .. } => "Discharging",
BatteryState::Empty => "Empty",
BatteryState::Full => "Full",
BatteryState::Unknown => "Unknown",
}
}
}
#[derive(Debug, Clone)]
pub struct BatteryData {
/// Current charge percent.
pub charge_percent: f64,
/// Power consumption, in watts.
pub power_consumption: f64,
/// Reported battery health.
pub health_percent: f64,
/// The current battery "state" (e.g. is it full, charging, etc.).
pub state: BatteryState,
}
impl BatteryData {
pub fn watt_consumption(&self) -> String {
format!("{:.2}W", self.power_consumption)
}
pub fn health(&self) -> String {
format!("{:.2}%", self.health_percent)
}
}
#[cfg(feature = "battery")]
pub fn refresh_batteries(manager: &Manager, batteries: &mut [Battery]) -> Vec<BatteryData> {
batteries
.iter_mut()
.filter_map(|battery| {
if manager.refresh(battery).is_ok() {
Some(BatteryData {
charge_percent: f64::from(battery.state_of_charge().get::<percent>()),
power_consumption: f64::from(battery.energy_rate().get::<watt>()),
health_percent: f64::from(battery.state_of_health().get::<percent>()),
state: match battery.state() {
State::Unknown => BatteryState::Unknown,
State::Charging => BatteryState::Charging {
time_to_full: {
let optional_time = battery.time_to_full();
optional_time.map(|time| f64::from(time.get::<second>()) as u32)
},
},
State::Discharging => BatteryState::Discharging {
time_to_empty: {
let optional_time = battery.time_to_empty();
optional_time.map(|time| f64::from(time.get::<second>()) as u32)
},
},
State::Empty => BatteryState::Empty,
State::Full => BatteryState::Full,
},
})
} else {
None
}
})
.collect::<Vec<_>>()
}

View File

@ -1,51 +0,0 @@
//! Uses the battery crate from svartalf.
//! Covers battery usage for:
//! - Linux 2.6.39+
//! - MacOS 10.10+
//! - iOS
//! - Windows 7+
//! - FreeBSD
//! - DragonFlyBSD
//!
//! For more information, refer to the [starship_battery](https://github.com/starship/rust-battery) repo/docs.
use starship_battery::{
units::{power::watt, ratio::percent, time::second},
Battery, Manager, State,
};
#[derive(Debug, Clone)]
pub struct BatteryHarvest {
pub charge_percent: f64,
pub secs_until_full: Option<i64>,
pub secs_until_empty: Option<i64>,
pub power_consumption_rate_watts: f64,
pub health_percent: f64,
pub state: State,
}
pub fn refresh_batteries(manager: &Manager, batteries: &mut [Battery]) -> Vec<BatteryHarvest> {
batteries
.iter_mut()
.filter_map(|battery| {
if manager.refresh(battery).is_ok() {
Some(BatteryHarvest {
secs_until_full: {
let optional_time = battery.time_to_full();
optional_time.map(|time| f64::from(time.get::<second>()) as i64)
},
secs_until_empty: {
let optional_time = battery.time_to_empty();
optional_time.map(|time| f64::from(time.get::<second>()) as i64)
},
charge_percent: f64::from(battery.state_of_charge().get::<percent>()),
power_consumption_rate_watts: f64::from(battery.energy_rate().get::<watt>()),
health_percent: f64::from(battery.state_of_health().get::<percent>()),
state: battery.state(),
})
} else {
None
}
})
.collect::<Vec<_>>()
}

View File

@ -8,30 +8,13 @@ use std::borrow::Cow;
use crate::{
app::{data_farmer::DataCollection, AxisScaling},
canvas::components::time_chart::Point,
data_collection::{cpu::CpuDataType, memory::MemHarvest, temperature::TemperatureType},
data_collection::{
batteries::BatteryData, cpu::CpuDataType, memory::MemHarvest, temperature::TemperatureType,
},
utils::{data_prefixes::*, data_units::DataUnit},
widgets::{DiskWidgetData, TempWidgetData},
};
#[derive(Debug, Default)]
pub enum BatteryDuration {
ToEmpty(i64),
ToFull(i64),
Empty,
Full,
#[default]
Unknown,
}
#[derive(Default, Debug)]
pub struct ConvertedBatteryData {
pub charge_percentage: f64,
pub watt_consumption: String,
pub battery_duration: BatteryDuration,
pub health: String,
pub state: String,
}
#[derive(Default, Debug)]
pub struct ConvertedNetworkData {
pub rx: Vec<Point>,
@ -90,7 +73,8 @@ pub struct ConvertedData {
pub load_avg_data: [f32; 3],
pub cpu_data: Vec<CpuWidgetData>,
pub battery_data: Vec<ConvertedBatteryData>,
pub battery_data: Vec<BatteryData>,
pub disk_data: Vec<DiskWidgetData>,
pub temp_data: Vec<TempWidgetData>,
}
@ -508,37 +492,6 @@ pub fn dec_bytes_string(value: u64) -> String {
}
}
#[cfg(feature = "battery")]
pub fn convert_battery_harvest(current_data: &DataCollection) -> Vec<ConvertedBatteryData> {
current_data
.battery_harvest
.iter()
.map(|battery_harvest| ConvertedBatteryData {
charge_percentage: battery_harvest.charge_percent,
watt_consumption: format!("{:.2}W", battery_harvest.power_consumption_rate_watts),
battery_duration: if let Some(secs) = battery_harvest.secs_until_empty {
BatteryDuration::ToEmpty(secs)
} else if let Some(secs) = battery_harvest.secs_until_full {
BatteryDuration::ToFull(secs)
} else {
match battery_harvest.state {
starship_battery::State::Empty => BatteryDuration::Empty,
starship_battery::State::Full => BatteryDuration::Full,
_ => BatteryDuration::Unknown,
}
},
health: format!("{:.2}%", battery_harvest.health_percent),
state: {
let mut s = battery_harvest.state.to_string();
if !s.is_empty() {
s[0..1].make_ascii_uppercase();
}
s
},
})
.collect()
}
#[cfg(feature = "zfs")]
pub fn convert_arc_data_points(current_data: &DataCollection) -> Vec<Point> {
let mut result: Vec<Point> = Vec::new();

View File

@ -513,7 +513,7 @@ pub fn start_bottom() -> anyhow::Result<()> {
{
if app.used_widgets.use_battery {
app.converted_data.battery_data =
convert_battery_harvest(&app.data_collection);
app.data_collection.battery_harvest.clone();
}
}

View File

@ -493,7 +493,7 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
proc_state: ProcState::init(proc_state_map),
temp_state: TempState::init(temp_state_map),
disk_state: DiskState::init(disk_state_map),
battery_state: BatteryState::init(battery_state_map),
battery_state: AppBatteryState::init(battery_state_map),
basic_table_widget_state,
};