battery module test
This commit is contained in:
@@ -35,6 +35,7 @@ fn bar_view(bar: &Bar) -> Element<'_, Message> {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<Element<Message>>>())
|
.collect::<Vec<Element<Message>>>())
|
||||||
.spacing(bar.spacing)
|
.spacing(bar.spacing)
|
||||||
|
.width(Length::Shrink)
|
||||||
.align_y(Alignment::Center);
|
.align_y(Alignment::Center);
|
||||||
|
|
||||||
let middle = row(bar
|
let middle = row(bar
|
||||||
@@ -50,6 +51,7 @@ fn bar_view(bar: &Bar) -> Element<'_, Message> {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<Element<Message>>>())
|
.collect::<Vec<Element<Message>>>())
|
||||||
.spacing(bar.spacing)
|
.spacing(bar.spacing)
|
||||||
|
.width(Length::Shrink)
|
||||||
.align_y(Alignment::Center);
|
.align_y(Alignment::Center);
|
||||||
let right = row(bar
|
let right = row(bar
|
||||||
.order
|
.order
|
||||||
@@ -64,6 +66,7 @@ fn bar_view(bar: &Bar) -> Element<'_, Message> {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<Element<Message>>>())
|
.collect::<Vec<Element<Message>>>())
|
||||||
.spacing(bar.spacing)
|
.spacing(bar.spacing)
|
||||||
|
.width(Length::Shrink)
|
||||||
.align_y(Alignment::Center);
|
.align_y(Alignment::Center);
|
||||||
|
|
||||||
let row = row![
|
let row = row![
|
||||||
|
|||||||
@@ -1,17 +1,69 @@
|
|||||||
//! Battery module: prints the charge percentage from the battery service.
|
//! Battery module: Android-style battery icon fed by the battery service.
|
||||||
|
|
||||||
use iced::widget::text;
|
use iced::widget::{container, row, text};
|
||||||
use iced::{Element, Task};
|
use iced::{Border, Color, Element, Length, Task, Theme};
|
||||||
|
|
||||||
use common::{BarModule, BatteryEvent, BatteryMsg, ModuleEffect, Service, Wire};
|
use common::{BarModule, BatteryEvent, BatteryMsg, BatteryStatus, ModuleEffect, Service, Wire};
|
||||||
|
|
||||||
|
/// Icon shell size (logical px); fill scales inside it.
|
||||||
|
const SHELL_W: f32 = 28.0;
|
||||||
|
const SHELL_H: f32 = 14.0;
|
||||||
|
const BORDER_W: f32 = 1.5;
|
||||||
|
const PAD: f32 = 2.0;
|
||||||
|
|
||||||
pub struct Battery {
|
pub struct Battery {
|
||||||
percent: Option<i32>,
|
percent: Option<i32>,
|
||||||
|
status: BatteryStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Battery {
|
impl Battery {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { percent: None }
|
Self {
|
||||||
|
percent: None,
|
||||||
|
status: BatteryStatus::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fill width for the level, leaving a sliver visible below 100%.
|
||||||
|
fn fill_w(&self) -> f32 {
|
||||||
|
match self.percent {
|
||||||
|
Some(p) => ((SHELL_W - 2.0 * (BORDER_W + PAD)) * p as f32 / 100.0)
|
||||||
|
.clamp(0.0, SHELL_W)
|
||||||
|
.max(if p > 0 { 2.0 } else { 0.0 }),
|
||||||
|
None => 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Icon ink: green while charging, white otherwise.
|
||||||
|
fn ink(status: BatteryStatus) -> Color {
|
||||||
|
match status {
|
||||||
|
BatteryStatus::Charging => Color::from_rgb8(0x76, 0xFF, 0x03),
|
||||||
|
_ => Color::WHITE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transparent shell with a rounded outline tinted by charge state.
|
||||||
|
fn shell_style(status: BatteryStatus) -> impl Fn(&Theme) -> container::Style {
|
||||||
|
move |_theme: &Theme| container::Style {
|
||||||
|
border: Border {
|
||||||
|
color: ink(status),
|
||||||
|
width: BORDER_W,
|
||||||
|
radius: 4.0.into(),
|
||||||
|
},
|
||||||
|
..container::Style::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Solid fill (and nub cap) tinted by charge state.
|
||||||
|
fn solid_style(status: BatteryStatus) -> impl Fn(&Theme) -> container::Style {
|
||||||
|
move |_theme: &Theme| container::Style {
|
||||||
|
background: Some(ink(status).into()),
|
||||||
|
border: Border {
|
||||||
|
radius: 2.0.into(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..container::Style::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,16 +73,37 @@ impl BarModule for Battery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self, _window_id: Option<iced::window::Id>) -> Element<'_, Wire> {
|
fn view(&self, _window_id: Option<iced::window::Id>) -> Element<'_, Wire> {
|
||||||
match self.percent {
|
let status = self.status;
|
||||||
Some(percent) => text(format!("{percent}%")).into(),
|
let icon = row![
|
||||||
None => text("--").into(),
|
container(
|
||||||
}
|
container(text(""))
|
||||||
|
.width(Length::Fixed(self.fill_w()))
|
||||||
|
.height(Length::Fill)
|
||||||
|
.style(solid_style(status)),
|
||||||
|
)
|
||||||
|
.width(Length::Fixed(SHELL_W))
|
||||||
|
.height(Length::Fixed(SHELL_H))
|
||||||
|
.padding(PAD)
|
||||||
|
.style(shell_style(status)),
|
||||||
|
// Nub cap on the right edge.
|
||||||
|
container(text(""))
|
||||||
|
.width(Length::Fixed(2.5))
|
||||||
|
.height(Length::Fixed(6.0))
|
||||||
|
.style(solid_style(status)),
|
||||||
|
]
|
||||||
|
.spacing(2)
|
||||||
|
.align_y(iced::Alignment::Center);
|
||||||
|
row![icon]
|
||||||
|
.spacing(6)
|
||||||
|
.align_y(iced::Alignment::Center)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Wire) -> Task<ModuleEffect> {
|
fn update(&mut self, msg: Wire) -> Task<ModuleEffect> {
|
||||||
if let Some(BatteryEvent::PercentageChanged(percent)) = msg.downcast::<BatteryEvent>()
|
match msg.downcast::<BatteryEvent>() {
|
||||||
{
|
Some(BatteryEvent::PercentageChanged(percent)) => self.percent = Some(*percent),
|
||||||
self.percent = Some(*percent);
|
Some(BatteryEvent::StatusChanged(status)) => self.status = *status,
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user