From f0865e3b10e75c92e96d8e79b52f6ad22c8a8514 Mon Sep 17 00:00:00 2001 From: obrusvit Date: Tue, 3 Jun 2025 10:48:18 +0200 Subject: [PATCH] feat(eckhart): fuel gauge UI - fuel gauge (battery state) with icons for charging/discharging state and soc percentage - on attach on Homescreen ActionBar - permanently on the first DeviceMenu subscreen - temporarily in the Header on charging state update [no changelog] --- core/Makefile | 2 +- .../embed/rust/src/trezorhal/power_manager.rs | 1 + core/embed/rust/src/ui/component/base.rs | 2 +- .../src/ui/layout_eckhart/component/button.rs | 24 +- .../ui/layout_eckhart/firmware/action_bar.rs | 15 ++ .../firmware/device_menu_screen.rs | 27 +-- .../ui/layout_eckhart/firmware/fuel_gauge.rs | 220 ++++++++++++++++++ .../src/ui/layout_eckhart/firmware/header.rs | 52 +++-- .../ui/layout_eckhart/firmware/homescreen.rs | 66 ++++-- .../src/ui/layout_eckhart/firmware/mod.rs | 2 + .../ui/layout_eckhart/res/battery/empty.png | Bin 0 -> 341 bytes .../ui/layout_eckhart/res/battery/empty.toif | Bin 0 -> 90 bytes .../ui/layout_eckhart/res/battery/full.png | Bin 0 -> 280 bytes .../ui/layout_eckhart/res/battery/full.toif | Bin 0 -> 98 bytes .../src/ui/layout_eckhart/res/battery/low.png | Bin 0 -> 271 bytes .../ui/layout_eckhart/res/battery/low.toif | Bin 0 -> 98 bytes .../src/ui/layout_eckhart/res/battery/mid.png | Bin 0 -> 283 bytes .../ui/layout_eckhart/res/battery/mid.toif | Bin 0 -> 103 bytes .../src/ui/layout_eckhart/res/battery/zap.png | Bin 0 -> 243 bytes .../ui/layout_eckhart/res/battery/zap.toif | Bin 0 -> 103 bytes .../src/ui/layout_eckhart/res/battery_bar.png | Bin 154 -> 0 bytes .../ui/layout_eckhart/res/battery_bar.toif | Bin 25 -> 0 bytes .../src/ui/layout_eckhart/res/battery_zap.png | Bin 236 -> 0 bytes .../ui/layout_eckhart/res/battery_zap.toif | Bin 97 -> 0 bytes .../src/ui/layout_eckhart/theme/firmware.rs | 2 + .../rust/src/ui/layout_eckhart/theme/mod.rs | 7 +- 26 files changed, 363 insertions(+), 57 deletions(-) create mode 100644 core/embed/rust/src/ui/layout_eckhart/firmware/fuel_gauge.rs create mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery/empty.png create mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery/empty.toif create mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery/full.png create mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery/full.toif create mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery/low.png create mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery/low.toif create mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery/mid.png create mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery/mid.toif create mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery/zap.png create mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery/zap.toif delete mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery_bar.png delete mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery_bar.toif delete mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery_zap.png delete mode 100644 core/embed/rust/src/ui/layout_eckhart/res/battery_zap.toif diff --git a/core/Makefile b/core/Makefile index 2545d3e7ba..2ce733d985 100644 --- a/core/Makefile +++ b/core/Makefile @@ -179,7 +179,7 @@ test: ## run unit tests test_rust: ## run rs unit tests export BUILD_DIR=$(abspath $(UNIX_BUILD_DIR)) ; \ cd embed/rust ; cargo test $(TESTOPTS) --target=$(RUST_TARGET) \ - --no-default-features --features $(LAYOUT_FEATURE),test \ + --no-default-features --features $(LAYOUT_FEATURE),power_manager,test \ -- --test-threads=1 --nocapture test_emu: ## run selected device tests from python-trezor diff --git a/core/embed/rust/src/trezorhal/power_manager.rs b/core/embed/rust/src/trezorhal/power_manager.rs index 8b8b0b8145..eba7c4b2e8 100644 --- a/core/embed/rust/src/trezorhal/power_manager.rs +++ b/core/embed/rust/src/trezorhal/power_manager.rs @@ -3,6 +3,7 @@ use super::ffi; #[cfg(feature = "ui")] use crate::ui::event::PMEvent; +#[derive(PartialEq, Eq, Copy, Clone)] pub enum ChargingState { Discharging, Charging, diff --git a/core/embed/rust/src/ui/component/base.rs b/core/embed/rust/src/ui/component/base.rs index da13168ec5..ce8393d09a 100644 --- a/core/embed/rust/src/ui/component/base.rs +++ b/core/embed/rust/src/ui/component/base.rs @@ -424,7 +424,7 @@ impl Timer { self.token().0 == Timer::INVALID_TOKEN_VALUE } - const fn is_running(&self) -> bool { + pub const fn is_running(&self) -> bool { self.0 & Timer::IS_RUNNING_BITMASK != 0 } diff --git a/core/embed/rust/src/ui/layout_eckhart/component/button.rs b/core/embed/rust/src/ui/layout_eckhart/component/button.rs index e73b3e3842..eb3e401fd5 100644 --- a/core/embed/rust/src/ui/layout_eckhart/component/button.rs +++ b/core/embed/rust/src/ui/layout_eckhart/component/button.rs @@ -15,11 +15,11 @@ use crate::{ }, }; +use super::super::theme; + #[cfg(feature = "bootloader")] use super::super::fonts; -use super::super::theme; - pub enum ButtonMsg { Pressed, Released, @@ -236,9 +236,7 @@ impl Button { } pub fn set_content(&mut self, content: ButtonContent) { - if self.content != content { - self.content = content - } + self.content = content } pub fn set_expanded_touch_area(&mut self, expand: Insets) { @@ -253,6 +251,10 @@ impl Button { &self.content } + pub fn content_mut(&mut self) -> &mut ButtonContent { + &mut self.content + } + pub fn content_offset(&self) -> Offset { self.content_offset } @@ -301,7 +303,7 @@ impl Button { text.map(|t| self.text_height(t, false, width) + self.baseline_subtext_height()) } #[cfg(feature = "micropython")] - ButtonContent::HomeBar(_) => theme::ACTION_BAR_HEIGHT, + ButtonContent::HomeBar(..) => theme::ACTION_BAR_HEIGHT, } } @@ -407,7 +409,7 @@ impl Button { } fn render_content<'s>( - &self, + &'s self, target: &mut impl Renderer<'s>, stylesheet: &ButtonStyle, alpha: u8, @@ -558,7 +560,7 @@ impl Button { } } - pub fn render_with_alpha<'s>(&self, target: &mut impl Renderer<'s>, alpha: u8) { + pub fn render_with_alpha<'s>(&'s self, target: &mut impl Renderer<'s>, alpha: u8) { let style = self.style(); self.render_background(target, style, alpha); self.render_content(target, style, alpha); @@ -690,7 +692,9 @@ impl crate::trace::Trace for Button { t.string("text", *text); } #[cfg(feature = "micropython")] - ButtonContent::HomeBar(text) => t.string("text", text.unwrap_or(TString::empty())), + ButtonContent::HomeBar(text) => { + t.string("text", text.unwrap_or(TString::empty())); + } } } } @@ -711,7 +715,7 @@ impl State { } } -#[derive(PartialEq, Eq, Clone)] +#[derive(Clone)] pub enum ButtonContent { Empty, Text { diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/action_bar.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/action_bar.rs index 259d2be092..a78aa11ef9 100644 --- a/core/embed/rust/src/ui/layout_eckhart/firmware/action_bar.rs +++ b/core/embed/rust/src/ui/layout_eckhart/firmware/action_bar.rs @@ -177,6 +177,21 @@ impl ActionBar { } } + pub fn left_button(&self) -> Option<&Button> { + self.left_button.as_ref() + } + + pub fn left_button_mut(&mut self) -> Option<&mut Button> { + self.left_button.as_mut() + } + pub fn right_button(&self) -> Option<&Button> { + self.right_button.as_ref() + } + + pub fn right_button_mut(&mut self) -> Option<&mut Button> { + self.right_button.as_mut() + } + fn new( mode: Mode, left_button: Option