From 676a7f8b0c634f2ac5a6173e7178567a1f3b6beb Mon Sep 17 00:00:00 2001 From: JustScott Date: Thu, 3 Oct 2024 15:51:00 -0500 Subject: [PATCH 1/5] Improved the Terminal Watchfaces UI + Reorder code to match the widgets order in the UI. + Moved all objects (rows) into a container + Use InfintimeTheme Colors instead of hardcoded hex values + Added a new InfinitimeTheme color: gray, using it to turn certain values gray when they contain no data + Implement @vkareh's [variable battery icon](https://github.com/InfiniTimeOrg/InfiniTime/pull/1964) color to the battery percentage text. + Replaced the 'You have mail.' notification message with the message '[1]+ Notify' to better fit the terminal lore. --- src/displayapp/InfiniTimeTheme.h | 1 + src/displayapp/screens/WatchFaceTerminal.cpp | 146 ++++++++++--------- src/displayapp/screens/WatchFaceTerminal.h | 11 +- 3 files changed, 88 insertions(+), 70 deletions(-) diff --git a/src/displayapp/InfiniTimeTheme.h b/src/displayapp/InfiniTimeTheme.h index 0690b09912..57680e8738 100644 --- a/src/displayapp/InfiniTimeTheme.h +++ b/src/displayapp/InfiniTimeTheme.h @@ -8,6 +8,7 @@ namespace Colors { static constexpr lv_color_t green = LV_COLOR_MAKE(0x0, 0xb0, 0x0); static constexpr lv_color_t blue = LV_COLOR_MAKE(0x0, 0x50, 0xff); static constexpr lv_color_t lightGray = LV_COLOR_MAKE(0xb0, 0xb0, 0xb0); + static constexpr lv_color_t gray = LV_COLOR_MAKE(0x50, 0x50, 0x50); static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e); static constexpr lv_color_t bgAlt = LV_COLOR_MAKE(0x38, 0x38, 0x38); diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index 87aa91eaf3..4442b29c6f 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -1,8 +1,6 @@ #include #include "displayapp/screens/WatchFaceTerminal.h" #include "displayapp/screens/BatteryIcon.h" -#include "displayapp/screens/NotificationIcon.h" -#include "displayapp/screens/Symbols.h" #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" #include "components/ble/NotificationManager.h" @@ -11,6 +9,7 @@ #include "components/settings/Settings.h" #include "components/ble/SimpleWeatherService.h" #include "displayapp/screens/WeatherSymbols.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -31,44 +30,46 @@ WatchFaceTerminal::WatchFaceTerminal(Controllers::DateTime& dateTimeController, heartRateController {heartRateController}, motionController {motionController}, weatherService {weatherService} { - batteryValue = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_recolor(batteryValue, true); - lv_obj_align(batteryValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20); - - connectState = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_recolor(connectState, true); - lv_obj_align(connectState, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 60); - notificationIcon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_LEFT_MID, 0, -100); + container = lv_cont_create(lv_scr_act(), nullptr); + lv_cont_set_layout(container, LV_LAYOUT_COLUMN_LEFT); + lv_cont_set_fit(container, LV_FIT_TIGHT); + lv_obj_set_style_local_pad_inner(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, -3); + lv_obj_set_style_local_bg_opa(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - label_date = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_recolor(label_date, true); - lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -40); + notificationIcon = lv_label_create(container, nullptr); - label_prompt_1 = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(label_prompt_1, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -80); + label_prompt_1 = lv_label_create(container, nullptr); + lv_obj_set_style_local_text_color(label_prompt_1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); lv_label_set_text_static(label_prompt_1, "user@watch:~ $ now"); - label_prompt_2 = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 80); - lv_label_set_text_static(label_prompt_2, "user@watch:~ $"); - - label_time = lv_label_create(lv_scr_act(), nullptr); + label_time = lv_label_create(container, nullptr); lv_label_set_recolor(label_time, true); - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -60); - heartbeatValue = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_recolor(heartbeatValue, true); - lv_obj_align(heartbeatValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 20); + label_date = lv_label_create(container, nullptr); + lv_label_set_recolor(label_date, true); - stepValue = lv_label_create(lv_scr_act(), nullptr); + batteryValue = lv_label_create(container, nullptr); + lv_label_set_recolor(batteryValue, true); + + stepValue = lv_label_create(container, nullptr); lv_label_set_recolor(stepValue, true); - lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0); + lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange); + + heartbeatValue = lv_label_create(container, nullptr); + lv_label_set_recolor(heartbeatValue, true); - weather = lv_label_create(lv_scr_act(), nullptr); + weather = lv_label_create(container, nullptr); lv_label_set_recolor(weather, true); - lv_obj_align(weather, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40); + + connectState = lv_label_create(container, nullptr); + lv_label_set_recolor(connectState, true); + + label_prompt_2 = lv_label_create(container, nullptr); + lv_obj_set_style_local_text_color(label_prompt_2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + lv_label_set_text_static(label_prompt_2, "user@watch:~ $"); + + lv_obj_align(container, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 7); taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); Refresh(); @@ -80,33 +81,10 @@ WatchFaceTerminal::~WatchFaceTerminal() { } void WatchFaceTerminal::Refresh() { - powerPresent = batteryController.IsPowerPresent(); - batteryPercentRemaining = batteryController.PercentRemaining(); - if (batteryPercentRemaining.IsUpdated() || powerPresent.IsUpdated()) { - lv_label_set_text_fmt(batteryValue, "[BATT]#387b54 %d%%", batteryPercentRemaining.Get()); - if (batteryController.IsPowerPresent()) { - lv_label_ins_text(batteryValue, LV_LABEL_POS_LAST, " Charging"); - } - } - - bleState = bleController.IsConnected(); - bleRadioEnabled = bleController.IsRadioEnabled(); - if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { - if (!bleRadioEnabled.Get()) { - lv_label_set_text_static(connectState, "[STAT]#0082fc Disabled#"); - } else { - if (bleState.Get()) { - lv_label_set_text_static(connectState, "[STAT]#0082fc Connected#"); - } else { - lv_label_set_text_static(connectState, "[STAT]#0082fc Disconnected#"); - } - } - } - notificationState = notificationManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { if (notificationState.Get()) { - lv_label_set_text_static(notificationIcon, "You have mail."); + lv_label_set_text_static(notificationIcon, "[1]+ Notify"); } else { lv_label_set_text_static(notificationIcon, ""); } @@ -128,9 +106,9 @@ void WatchFaceTerminal::Refresh() { hour = hour - 12; ampmChar[0] = 'P'; } - lv_label_set_text_fmt(label_time, "[TIME]#11cc55 %02d:%02d:%02d %s#", hour, minute, second, ampmChar); + lv_label_set_text_fmt(label_time, "#ffffff [TIME]# #11cc55 %02d:%02d:%02d %s#", hour, minute, second, ampmChar); } else { - lv_label_set_text_fmt(label_time, "[TIME]#11cc55 %02d:%02d:%02d", hour, minute, second); + lv_label_set_text_fmt(label_time, "#ffffff [TIME]# #11cc55 %02d:%02d:%02d#", hour, minute, second); } currentDate = std::chrono::time_point_cast(currentDateTime.Get()); @@ -138,25 +116,42 @@ void WatchFaceTerminal::Refresh() { uint16_t year = dateTimeController.Year(); Controllers::DateTime::Months month = dateTimeController.Month(); uint8_t day = dateTimeController.Day(); - lv_label_set_text_fmt(label_date, "[DATE]#007fff %04d-%02d-%02d#", short(year), char(month), char(day)); + lv_label_set_text_fmt(label_date, "#ffffff [DATE]# #007fff %04d-%02d-%02d#", short(year), char(month), char(day)); } } + powerPresent = batteryController.IsPowerPresent(); + batteryPercentRemaining = batteryController.PercentRemaining(); + if (batteryPercentRemaining.IsUpdated() || powerPresent.IsUpdated()) { + // HSV color model has red at 0° and green at 120°. + // We lock satuation and brightness at 100% and traverse the cilinder + // between red and green, thus avoiding the darker RGB on medium battery + // charges and giving us a much nicer color range. + uint8_t hue = batteryPercentRemaining.Get() * 120 / 100; + lv_obj_set_style_local_text_color(batteryValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(hue, 100, 100)); + lv_label_set_text_fmt(batteryValue, "#ffffff [BATT]# %d%%", batteryPercentRemaining.Get()); + if (batteryController.IsCharging()) { + lv_label_ins_text(batteryValue, LV_LABEL_POS_LAST, " Charging"); + } + } + + stepCount = motionController.NbSteps(); + if (stepCount.IsUpdated()) { + lv_label_set_text_fmt(stepValue, "#ffffff [STEP]# %lu steps", stepCount.Get()); + } + heartbeat = heartRateController.HeartRate(); heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) { if (heartbeatRunning.Get()) { - lv_label_set_text_fmt(heartbeatValue, "[L_HR]#ee3311 %d bpm#", heartbeat.Get()); + lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::deepOrange); + lv_label_set_text_fmt(heartbeatValue, "#ffffff [L_HR]# %d bpm", heartbeat.Get()); } else { - lv_label_set_text_static(heartbeatValue, "[L_HR]#ee3311 ---#"); + lv_label_set_text_static(heartbeatValue, "#ffffff [L_HR]# ---"); + lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray); } } - stepCount = motionController.NbSteps(); - if (stepCount.IsUpdated()) { - lv_label_set_text_fmt(stepValue, "[STEP]#ee3377 %lu steps#", stepCount.Get()); - } - currentWeather = weatherService.Current(); if (currentWeather.IsUpdated()) { auto optCurrentWeather = currentWeather.Get(); @@ -167,9 +162,30 @@ void WatchFaceTerminal::Refresh() { temp = optCurrentWeather->temperature.Fahrenheit(); tempUnit = 'F'; } - lv_label_set_text_fmt(weather, "[WTHR]#ffdd00 %d°%c %s#", temp, tempUnit, Symbols::GetSimpleCondition(optCurrentWeather->iconId)); + lv_label_set_text_fmt(weather, + "#ffffff [WTHR]# #ffdd00 %d°%c %s#", + temp, + tempUnit, + Symbols::GetSimpleCondition(optCurrentWeather->iconId)); } else { - lv_label_set_text(weather, "[WTHR]#ffdd00 ---"); + lv_label_set_text(weather, "#ffffff [WTHR]# #ffdd00 ---"); + } + } + + bleState = bleController.IsConnected(); + bleRadioEnabled = bleController.IsRadioEnabled(); + if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { + if (!bleRadioEnabled.Get()) { + lv_label_set_text_static(connectState, "#ffffff [STAT]# Disabled"); + lv_obj_set_style_local_text_color(connectState, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray); + } else { + if (bleState.Get()) { + lv_label_set_text_static(connectState, "#ffffff [STAT]# Connected"); + lv_obj_set_style_local_text_color(connectState, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::blue); + } else { + lv_label_set_text_static(connectState, "#ffffff [STAT]# Disconnected"); + lv_obj_set_style_local_text_color(connectState, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray); + } } } } diff --git a/src/displayapp/screens/WatchFaceTerminal.h b/src/displayapp/screens/WatchFaceTerminal.h index be425e7aa1..85d50b7a16 100644 --- a/src/displayapp/screens/WatchFaceTerminal.h +++ b/src/displayapp/screens/WatchFaceTerminal.h @@ -50,16 +50,17 @@ namespace Pinetime { Utility::DirtyValue> currentDate; Utility::DirtyValue> currentWeather {}; + lv_obj_t* container; + lv_obj_t* notificationIcon; + lv_obj_t* label_prompt_1; lv_obj_t* label_time; lv_obj_t* label_date; - lv_obj_t* label_prompt_1; - lv_obj_t* label_prompt_2; lv_obj_t* batteryValue; - lv_obj_t* heartbeatValue; lv_obj_t* stepValue; - lv_obj_t* notificationIcon; - lv_obj_t* connectState; + lv_obj_t* heartbeatValue; lv_obj_t* weather; + lv_obj_t* connectState; + lv_obj_t* label_prompt_2; Controllers::DateTime& dateTimeController; const Controllers::Battery& batteryController; From 1d97384e9135f179d445abd0afbc34ec8ea5a3fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Fri, 26 Dec 2025 14:50:01 +0100 Subject: [PATCH 2/5] Refactor battery color calculation logic into `BatteryIcon::ColorFromPercentage()`. --- src/displayapp/screens/BatteryIcon.cpp | 10 ++++++++++ src/displayapp/screens/BatteryIcon.h | 1 + src/displayapp/screens/WatchFaceTerminal.cpp | 10 ++++------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/BatteryIcon.cpp b/src/displayapp/screens/BatteryIcon.cpp index 6194807d32..ec740e9312 100644 --- a/src/displayapp/screens/BatteryIcon.cpp +++ b/src/displayapp/screens/BatteryIcon.cpp @@ -3,6 +3,7 @@ #include "displayapp/screens/Symbols.h" #include "displayapp/icons/battery/batteryicon.c" #include "displayapp/InfiniTimeTheme.h" +#include using namespace Pinetime::Applications::Screens; @@ -51,3 +52,12 @@ const char* BatteryIcon::GetPlugIcon(bool isCharging) { else return ""; } + +lv_color_t BatteryIcon::ColorFromPercentage(int batteryPercent) { + // HSV color model has red at 0° and green at 120°. + // We lock saturation and brightness at 100% and traverse the cylinder + // between red and green, thus avoiding the darker RGB on medium battery + // charges and giving us a much nicer color range. + const uint8_t hue = batteryPercent * 120 / 100; + return lv_color_hsv_to_rgb(hue, 100, 100); +} diff --git a/src/displayapp/screens/BatteryIcon.h b/src/displayapp/screens/BatteryIcon.h index 19fea967d9..ffce57c716 100644 --- a/src/displayapp/screens/BatteryIcon.h +++ b/src/displayapp/screens/BatteryIcon.h @@ -16,6 +16,7 @@ namespace Pinetime { static const char* GetUnknownIcon(); static const char* GetPlugIcon(bool isCharging); + static lv_color_t ColorFromPercentage(int batteryPercent); private: lv_obj_t* batteryImg; diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index 4442b29c6f..69fbc3ceea 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -123,12 +123,10 @@ void WatchFaceTerminal::Refresh() { powerPresent = batteryController.IsPowerPresent(); batteryPercentRemaining = batteryController.PercentRemaining(); if (batteryPercentRemaining.IsUpdated() || powerPresent.IsUpdated()) { - // HSV color model has red at 0° and green at 120°. - // We lock satuation and brightness at 100% and traverse the cilinder - // between red and green, thus avoiding the darker RGB on medium battery - // charges and giving us a much nicer color range. - uint8_t hue = batteryPercentRemaining.Get() * 120 / 100; - lv_obj_set_style_local_text_color(batteryValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(hue, 100, 100)); + lv_obj_set_style_local_text_color(batteryValue, + LV_LABEL_PART_MAIN, + LV_STATE_DEFAULT, + BatteryIcon::ColorFromPercentage(batteryPercentRemaining.Get())); lv_label_set_text_fmt(batteryValue, "#ffffff [BATT]# %d%%", batteryPercentRemaining.Get()); if (batteryController.IsCharging()) { lv_label_ins_text(batteryValue, LV_LABEL_POS_LAST, " Charging"); From 8c019d2ebd4a3dc05623e05b71260c59eedc6676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Mon, 29 Dec 2025 22:10:11 +0100 Subject: [PATCH 3/5] WatchFaceTerminal : rename a few fields to camelCase. --- src/displayapp/screens/WatchFaceTerminal.cpp | 26 ++++++++++---------- src/displayapp/screens/WatchFaceTerminal.h | 8 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index 69fbc3ceea..3fa80dcb37 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -39,15 +39,15 @@ WatchFaceTerminal::WatchFaceTerminal(Controllers::DateTime& dateTimeController, notificationIcon = lv_label_create(container, nullptr); - label_prompt_1 = lv_label_create(container, nullptr); - lv_obj_set_style_local_text_color(label_prompt_1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - lv_label_set_text_static(label_prompt_1, "user@watch:~ $ now"); + labelPrompt1 = lv_label_create(container, nullptr); + lv_obj_set_style_local_text_color(labelPrompt1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + lv_label_set_text_static(labelPrompt1, "user@watch:~ $ now"); - label_time = lv_label_create(container, nullptr); - lv_label_set_recolor(label_time, true); + labelTime = lv_label_create(container, nullptr); + lv_label_set_recolor(labelTime, true); - label_date = lv_label_create(container, nullptr); - lv_label_set_recolor(label_date, true); + labelDate = lv_label_create(container, nullptr); + lv_label_set_recolor(labelDate, true); batteryValue = lv_label_create(container, nullptr); lv_label_set_recolor(batteryValue, true); @@ -65,9 +65,9 @@ WatchFaceTerminal::WatchFaceTerminal(Controllers::DateTime& dateTimeController, connectState = lv_label_create(container, nullptr); lv_label_set_recolor(connectState, true); - label_prompt_2 = lv_label_create(container, nullptr); - lv_obj_set_style_local_text_color(label_prompt_2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - lv_label_set_text_static(label_prompt_2, "user@watch:~ $"); + labelPrompt2 = lv_label_create(container, nullptr); + lv_obj_set_style_local_text_color(labelPrompt2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + lv_label_set_text_static(labelPrompt2, "user@watch:~ $"); lv_obj_align(container, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 7); @@ -106,9 +106,9 @@ void WatchFaceTerminal::Refresh() { hour = hour - 12; ampmChar[0] = 'P'; } - lv_label_set_text_fmt(label_time, "#ffffff [TIME]# #11cc55 %02d:%02d:%02d %s#", hour, minute, second, ampmChar); + lv_label_set_text_fmt(labelTime, "#ffffff [TIME]# #11cc55 %02d:%02d:%02d %s#", hour, minute, second, ampmChar); } else { - lv_label_set_text_fmt(label_time, "#ffffff [TIME]# #11cc55 %02d:%02d:%02d#", hour, minute, second); + lv_label_set_text_fmt(labelTime, "#ffffff [TIME]# #11cc55 %02d:%02d:%02d#", hour, minute, second); } currentDate = std::chrono::time_point_cast(currentDateTime.Get()); @@ -116,7 +116,7 @@ void WatchFaceTerminal::Refresh() { uint16_t year = dateTimeController.Year(); Controllers::DateTime::Months month = dateTimeController.Month(); uint8_t day = dateTimeController.Day(); - lv_label_set_text_fmt(label_date, "#ffffff [DATE]# #007fff %04d-%02d-%02d#", short(year), char(month), char(day)); + lv_label_set_text_fmt(labelDate, "#ffffff [DATE]# #007fff %04d-%02d-%02d#", short(year), char(month), char(day)); } } diff --git a/src/displayapp/screens/WatchFaceTerminal.h b/src/displayapp/screens/WatchFaceTerminal.h index 85d50b7a16..04c2d3616d 100644 --- a/src/displayapp/screens/WatchFaceTerminal.h +++ b/src/displayapp/screens/WatchFaceTerminal.h @@ -52,15 +52,15 @@ namespace Pinetime { lv_obj_t* container; lv_obj_t* notificationIcon; - lv_obj_t* label_prompt_1; - lv_obj_t* label_time; - lv_obj_t* label_date; + lv_obj_t* labelPrompt1; + lv_obj_t* labelTime; + lv_obj_t* labelDate; lv_obj_t* batteryValue; lv_obj_t* stepValue; lv_obj_t* heartbeatValue; lv_obj_t* weather; lv_obj_t* connectState; - lv_obj_t* label_prompt_2; + lv_obj_t* labelPrompt2; Controllers::DateTime& dateTimeController; const Controllers::Battery& batteryController; From 365e1f56f22d71e0afa77d523fde65a06e30434c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Mon, 29 Dec 2025 22:25:53 +0100 Subject: [PATCH 4/5] WatchFaceTerminal : Apply better curve in BatteryIcon::ColorFromPercentage() so the color doesn't start going yellow until the battery is low. --- src/displayapp/screens/BatteryIcon.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/BatteryIcon.cpp b/src/displayapp/screens/BatteryIcon.cpp index ec740e9312..8ebb1f5405 100644 --- a/src/displayapp/screens/BatteryIcon.cpp +++ b/src/displayapp/screens/BatteryIcon.cpp @@ -1,5 +1,6 @@ -#include "displayapp/screens/BatteryIcon.h" #include +#include +#include "displayapp/screens/BatteryIcon.h" #include "displayapp/screens/Symbols.h" #include "displayapp/icons/battery/batteryicon.c" #include "displayapp/InfiniTimeTheme.h" @@ -58,6 +59,8 @@ lv_color_t BatteryIcon::ColorFromPercentage(int batteryPercent) { // We lock saturation and brightness at 100% and traverse the cylinder // between red and green, thus avoiding the darker RGB on medium battery // charges and giving us a much nicer color range. - const uint8_t hue = batteryPercent * 120 / 100; + const float normalizedPercent = batteryPercent / 100.0f; + // Follow -e^{-4x} + 1 curve: begins going yellow around 25%, yellow around 15%, red around 5% + const uint8_t hue = (-std::exp(-4.0f * normalizedPercent) + 1.0f) * 120.0f; return lv_color_hsv_to_rgb(hue, 100, 100); } From 4aa4ef95da3c7b6896bd9fd8f0e7eff8cb563e67 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Thu, 1 Jan 2026 17:28:55 +0000 Subject: [PATCH 5/5] Remove unneeded casts --- src/displayapp/screens/WatchFaceTerminal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index 3fa80dcb37..505f79500c 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -116,7 +116,7 @@ void WatchFaceTerminal::Refresh() { uint16_t year = dateTimeController.Year(); Controllers::DateTime::Months month = dateTimeController.Month(); uint8_t day = dateTimeController.Day(); - lv_label_set_text_fmt(labelDate, "#ffffff [DATE]# #007fff %04d-%02d-%02d#", short(year), char(month), char(day)); + lv_label_set_text_fmt(labelDate, "#ffffff [DATE]# #007fff %04d-%02d-%02d#", year, month, day); } }