From f8bc9d5f556d1eeaf0dad0c1040b792ce21bd13f Mon Sep 17 00:00:00 2001 From: Steve Amor Date: Mon, 28 Aug 2023 07:25:22 +0100 Subject: [PATCH 01/67] Shows selected watch face page first --- src/displayapp/screens/settings/SettingWatchFace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index 5498d06792..30ac275f03 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -26,7 +26,7 @@ SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, : app {app}, settingsController {settingsController}, filesystem {filesystem}, - screens {app, 0, CreateScreenList(), Screens::ScreenListModes::UpDown} { + screens {app, static_cast(static_cast(settingsController.GetWatchFace())/4), CreateScreenList(), Screens::ScreenListModes::UpDown} { } SettingWatchFace::~SettingWatchFace() { From 29ede18d18777917efc9529ee7edf5c392aee103 Mon Sep 17 00:00:00 2001 From: Steveis Date: Wed, 4 Oct 2023 18:38:41 +0100 Subject: [PATCH 02/67] Update SettingWatchFace.cpp --- src/displayapp/screens/settings/SettingWatchFace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index 30ac275f03..7a9ed63728 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -26,7 +26,7 @@ SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, : app {app}, settingsController {settingsController}, filesystem {filesystem}, - screens {app, static_cast(static_cast(settingsController.GetWatchFace())/4), CreateScreenList(), Screens::ScreenListModes::UpDown} { + screens {app, static_cast(static_cast(settingsController.GetWatchFace()) / 4), CreateScreenList(), Screens::ScreenListModes::UpDown} { } SettingWatchFace::~SettingWatchFace() { From b6550cbd7bf126adf95e5199b4967bb2602a75e6 Mon Sep 17 00:00:00 2001 From: Steveis Date: Wed, 4 Oct 2023 18:47:25 +0100 Subject: [PATCH 03/67] Update SettingWatchFace.cpp --- src/displayapp/screens/settings/SettingWatchFace.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index 7a9ed63728..42911ef1e8 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -26,7 +26,10 @@ SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, : app {app}, settingsController {settingsController}, filesystem {filesystem}, - screens {app, static_cast(static_cast(settingsController.GetWatchFace()) / 4), CreateScreenList(), Screens::ScreenListModes::UpDown} { + screens {app, + static_cast(static_cast(settingsController.GetWatchFace()) / 4), + CreateScreenList(), + Screens::ScreenListModes::UpDown} { } SettingWatchFace::~SettingWatchFace() { From 9d13f7a859b2c04eac98116f76d5ad22cc27d283 Mon Sep 17 00:00:00 2001 From: JustScott Date: Mon, 3 Feb 2025 12:06:58 -0600 Subject: [PATCH 04/67] Add time since last weather update to weather app --- src/displayapp/screens/Weather.cpp | 23 +++++++++++++++++++++-- src/displayapp/screens/Weather.h | 9 +++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 25464c70cf..ceb0892c39 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -35,8 +35,10 @@ namespace { } } -Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService) - : settingsController {settingsController}, weatherService {weatherService} { +Weather::Weather(Controllers::Settings& settingsController, + Controllers::SimpleWeatherService& weatherService, + Controllers::DateTime& dateTimeController) + : settingsController {settingsController}, weatherService {weatherService}, dateTimeController {dateTimeController} { temperature = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); @@ -45,6 +47,11 @@ Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleW lv_obj_align(temperature, nullptr, LV_ALIGN_CENTER, 0, -30); lv_obj_set_auto_realign(temperature, true); + lastUpdated = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(lastUpdated, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); + lv_label_set_text_fmt(lastUpdated, ""); + lv_obj_align(lastUpdated, nullptr, LV_ALIGN_CENTER, -40, 0); + minTemperature = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(minTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); lv_label_set_text(minTemperature, ""); @@ -137,6 +144,18 @@ void Weather::Refresh() { lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); lv_label_set_text_fmt(minTemperature, "%d°", minTemp); lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp); + + int64_t secondsSinceEpoch = dateTimeController.CurrentDateTime().time_since_epoch().count() / 1000000000; + int64_t secondsSinceWeatherUpdate = secondsSinceEpoch - optCurrentWeather->timestamp; + if (secondsSinceWeatherUpdate < 0) { + lv_label_set_text_fmt(lastUpdated, "0s old", secondsSinceWeatherUpdate); + } else if (secondsSinceWeatherUpdate < 60) { + lv_label_set_text_fmt(lastUpdated, "%ds old", secondsSinceWeatherUpdate); + } else if (secondsSinceWeatherUpdate > 59 && secondsSinceWeatherUpdate < 3600) { + lv_label_set_text_fmt(lastUpdated, "%dm old", secondsSinceWeatherUpdate / 60); + } else if (secondsSinceWeatherUpdate > 3599) { + lv_label_set_text_fmt(lastUpdated, "%dh old", secondsSinceWeatherUpdate / 3600); + } } else { lv_label_set_text(icon, ""); lv_label_set_text(condition, ""); diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h index 6975311e06..2d41555bbc 100644 --- a/src/displayapp/screens/Weather.h +++ b/src/displayapp/screens/Weather.h @@ -4,6 +4,7 @@ #include #include "displayapp/screens/Screen.h" #include "components/ble/SimpleWeatherService.h" +#include "components/datetime/DateTimeController.h" #include "displayapp/apps/Apps.h" #include "displayapp/Controllers.h" #include "Symbols.h" @@ -20,7 +21,9 @@ namespace Pinetime { class Weather : public Screen { public: - Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService); + Weather(Controllers::Settings& settingsController, + Controllers::SimpleWeatherService& weatherService, + Controllers::DateTime& dateTimeController); ~Weather() override; void Refresh() override; @@ -28,6 +31,7 @@ namespace Pinetime { private: Controllers::Settings& settingsController; Controllers::SimpleWeatherService& weatherService; + Controllers::DateTime& dateTimeController; Utility::DirtyValue> currentWeather {}; Utility::DirtyValue> currentForecast {}; @@ -35,6 +39,7 @@ namespace Pinetime { lv_obj_t* icon; lv_obj_t* condition; lv_obj_t* temperature; + lv_obj_t* lastUpdated; lv_obj_t* minTemperature; lv_obj_t* maxTemperature; lv_obj_t* forecast; @@ -49,7 +54,7 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::cloudSunRain; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Weather(controllers.settingsController, *controllers.weatherController); + return new Screens::Weather(controllers.settingsController, *controllers.weatherController, controllers.dateTimeController); }; }; } From b542e26c269355d74ded5a5d151e91281e97d714 Mon Sep 17 00:00:00 2001 From: JustScott Date: Tue, 4 Feb 2025 22:48:27 -0600 Subject: [PATCH 05/67] Replace 'old' with 'ago' and adjust positioning --- src/displayapp/screens/Weather.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index ceb0892c39..055b3b07f7 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -44,13 +44,13 @@ Weather::Weather(Controllers::Settings& settingsController, lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_obj_set_style_local_text_font(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); lv_label_set_text(temperature, "---"); - lv_obj_align(temperature, nullptr, LV_ALIGN_CENTER, 0, -30); + lv_obj_align(temperature, nullptr, LV_ALIGN_CENTER, 0, -32); lv_obj_set_auto_realign(temperature, true); lastUpdated = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(lastUpdated, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); lv_label_set_text_fmt(lastUpdated, ""); - lv_obj_align(lastUpdated, nullptr, LV_ALIGN_CENTER, -40, 0); + lv_obj_align(lastUpdated, nullptr, LV_ALIGN_CENTER, -40, -1); minTemperature = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(minTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); @@ -148,13 +148,13 @@ void Weather::Refresh() { int64_t secondsSinceEpoch = dateTimeController.CurrentDateTime().time_since_epoch().count() / 1000000000; int64_t secondsSinceWeatherUpdate = secondsSinceEpoch - optCurrentWeather->timestamp; if (secondsSinceWeatherUpdate < 0) { - lv_label_set_text_fmt(lastUpdated, "0s old", secondsSinceWeatherUpdate); + lv_label_set_text_fmt(lastUpdated, "0s ago", secondsSinceWeatherUpdate); } else if (secondsSinceWeatherUpdate < 60) { - lv_label_set_text_fmt(lastUpdated, "%ds old", secondsSinceWeatherUpdate); + lv_label_set_text_fmt(lastUpdated, "%ds ago", secondsSinceWeatherUpdate); } else if (secondsSinceWeatherUpdate > 59 && secondsSinceWeatherUpdate < 3600) { - lv_label_set_text_fmt(lastUpdated, "%dm old", secondsSinceWeatherUpdate / 60); + lv_label_set_text_fmt(lastUpdated, "%dm ago", secondsSinceWeatherUpdate / 60); } else if (secondsSinceWeatherUpdate > 3599) { - lv_label_set_text_fmt(lastUpdated, "%dh old", secondsSinceWeatherUpdate / 3600); + lv_label_set_text_fmt(lastUpdated, "%dh ago", secondsSinceWeatherUpdate / 3600); } } else { lv_label_set_text(icon, ""); From 6cd398826b407136b4a79bd99fc8bd93c66f009d Mon Sep 17 00:00:00 2001 From: JustScott Date: Fri, 7 Feb 2025 04:38:50 -0600 Subject: [PATCH 06/67] Updated labels, improved/simplified logic, and improved positioning Use "Now" for the label until 31 seconds, then display the live time. --- src/displayapp/screens/Weather.cpp | 31 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 055b3b07f7..29ce2f28dc 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -50,7 +50,6 @@ Weather::Weather(Controllers::Settings& settingsController, lastUpdated = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(lastUpdated, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); lv_label_set_text_fmt(lastUpdated, ""); - lv_obj_align(lastUpdated, nullptr, LV_ALIGN_CENTER, -40, -1); minTemperature = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(minTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); @@ -145,21 +144,33 @@ void Weather::Refresh() { lv_label_set_text_fmt(minTemperature, "%d°", minTemp); lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp); - int64_t secondsSinceEpoch = dateTimeController.CurrentDateTime().time_since_epoch().count() / 1000000000; - int64_t secondsSinceWeatherUpdate = secondsSinceEpoch - optCurrentWeather->timestamp; - if (secondsSinceWeatherUpdate < 0) { - lv_label_set_text_fmt(lastUpdated, "0s ago", secondsSinceWeatherUpdate); - } else if (secondsSinceWeatherUpdate < 60) { + std::chrono::seconds secondsSinceEpoch = + std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()); + int32_t secondsSinceWeatherUpdate = secondsSinceEpoch.count() - optCurrentWeather->timestamp; + int8_t minutesSinceWeatherUpdate = secondsSinceWeatherUpdate / 60; + int8_t hoursSinceWeatherUpdate = secondsSinceWeatherUpdate / 3600; + + lv_obj_align(lastUpdated, nullptr, LV_ALIGN_CENTER, -31, -1); + if ((secondsSinceWeatherUpdate > 9 && secondsSinceWeatherUpdate < 60) || + (minutesSinceWeatherUpdate > 9 && minutesSinceWeatherUpdate < 60) || hoursSinceWeatherUpdate > 9) { + lv_obj_align(lastUpdated, nullptr, LV_ALIGN_CENTER, -41, -1); + } + + if (hoursSinceWeatherUpdate > 0) { + lv_label_set_text_fmt(lastUpdated, "%dh ago", hoursSinceWeatherUpdate); + } else if (minutesSinceWeatherUpdate > 0) { + lv_label_set_text_fmt(lastUpdated, "%dm ago", minutesSinceWeatherUpdate); + } else if (secondsSinceWeatherUpdate > 30) { lv_label_set_text_fmt(lastUpdated, "%ds ago", secondsSinceWeatherUpdate); - } else if (secondsSinceWeatherUpdate > 59 && secondsSinceWeatherUpdate < 3600) { - lv_label_set_text_fmt(lastUpdated, "%dm ago", secondsSinceWeatherUpdate / 60); - } else if (secondsSinceWeatherUpdate > 3599) { - lv_label_set_text_fmt(lastUpdated, "%dh ago", secondsSinceWeatherUpdate / 3600); + } else if (secondsSinceWeatherUpdate < 31) { + lv_obj_align(lastUpdated, nullptr, LV_ALIGN_CENTER, -18, -1); + lv_label_set_text_fmt(lastUpdated, "Now", secondsSinceWeatherUpdate); } } else { lv_label_set_text(icon, ""); lv_label_set_text(condition, ""); lv_label_set_text(temperature, "---"); + lv_label_set_text(lastUpdated, ""); lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_label_set_text(minTemperature, ""); lv_label_set_text(maxTemperature, ""); From cb4e7d655b5fd867074755f82bc7f481acfffad4 Mon Sep 17 00:00:00 2001 From: JustScott Date: Sat, 8 Feb 2025 12:13:59 -0600 Subject: [PATCH 07/67] Fixed positioning Move from `lv_obj_align` to `lv_obj_set_pos` to avoid weird positioning errors when changing the position more than once. --- src/displayapp/screens/Weather.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 29ce2f28dc..c8debd81f0 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -49,7 +49,7 @@ Weather::Weather(Controllers::Settings& settingsController, lastUpdated = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(lastUpdated, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); - lv_label_set_text_fmt(lastUpdated, ""); + lv_label_set_text(lastUpdated, ""); minTemperature = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(minTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); @@ -150,20 +150,30 @@ void Weather::Refresh() { int8_t minutesSinceWeatherUpdate = secondsSinceWeatherUpdate / 60; int8_t hoursSinceWeatherUpdate = secondsSinceWeatherUpdate / 3600; - lv_obj_align(lastUpdated, nullptr, LV_ALIGN_CENTER, -31, -1); - if ((secondsSinceWeatherUpdate > 9 && secondsSinceWeatherUpdate < 60) || - (minutesSinceWeatherUpdate > 9 && minutesSinceWeatherUpdate < 60) || hoursSinceWeatherUpdate > 9) { - lv_obj_align(lastUpdated, nullptr, LV_ALIGN_CENTER, -41, -1); - } + constexpr uint8_t Y_POSITION = 108; + constexpr uint8_t X_SINGLE_DIGIT_POSITION = 90; + constexpr uint8_t X_TWO_DIGIT_POSITION = 78; + constexpr uint8_t X_NOW_POSITION = 102; + + lv_obj_set_pos(lastUpdated, X_SINGLE_DIGIT_POSITION, Y_POSITION); if (hoursSinceWeatherUpdate > 0) { + if (hoursSinceWeatherUpdate > 9) { + lv_obj_set_pos(lastUpdated, X_TWO_DIGIT_POSITION, Y_POSITION); + } lv_label_set_text_fmt(lastUpdated, "%dh ago", hoursSinceWeatherUpdate); } else if (minutesSinceWeatherUpdate > 0) { + if (minutesSinceWeatherUpdate > 9 && minutesSinceWeatherUpdate < 60) { + lv_obj_set_pos(lastUpdated, X_TWO_DIGIT_POSITION, Y_POSITION); + } lv_label_set_text_fmt(lastUpdated, "%dm ago", minutesSinceWeatherUpdate); } else if (secondsSinceWeatherUpdate > 30) { + if (secondsSinceWeatherUpdate > 9 && secondsSinceWeatherUpdate < 60) { + lv_obj_set_pos(lastUpdated, X_TWO_DIGIT_POSITION, Y_POSITION); + } lv_label_set_text_fmt(lastUpdated, "%ds ago", secondsSinceWeatherUpdate); } else if (secondsSinceWeatherUpdate < 31) { - lv_obj_align(lastUpdated, nullptr, LV_ALIGN_CENTER, -18, -1); + lv_obj_set_pos(lastUpdated, X_NOW_POSITION, Y_POSITION); lv_label_set_text_fmt(lastUpdated, "Now", secondsSinceWeatherUpdate); } } else { From 74701236f6d4cd5a9126b18088e46628a964e58b Mon Sep 17 00:00:00 2001 From: Steve Amor Date: Wed, 19 Feb 2025 18:18:48 +0000 Subject: [PATCH 08/67] Improves UX when charing on Quick Settings --- src/displayapp/screens/settings/QuickSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp index c5c3071aef..66231453c4 100644 --- a/src/displayapp/screens/settings/QuickSettings.cpp +++ b/src/displayapp/screens/settings/QuickSettings.cpp @@ -119,7 +119,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app, lv_obj_set_style_local_text_font(lbl_btn, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48); lv_label_set_text_static(lbl_btn, Symbols::settings); - taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_MID, this); + taskUpdate = lv_task_create(lv_update_task, 100, LV_TASK_PRIO_MID, this); UpdateScreen(); } From 3a79fc6ff78465ced19020432cc6367f40ca5a04 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 12 May 2025 01:22:05 +0200 Subject: [PATCH 09/67] music app redesign --- src/displayapp/screens/Music.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 0763da0fe3..0369f28a38 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -23,6 +23,8 @@ #include "displayapp/icons/music/disc.c" #include "displayapp/icons/music/disc_f_1.c" #include "displayapp/icons/music/disc_f_2.c" +#include "displayapp/InfiniTimeTheme.h" + using namespace Pinetime::Applications::Screens; @@ -52,7 +54,7 @@ Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { lv_style_init(&btn_style); lv_style_set_radius(&btn_style, LV_STATE_DEFAULT, 20); - lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, LV_COLOR_AQUA); + lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, Colors::bgAlt); lv_style_set_bg_opa(&btn_style, LV_STATE_DEFAULT, LV_OPA_50); btnVolDown = lv_btn_create(lv_scr_act(), nullptr); @@ -114,15 +116,15 @@ Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { constexpr int8_t MIDDLE_OFFSET = -25; txtArtist = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC); - lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT); + lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 2 * FONT_HEIGHT + LINE_PAD); lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtArtist, LV_HOR_RES - 12); lv_label_set_text_static(txtArtist, "Artist Name"); + lv_obj_set_style_local_text_color(txtArtist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); txtTrack = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC); - lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 2 * FONT_HEIGHT + LINE_PAD); - + lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT); lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtTrack, LV_HOR_RES - 12); lv_label_set_text_static(txtTrack, "This is a very long getTrack name"); From 5ccbaad83e981fde19eb83e8cc16bfbc6200c12b Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 12 May 2025 01:41:58 +0200 Subject: [PATCH 10/67] removed an empty line --- src/displayapp/screens/Music.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 0369f28a38..6be76fb010 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -25,7 +25,6 @@ #include "displayapp/icons/music/disc_f_2.c" #include "displayapp/InfiniTimeTheme.h" - using namespace Pinetime::Applications::Screens; static void event_handler(lv_obj_t* obj, lv_event_t event) { From e97cb58fbbeb1f2cc283b93a9ba2f5277a6e4a39 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 12 May 2025 19:25:30 +0200 Subject: [PATCH 11/67] Some tweaks for the default texts, as well as adding a different approach to switching between skipping and volume buttons --- .vscode/settings.json | 4 +++- src/components/ble/MusicService.h | 6 +++--- src/displayapp/screens/Music.cpp | 36 ++++++++++++++++++------------- src/displayapp/screens/Music.h | 8 +++++-- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a7b04eea3c..70643b0798 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,6 +65,8 @@ "stdexcept": "cpp", "streambuf": "cpp", "cinttypes": "cpp", - "typeinfo": "cpp" + "typeinfo": "cpp", + "ios": "cpp", + "disc.c": "cpp" } } diff --git a/src/components/ble/MusicService.h b/src/components/ble/MusicService.h index 93d94a346e..9257e13514 100644 --- a/src/components/ble/MusicService.h +++ b/src/components/ble/MusicService.h @@ -71,9 +71,9 @@ namespace Pinetime { uint16_t eventHandle {}; - std::string artistName {"Waiting for"}; - std::string albumName {}; - std::string trackName {"track information.."}; + std::string trackName {""}; + std::string albumName {""}; + std::string artistName {"Not Playing"}; bool playing {false}; diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 6be76fb010..e7d7b1cf6c 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -48,7 +48,9 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ -Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { +Music::Music(Pinetime::Controllers::MusicService& music, + Pinetime::Controllers::MotorController& motor) + : musicService(music), motor(motor) { lv_obj_t* label; lv_style_init(&btn_style); @@ -118,7 +120,7 @@ Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 2 * FONT_HEIGHT + LINE_PAD); lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtArtist, LV_HOR_RES - 12); - lv_label_set_text_static(txtArtist, "Artist Name"); + lv_label_set_text_static(txtArtist, ""); lv_obj_set_style_local_text_color(txtArtist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); txtTrack = lv_label_create(lv_scr_act(), nullptr); @@ -126,7 +128,7 @@ Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT); lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtTrack, LV_HOR_RES - 12); - lv_label_set_text_static(txtTrack, "This is a very long getTrack name"); + lv_label_set_text_static(txtTrack, ""); /** Init animation */ imgDisc = lv_img_create(lv_scr_act(), nullptr); @@ -250,24 +252,28 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { } bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) { - switch (event) { - case TouchEvents::SwipeUp: { - lv_obj_set_hidden(btnVolDown, false); - lv_obj_set_hidden(btnVolUp, false); + static bool isVolumeMode = false; // T-flip-flop state - lv_obj_set_hidden(btnNext, true); - lv_obj_set_hidden(btnPrev, true); - return true; - } - case TouchEvents::SwipeDown: { - if (lv_obj_get_hidden(btnNext)) { + switch (event) { + case TouchEvents::DoubleTap: { + isVolumeMode = !isVolumeMode; // Toggle state + + if (isVolumeMode) { + motor.RunForDuration(35); + // Show volume controls, hide track controls + lv_obj_set_hidden(btnVolDown, false); + lv_obj_set_hidden(btnVolUp, false); + lv_obj_set_hidden(btnNext, true); + lv_obj_set_hidden(btnPrev, true); + } else { + motor.RunForDuration(35); + // Show track controls, hide volume controls lv_obj_set_hidden(btnNext, false); lv_obj_set_hidden(btnPrev, false); lv_obj_set_hidden(btnVolDown, true); lv_obj_set_hidden(btnVolUp, true); - return true; } - return false; + return true; } case TouchEvents::SwipeLeft: { musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT); diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 522533215b..e9aa2c8bf1 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -34,7 +34,8 @@ namespace Pinetime { namespace Screens { class Music : public Screen { public: - Music(Pinetime::Controllers::MusicService& music); + Music(Pinetime::Controllers::MusicService& music, + Pinetime::Controllers::MotorController& motor); ~Music() override; @@ -82,6 +83,9 @@ namespace Pinetime { lv_task_t* taskRefresh; + Controllers::MotorController& motor; + + /** Watchapp */ }; } @@ -92,7 +96,7 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::music; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Music(*controllers.musicService); + return new Screens::Music(*controllers.musicService, controllers.motorController); }; }; } From db1a0add8d27e5997babab4d8287d2967c55a7db Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 12 May 2025 19:28:32 +0200 Subject: [PATCH 12/67] formatting --- src/displayapp/screens/Music.cpp | 9 ++++----- src/displayapp/screens/Music.h | 3 +-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index e7d7b1cf6c..cd3f1af3b8 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -48,9 +48,8 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ -Music::Music(Pinetime::Controllers::MusicService& music, - Pinetime::Controllers::MotorController& motor) - : musicService(music), motor(motor) { +Music::Music(Pinetime::Controllers::MusicService& music, Pinetime::Controllers::MotorController& motor) +: musicService(music), motor(motor) { lv_obj_t* label; lv_style_init(&btn_style); @@ -252,11 +251,11 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { } bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) { - static bool isVolumeMode = false; // T-flip-flop state + static bool isVolumeMode = false; // T-flip-flop state switch (event) { case TouchEvents::DoubleTap: { - isVolumeMode = !isVolumeMode; // Toggle state + isVolumeMode = !isVolumeMode; // Toggle state if (isVolumeMode) { motor.RunForDuration(35); diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index e9aa2c8bf1..4b9992715e 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -34,8 +34,7 @@ namespace Pinetime { namespace Screens { class Music : public Screen { public: - Music(Pinetime::Controllers::MusicService& music, - Pinetime::Controllers::MotorController& motor); + Music(Pinetime::Controllers::MusicService& music, Pinetime::Controllers::MotorController& motor); ~Music() override; From e633015375cd478a1d9f8c26fec74bd6ffb6d651 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 12 May 2025 19:30:25 +0200 Subject: [PATCH 13/67] more formatting --- src/displayapp/screens/Music.cpp | 2 +- src/displayapp/screens/Music.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index cd3f1af3b8..db2033bce6 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -49,7 +49,7 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ Music::Music(Pinetime::Controllers::MusicService& music, Pinetime::Controllers::MotorController& motor) -: musicService(music), motor(motor) { + : musicService(music), motor(motor) { lv_obj_t* label; lv_style_init(&btn_style); diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 4b9992715e..924931f3df 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -84,7 +84,6 @@ namespace Pinetime { Controllers::MotorController& motor; - /** Watchapp */ }; } From ee276b5cd0545bcb9d0bbe4781c50513991f05af Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Wed, 14 May 2025 18:47:32 +0200 Subject: [PATCH 14/67] revert back to swiping as a gesture to switch between skip and volume buttons --- src/displayapp/screens/Music.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index db2033bce6..3fa2a8c938 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -251,28 +251,24 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { } bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) { - static bool isVolumeMode = false; // T-flip-flop state - switch (event) { - case TouchEvents::DoubleTap: { - isVolumeMode = !isVolumeMode; // Toggle state - - if (isVolumeMode) { - motor.RunForDuration(35); - // Show volume controls, hide track controls - lv_obj_set_hidden(btnVolDown, false); - lv_obj_set_hidden(btnVolUp, false); - lv_obj_set_hidden(btnNext, true); - lv_obj_set_hidden(btnPrev, true); - } else { - motor.RunForDuration(35); - // Show track controls, hide volume controls + case TouchEvents::SwipeUp: { + lv_obj_set_hidden(btnVolDown, false); + lv_obj_set_hidden(btnVolUp, false); + + lv_obj_set_hidden(btnNext, true); + lv_obj_set_hidden(btnPrev, true); + return true; + } + case TouchEvents::SwipeDown: { + if (lv_obj_get_hidden(btnNext)) { lv_obj_set_hidden(btnNext, false); lv_obj_set_hidden(btnPrev, false); lv_obj_set_hidden(btnVolDown, true); lv_obj_set_hidden(btnVolUp, true); + return true; } - return true; + return false; } case TouchEvents::SwipeLeft: { musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT); From 43aa9323428eb79218390e1fe2c84a41170a7549 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Wed, 14 May 2025 18:50:52 +0200 Subject: [PATCH 15/67] remove all unneccessary references to the motor controller --- src/displayapp/screens/Music.cpp | 4 ++-- src/displayapp/screens/Music.h | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 3fa2a8c938..a534b70061 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -48,8 +48,8 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ -Music::Music(Pinetime::Controllers::MusicService& music, Pinetime::Controllers::MotorController& motor) - : musicService(music), motor(motor) { +Music::Music(Pinetime::Controllers::MusicService& music) + : musicService(music){ lv_obj_t* label; lv_style_init(&btn_style); diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 924931f3df..522533215b 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -34,7 +34,7 @@ namespace Pinetime { namespace Screens { class Music : public Screen { public: - Music(Pinetime::Controllers::MusicService& music, Pinetime::Controllers::MotorController& motor); + Music(Pinetime::Controllers::MusicService& music); ~Music() override; @@ -82,8 +82,6 @@ namespace Pinetime { lv_task_t* taskRefresh; - Controllers::MotorController& motor; - /** Watchapp */ }; } @@ -94,7 +92,7 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::music; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Music(*controllers.musicService, controllers.motorController); + return new Screens::Music(*controllers.musicService); }; }; } From 29cc0eb21525f7aa9674717612cb015fdaa5d7b8 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Wed, 14 May 2025 18:53:10 +0200 Subject: [PATCH 16/67] formatting --- src/displayapp/screens/Music.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index a534b70061..29b8e45688 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -48,8 +48,7 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ -Music::Music(Pinetime::Controllers::MusicService& music) - : musicService(music){ +Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { lv_obj_t* label; lv_style_init(&btn_style); From 18894a6e0348dfd0c0cdd8b0dffb1f6b04e1b264 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Fri, 30 May 2025 15:39:38 +0200 Subject: [PATCH 17/67] removed accidental change --- .vscode/settings.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 70643b0798..a7b04eea3c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,8 +65,6 @@ "stdexcept": "cpp", "streambuf": "cpp", "cinttypes": "cpp", - "typeinfo": "cpp", - "ios": "cpp", - "disc.c": "cpp" + "typeinfo": "cpp" } } From cbc9625aa9706dae414936fa4ea002ac3dc333de Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Sat, 7 Jun 2025 00:33:01 +0200 Subject: [PATCH 18/67] correct color of the buttons --- src/displayapp/screens/Music.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 29b8e45688..0bd0965ff9 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -54,7 +54,6 @@ Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { lv_style_init(&btn_style); lv_style_set_radius(&btn_style, LV_STATE_DEFAULT, 20); lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, Colors::bgAlt); - lv_style_set_bg_opa(&btn_style, LV_STATE_DEFAULT, LV_OPA_50); btnVolDown = lv_btn_create(lv_scr_act(), nullptr); btnVolDown->user_data = this; From e44aac1f25117e17c485bc498e9427e8e88bb86f Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Thu, 12 Jun 2025 17:33:29 +0200 Subject: [PATCH 19/67] remove redundant initialisers for trackName and albumName --- src/components/ble/MusicService.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ble/MusicService.h b/src/components/ble/MusicService.h index 9257e13514..e32980b42c 100644 --- a/src/components/ble/MusicService.h +++ b/src/components/ble/MusicService.h @@ -71,8 +71,8 @@ namespace Pinetime { uint16_t eventHandle {}; - std::string trackName {""}; - std::string albumName {""}; + std::string trackName; + std::string albumName; std::string artistName {"Not Playing"}; bool playing {false}; From ef74a001d320cd1bab7bb29afaa474c5362e0f37 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Sat, 26 Jul 2025 18:47:59 +0200 Subject: [PATCH 20/67] add progress bar --- .vscode/settings.json | 3 +- src/displayapp/screens/Music.cpp | 103 +++++++++++++++++++++++-------- src/displayapp/screens/Music.h | 17 ++++- 3 files changed, 94 insertions(+), 29 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a7b04eea3c..f0414bac40 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,6 +65,7 @@ "stdexcept": "cpp", "streambuf": "cpp", "cinttypes": "cpp", - "typeinfo": "cpp" + "typeinfo": "cpp", + "disc_f_1.c": "cpp" } } diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 0bd0965ff9..ace12f2638 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -24,6 +24,7 @@ #include "displayapp/icons/music/disc_f_1.c" #include "displayapp/icons/music/disc_f_2.c" #include "displayapp/InfiniTimeTheme.h" +#include "components/ble/BleController.h" using namespace Pinetime::Applications::Screens; @@ -48,7 +49,7 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ -Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { +Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController): musicService(music), bleController {bleController}{ lv_obj_t* label; lv_style_init(&btn_style); @@ -102,19 +103,12 @@ Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { txtPlayPause = lv_label_create(btnPlayPause, nullptr); lv_label_set_text_static(txtPlayPause, Symbols::play); - txtTrackDuration = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_long_mode(txtTrackDuration, LV_LABEL_LONG_SROLL); - lv_obj_align(txtTrackDuration, nullptr, LV_ALIGN_IN_TOP_LEFT, 12, 20); - lv_label_set_text_static(txtTrackDuration, "--:--/--:--"); - lv_label_set_align(txtTrackDuration, LV_ALIGN_IN_LEFT_MID); - lv_obj_set_width(txtTrackDuration, LV_HOR_RES); - constexpr uint8_t FONT_HEIGHT = 12; constexpr uint8_t LINE_PAD = 15; constexpr int8_t MIDDLE_OFFSET = -25; txtArtist = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC); - lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 2 * FONT_HEIGHT + LINE_PAD); + lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 0, (MIDDLE_OFFSET - 45) + 2 * FONT_HEIGHT + LINE_PAD); lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtArtist, LV_HOR_RES - 12); lv_label_set_text_static(txtArtist, ""); @@ -122,19 +116,53 @@ Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { txtTrack = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC); - lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT); + lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 0, (MIDDLE_OFFSET - 45) + 1 * FONT_HEIGHT); lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtTrack, LV_HOR_RES - 12); lv_label_set_text_static(txtTrack, ""); - /** Init animation */ + barTrackDuration = lv_bar_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(barTrackDuration, LV_BAR_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(barTrackDuration, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Colors::lightGray); + lv_obj_set_style_local_bg_opa(barTrackDuration, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100); + lv_obj_set_style_local_radius(barTrackDuration, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_size(barTrackDuration, 240, 10); + lv_obj_align(barTrackDuration, nullptr, LV_ALIGN_CENTER, 0, 5); + lv_bar_set_range(barTrackDuration, 0, 1000); + lv_bar_set_value(barTrackDuration, 0, LV_ANIM_OFF); + + txtCurrentPosition = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_long_mode(txtCurrentPosition, LV_LABEL_LONG_SROLL); + lv_obj_align(txtCurrentPosition, nullptr, LV_ALIGN_IN_LEFT_MID, 0, 25); + lv_label_set_text_static(txtCurrentPosition, "--:--"); + lv_label_set_align(txtCurrentPosition, LV_ALIGN_IN_LEFT_MID); + lv_obj_set_width(txtCurrentPosition, LV_HOR_RES); + lv_obj_set_style_local_text_color(txtCurrentPosition, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + + txtTrackDuration = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_long_mode(txtTrackDuration, LV_LABEL_LONG_SROLL); + lv_obj_align(txtTrackDuration, nullptr, LV_ALIGN_IN_RIGHT_MID, -13, 25); + lv_label_set_text_static(txtTrackDuration, "--:--"); + lv_label_set_align(txtTrackDuration, LV_ALIGN_IN_RIGHT_MID); + lv_obj_set_width(txtTrackDuration, LV_HOR_RES); + lv_obj_set_style_local_text_color(txtTrackDuration, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + + bluetoothInfo = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_fmt(bluetoothInfo, "%s ???", Screens::Symbols::bluetooth); + lv_obj_set_style_local_text_color(bluetoothInfo, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_align(bluetoothInfo, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0); + lv_obj_set_auto_realign(bluetoothInfo, true); + + + /* Init animation imgDisc = lv_img_create(lv_scr_act(), nullptr); lv_img_set_src_arr(imgDisc, &disc); - lv_obj_align(imgDisc, nullptr, LV_ALIGN_IN_TOP_RIGHT, -15, 15); + lv_obj_align(imgDisc, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); imgDiscAnim = lv_img_create(lv_scr_act(), nullptr); lv_img_set_src_arr(imgDiscAnim, &disc_f_1); - lv_obj_align(imgDiscAnim, nullptr, LV_ALIGN_IN_TOP_RIGHT, -15 - 32, 15); + lv_obj_align(imgDiscAnim, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0 - 32, 0); + */ frameB = false; @@ -178,16 +206,27 @@ void Music::Refresh() { UpdateLength(); } + bleState = bleController.IsConnected(); + bleRadioEnabled = bleController.IsRadioEnabled(); + if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { + if (bleState.Get() == false) { + lv_label_set_text_fmt(bluetoothInfo, "%s Disconnected", Screens::Symbols::bluetooth); + } else { + lv_label_set_text_fmt(bluetoothInfo, "%s Connected", Screens::Symbols::bluetooth); + } + } + if (playing) { lv_label_set_text_static(txtPlayPause, Symbols::pause); if (xTaskGetTickCount() - 1024 >= lastIncrement) { - if (frameB) { + /*if (frameB) { lv_img_set_src(imgDiscAnim, &disc_f_1); } else { lv_img_set_src(imgDiscAnim, &disc_f_2); } frameB = !frameB; + */ if (currentPosition >= totalLength) { // Let's assume the getTrack finished, paused when the timer ends @@ -202,22 +241,36 @@ void Music::Refresh() { } void Music::UpdateLength() { + int remaining = totalLength - currentPosition; + if (remaining < 0) remaining = 0; + if (totalLength > (99 * 60 * 60)) { - lv_label_set_text_static(txtTrackDuration, "Inf/Inf"); + lv_label_set_text_static(txtCurrentPosition, "Inf"); + lv_label_set_text_static(txtTrackDuration, "Inf"); } else if (totalLength > (99 * 60)) { - lv_label_set_text_fmt(txtTrackDuration, - "%02d:%02d/%02d:%02d", + lv_label_set_text_fmt(txtCurrentPosition, + "%d:%02d", (currentPosition / (60 * 60)) % 100, - ((currentPosition % (60 * 60)) / 60) % 100, - (totalLength / (60 * 60)) % 100, - ((totalLength % (60 * 60)) / 60) % 100); - } else { + ((currentPosition % (60 * 60)) / 60) % 100); + lv_label_set_text_fmt(txtTrackDuration, - "%02d:%02d/%02d:%02d", + "-%d:%02d", + (remaining / (60 * 60)) % 100, + ((remaining % (60 * 60)) / 60) % 100); + lv_bar_set_range(barTrackDuration, 0, totalLength > 0 ? totalLength : 1); + lv_bar_set_value(barTrackDuration, currentPosition, LV_ANIM_OFF); + } else { + lv_label_set_text_fmt(txtCurrentPosition, + "%d:%02d", (currentPosition / 60) % 100, - (currentPosition % 60) % 100, - (totalLength / 60) % 100, - (totalLength % 60) % 100); + (currentPosition % 60) % 100); + + lv_label_set_text_fmt(txtTrackDuration, + "-%d:%02d", + (remaining / 60) % 100, + (remaining % 60) % 100); + lv_bar_set_range(barTrackDuration, 0, totalLength); + lv_bar_set_value(barTrackDuration, currentPosition, LV_ANIM_OFF); } } diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 522533215b..c801ae9773 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -24,6 +24,8 @@ #include "displayapp/apps/Apps.h" #include "displayapp/Controllers.h" #include "Symbols.h" +#include "components/ble/BleController.h" +#include "utility/DirtyValue.h" namespace Pinetime { namespace Controllers { @@ -34,7 +36,7 @@ namespace Pinetime { namespace Screens { class Music : public Screen { public: - Music(Pinetime::Controllers::MusicService& music); + Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController); ~Music() override; @@ -55,17 +57,22 @@ namespace Pinetime { lv_obj_t* txtArtist; lv_obj_t* txtTrack; lv_obj_t* txtPlayPause; + lv_obj_t* bluetoothInfo; lv_obj_t* imgDisc; lv_obj_t* imgDiscAnim; lv_obj_t* txtTrackDuration; + lv_obj_t* txtCurrentPosition; + lv_obj_t* barTrackDuration; + lv_style_t btn_style; /** For the spinning disc animation */ bool frameB; - Pinetime::Controllers::MusicService& musicService; + Pinetime::Controllers::MusicService& musicService; + const Controllers::Ble& bleController; std::string artist; std::string album; @@ -82,6 +89,9 @@ namespace Pinetime { lv_task_t* taskRefresh; + Utility::DirtyValue bleState {}; + Utility::DirtyValue bleRadioEnabled {}; + /** Watchapp */ }; } @@ -92,7 +102,8 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::music; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Music(*controllers.musicService); + return new Screens::Music(*controllers.musicService, + controllers.bleController); }; }; } From fcea150959e429bbfff0aa8b76fe4e6b1957514a Mon Sep 17 00:00:00 2001 From: Titus <154823939+tituscmd@users.noreply.github.com> Date: Sat, 26 Jul 2025 21:19:38 +0200 Subject: [PATCH 21/67] Update settings.json --- .vscode/settings.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f0414bac40..a7b04eea3c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,7 +65,6 @@ "stdexcept": "cpp", "streambuf": "cpp", "cinttypes": "cpp", - "typeinfo": "cpp", - "disc_f_1.c": "cpp" + "typeinfo": "cpp" } } From 052dad29a229081d774f43de379eb0adc990bdd6 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 28 Jul 2025 22:43:27 +0200 Subject: [PATCH 22/67] formatting --- src/displayapp/screens/Music.cpp | 30 +++++++++--------------------- src/displayapp/screens/Music.h | 3 +-- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index ace12f2638..bbbf4f8cd1 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -49,7 +49,8 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ -Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController): musicService(music), bleController {bleController}{ +Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController) + : musicService(music), bleController {bleController}{ lv_obj_t* label; lv_style_init(&btn_style); @@ -212,7 +213,7 @@ void Music::Refresh() { if (bleState.Get() == false) { lv_label_set_text_fmt(bluetoothInfo, "%s Disconnected", Screens::Symbols::bluetooth); } else { - lv_label_set_text_fmt(bluetoothInfo, "%s Connected", Screens::Symbols::bluetooth); + lv_label_set_text_fmt(bluetoothInfo, "%s Connected", Screens::Symbols::bluetooth); } } @@ -242,33 +243,20 @@ void Music::Refresh() { void Music::UpdateLength() { int remaining = totalLength - currentPosition; - if (remaining < 0) remaining = 0; + if (remaining < 0) + remaining = 0; if (totalLength > (99 * 60 * 60)) { lv_label_set_text_static(txtCurrentPosition, "Inf"); lv_label_set_text_static(txtTrackDuration, "Inf"); } else if (totalLength > (99 * 60)) { - lv_label_set_text_fmt(txtCurrentPosition, - "%d:%02d", - (currentPosition / (60 * 60)) % 100, - ((currentPosition % (60 * 60)) / 60) % 100); - - lv_label_set_text_fmt(txtTrackDuration, - "-%d:%02d", - (remaining / (60 * 60)) % 100, - ((remaining % (60 * 60)) / 60) % 100); + lv_label_set_text_fmt(txtCurrentPosition, "%d:%02d", (currentPosition / (60 * 60)) % 100, ((currentPosition % (60 * 60)) / 60) % 100); + lv_label_set_text_fmt(txtTrackDuration, "-%d:%02d", (remaining / (60 * 60)) % 100, ((remaining % (60 * 60)) / 60) % 100); lv_bar_set_range(barTrackDuration, 0, totalLength > 0 ? totalLength : 1); lv_bar_set_value(barTrackDuration, currentPosition, LV_ANIM_OFF); } else { - lv_label_set_text_fmt(txtCurrentPosition, - "%d:%02d", - (currentPosition / 60) % 100, - (currentPosition % 60) % 100); - - lv_label_set_text_fmt(txtTrackDuration, - "-%d:%02d", - (remaining / 60) % 100, - (remaining % 60) % 100); + lv_label_set_text_fmt(txtCurrentPosition, "%d:%02d", (currentPosition / 60) % 100, (currentPosition % 60) % 100); + lv_label_set_text_fmt(txtTrackDuration, "-%d:%02d", (remaining / 60) % 100, (remaining % 60) % 100); lv_bar_set_range(barTrackDuration, 0, totalLength); lv_bar_set_value(barTrackDuration, currentPosition, LV_ANIM_OFF); } diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index c801ae9773..e94fe8db3b 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -102,8 +102,7 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::music; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Music(*controllers.musicService, - controllers.bleController); + return new Screens::Music(*controllers.musicService, controllers.bleController); }; }; } From 65ae1293b0454edcd2f69ca4a03f5f446ce1f14f Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 28 Jul 2025 22:48:36 +0200 Subject: [PATCH 23/67] formatting --- src/displayapp/screens/Music.cpp | 2 +- src/displayapp/screens/Music.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index c8b9079f63..39be58c0b4 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -51,7 +51,7 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController) - : musicService(music), bleController {bleController}{ + : musicService(music), bleController {bleController} { lv_obj_t* label; lv_style_init(&btn_style); diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index f8e8c9f05f..f4504c2f58 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -71,7 +71,7 @@ namespace Pinetime { /** For the spinning disc animation */ bool frameB; - Pinetime::Controllers::MusicService& musicService; + Pinetime::Controllers::MusicService& musicService; const Controllers::Ble& bleController; std::string artist; From ed30e539fdf2b0dfa2a312deb227ef1ac648b60f Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Tue, 29 Jul 2025 00:16:44 +0200 Subject: [PATCH 24/67] more formatting --- src/displayapp/screens/Music.cpp | 1 - src/displayapp/screens/Music.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 39be58c0b4..52538cf6ac 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -26,7 +26,6 @@ #include "displayapp/InfiniTimeTheme.h" #include "components/ble/BleController.h" - using namespace Pinetime::Applications::Screens; static void event_handler(lv_obj_t* obj, lv_event_t event) { diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index f4504c2f58..7d60f6c8e8 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -65,7 +65,6 @@ namespace Pinetime { lv_obj_t* txtCurrentPosition; lv_obj_t* barTrackDuration; - lv_style_t btn_style; /** For the spinning disc animation */ From 1f502efec72c66a09db262135a6f4320b637452a Mon Sep 17 00:00:00 2001 From: JustScott Date: Mon, 4 Aug 2025 16:50:21 -0500 Subject: [PATCH 25/67] Use `auto` for cast to meet Coding convention Thanks to @dariusarnold for catching this --- src/displayapp/screens/Weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index c8debd81f0..a9c9f6d5a4 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -144,7 +144,7 @@ void Weather::Refresh() { lv_label_set_text_fmt(minTemperature, "%d°", minTemp); lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp); - std::chrono::seconds secondsSinceEpoch = + auto secondsSinceEpoch = std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()); int32_t secondsSinceWeatherUpdate = secondsSinceEpoch.count() - optCurrentWeather->timestamp; int8_t minutesSinceWeatherUpdate = secondsSinceWeatherUpdate / 60; From 1b69ccf629ce36d32252236b734247b5d8141fd1 Mon Sep 17 00:00:00 2001 From: JustScott Date: Mon, 4 Aug 2025 17:16:35 -0500 Subject: [PATCH 26/67] Reduce unnecessary logic in positioning code Thanks to @dariusarnold for suggesting these changes. There was no need to define an upper bounds of 60 for changing to two digit positioning. --- src/displayapp/screens/Weather.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index a9c9f6d5a4..c46eab51e8 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -163,14 +163,12 @@ void Weather::Refresh() { } lv_label_set_text_fmt(lastUpdated, "%dh ago", hoursSinceWeatherUpdate); } else if (minutesSinceWeatherUpdate > 0) { - if (minutesSinceWeatherUpdate > 9 && minutesSinceWeatherUpdate < 60) { + if (minutesSinceWeatherUpdate > 9) { lv_obj_set_pos(lastUpdated, X_TWO_DIGIT_POSITION, Y_POSITION); } lv_label_set_text_fmt(lastUpdated, "%dm ago", minutesSinceWeatherUpdate); } else if (secondsSinceWeatherUpdate > 30) { - if (secondsSinceWeatherUpdate > 9 && secondsSinceWeatherUpdate < 60) { - lv_obj_set_pos(lastUpdated, X_TWO_DIGIT_POSITION, Y_POSITION); - } + lv_obj_set_pos(lastUpdated, X_TWO_DIGIT_POSITION, Y_POSITION); lv_label_set_text_fmt(lastUpdated, "%ds ago", secondsSinceWeatherUpdate); } else if (secondsSinceWeatherUpdate < 31) { lv_obj_set_pos(lastUpdated, X_NOW_POSITION, Y_POSITION); From 40a514297b7edb2d8db1224d20bed5e0c0b92221 Mon Sep 17 00:00:00 2001 From: JustScott Date: Mon, 4 Aug 2025 17:26:19 -0500 Subject: [PATCH 27/67] Fixed formatting --- src/displayapp/screens/Weather.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index c46eab51e8..cbbc21fb41 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -144,8 +144,7 @@ void Weather::Refresh() { lv_label_set_text_fmt(minTemperature, "%d°", minTemp); lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp); - auto secondsSinceEpoch = - std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()); + auto secondsSinceEpoch = std::chrono::duration_cast(dateTimeController.CurrentDateTime().time_since_epoch()); int32_t secondsSinceWeatherUpdate = secondsSinceEpoch.count() - optCurrentWeather->timestamp; int8_t minutesSinceWeatherUpdate = secondsSinceWeatherUpdate / 60; int8_t hoursSinceWeatherUpdate = secondsSinceWeatherUpdate / 3600; From c634bf21339f95097ef1372b797a3ccdcf5834bc Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Wed, 6 Aug 2025 14:54:59 +0200 Subject: [PATCH 28/67] different design for music.cpp --- src/displayapp/screens/Music.cpp | 30 +++++++++++++++++++++++++----- src/displayapp/screens/Music.h | 10 ++++++++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 52538cf6ac..0b88d640ed 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -49,8 +49,12 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ -Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController) - : musicService(music), bleController {bleController} { +Music::Music(Pinetime::Controllers::MusicService& music, + const Controllers::Ble& bleController, + Controllers::DateTime& dateTimeController) + : musicService(music), bleController {bleController}, + dateTimeController {dateTimeController} { + lv_obj_t* label; lv_style_init(&btn_style); @@ -149,11 +153,13 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& lv_obj_set_width(txtTrackDuration, LV_HOR_RES); lv_obj_set_style_local_text_color(txtTrackDuration, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + /* bluetoothInfo = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_fmt(bluetoothInfo, "%s ???", Screens::Symbols::bluetooth); lv_obj_set_style_local_text_color(bluetoothInfo, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_align(bluetoothInfo, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0); lv_obj_set_auto_realign(bluetoothInfo, true); + */ /* Init animation imgDisc = lv_img_create(lv_scr_act(), nullptr); @@ -165,6 +171,11 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& lv_obj_align(imgDiscAnim, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0 - 32, 0); */ + label_time = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_align(label_time, LV_LABEL_ALIGN_CENTER); + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0); + lv_obj_set_auto_realign(label_time, true); + frameB = false; musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); @@ -207,15 +218,24 @@ void Music::Refresh() { UpdateLength(); } + lv_label_set_text(label_time, dateTimeController.FormattedTime().c_str()); + bleState = bleController.IsConnected(); bleRadioEnabled = bleController.IsRadioEnabled(); if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { if (bleState.Get() == false) { - lv_label_set_text_fmt(bluetoothInfo, "%s Disconnected", Screens::Symbols::bluetooth); - } else { - lv_label_set_text_fmt(bluetoothInfo, "%s Connected", Screens::Symbols::bluetooth); + lv_label_set_text_fmt(txtArtist, "Disconnected"); + lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + } + else { + lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); } } + if (playing) { lv_label_set_text_static(txtPlayPause, Symbols::pause); diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 7d60f6c8e8..97ecb2ec49 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -36,7 +36,9 @@ namespace Pinetime { namespace Screens { class Music : public Screen { public: - Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController); + Music(Pinetime::Controllers::MusicService& music, + const Controllers::Ble& bleController, + Controllers::DateTime& dateTimeController); ~Music() override; @@ -58,6 +60,7 @@ namespace Pinetime { lv_obj_t* txtTrack; lv_obj_t* txtPlayPause; lv_obj_t* bluetoothInfo; + lv_obj_t* label_time; lv_obj_t* imgDisc; lv_obj_t* imgDiscAnim; @@ -72,6 +75,7 @@ namespace Pinetime { Pinetime::Controllers::MusicService& musicService; const Controllers::Ble& bleController; + Pinetime::Controllers::DateTime& dateTimeController; std::string artist; std::string album; @@ -101,7 +105,9 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::music; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Music(*controllers.musicService, controllers.bleController); + return new Screens::Music(*controllers.musicService, + controllers.bleController, + controllers.dateTimeController); }; static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { From b27c4f2b7e86be5efd7d96a358b2bbb713fab886 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 11 Aug 2025 02:09:50 +0200 Subject: [PATCH 29/67] renaming to camelCase, time top center, some visual tweaks --- src/displayapp/screens/Music.cpp | 27 ++++++++++----------------- src/displayapp/screens/Music.h | 3 +-- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 0b88d640ed..591e485ae8 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -115,16 +115,15 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC); lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 0, (MIDDLE_OFFSET - 45) + 2 * FONT_HEIGHT + LINE_PAD); lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID); - lv_obj_set_width(txtArtist, LV_HOR_RES - 12); + lv_obj_set_width(txtArtist, LV_HOR_RES); lv_label_set_text_static(txtArtist, ""); lv_obj_set_style_local_text_color(txtArtist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); txtTrack = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC); - lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 0, (MIDDLE_OFFSET - 45) + 1 * FONT_HEIGHT); lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID); - lv_obj_set_width(txtTrack, LV_HOR_RES - 12); + lv_obj_set_width(txtTrack, LV_HOR_RES); lv_label_set_text_static(txtTrack, ""); barTrackDuration = lv_bar_create(lv_scr_act(), nullptr); @@ -153,14 +152,6 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_set_width(txtTrackDuration, LV_HOR_RES); lv_obj_set_style_local_text_color(txtTrackDuration, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - /* - bluetoothInfo = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(bluetoothInfo, "%s ???", Screens::Symbols::bluetooth); - lv_obj_set_style_local_text_color(bluetoothInfo, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_align(bluetoothInfo, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0); - lv_obj_set_auto_realign(bluetoothInfo, true); - */ - /* Init animation imgDisc = lv_img_create(lv_scr_act(), nullptr); lv_img_set_src_arr(imgDisc, &disc); @@ -171,10 +162,11 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_align(imgDiscAnim, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0 - 32, 0); */ - label_time = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_align(label_time, LV_LABEL_ALIGN_CENTER); - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0); - lv_obj_set_auto_realign(label_time, true); + labelTime = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_align(labelTime, LV_LABEL_ALIGN_CENTER); + lv_obj_align(labelTime, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0); + lv_obj_set_auto_realign(labelTime, true); + lv_label_set_text_static(labelTime, "09:41"); frameB = false; @@ -218,7 +210,7 @@ void Music::Refresh() { UpdateLength(); } - lv_label_set_text(label_time, dateTimeController.FormattedTime().c_str()); + lv_label_set_text(labelTime, dateTimeController.FormattedTime().c_str()); bleState = bleController.IsConnected(); bleRadioEnabled = bleController.IsRadioEnabled(); @@ -241,7 +233,8 @@ void Music::Refresh() { lv_label_set_text_static(txtPlayPause, Symbols::pause); if (xTaskGetTickCount() - 1024 >= lastIncrement) { - /*if (frameB) { + /* + if (frameB) { lv_img_set_src(imgDiscAnim, &disc_f_1); } else { lv_img_set_src(imgDiscAnim, &disc_f_2); diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 97ecb2ec49..eccfb138e6 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -59,8 +59,7 @@ namespace Pinetime { lv_obj_t* txtArtist; lv_obj_t* txtTrack; lv_obj_t* txtPlayPause; - lv_obj_t* bluetoothInfo; - lv_obj_t* label_time; + lv_obj_t* labelTime; lv_obj_t* imgDisc; lv_obj_t* imgDiscAnim; From afe65d69dbd2d873cb7c2541753c86b4405eccfe Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 18 Aug 2025 19:30:00 +0200 Subject: [PATCH 30/67] tweak code for much easier alignment testing --- src/displayapp/screens/Music.cpp | 45 ++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 591e485ae8..0db5a3da6e 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -108,37 +108,40 @@ Music::Music(Pinetime::Controllers::MusicService& music, txtPlayPause = lv_label_create(btnPlayPause, nullptr); lv_label_set_text_static(txtPlayPause, Symbols::play); - constexpr uint8_t FONT_HEIGHT = 12; - constexpr uint8_t LINE_PAD = 15; - constexpr int8_t MIDDLE_OFFSET = -25; - txtArtist = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC); - lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 0, (MIDDLE_OFFSET - 45) + 2 * FONT_HEIGHT + LINE_PAD); - lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID); - lv_obj_set_width(txtArtist, LV_HOR_RES); - lv_label_set_text_static(txtArtist, ""); - lv_obj_set_style_local_text_color(txtArtist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + // top anchor for the whole stack, move this and everything follows + constexpr int16_t BASE_Y = -70; // was txtTrack's previous y, 70 looks good for current default txtTrack = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC); - lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 0, (MIDDLE_OFFSET - 45) + 1 * FONT_HEIGHT); + lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 0, BASE_Y); lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtTrack, LV_HOR_RES); lv_label_set_text_static(txtTrack, ""); + // 27px below txtTrack (12 + 15 previously), hard coded + txtArtist = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC); + lv_obj_align(txtArtist, txtTrack, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 27); + lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID); + lv_obj_set_width(txtArtist, LV_HOR_RES); + lv_label_set_text_static(txtArtist, ""); + lv_obj_set_style_local_text_color(txtArtist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + + // bar sits 36px below txtArtist (to match old layout) barTrackDuration = lv_bar_create(lv_scr_act(), nullptr); lv_obj_set_style_local_bg_color(barTrackDuration, LV_BAR_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_style_local_bg_color(barTrackDuration, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Colors::lightGray); lv_obj_set_style_local_bg_opa(barTrackDuration, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100); lv_obj_set_style_local_radius(barTrackDuration, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_obj_set_size(barTrackDuration, 240, 10); - lv_obj_align(barTrackDuration, nullptr, LV_ALIGN_CENTER, 0, 5); + lv_obj_align(barTrackDuration, txtArtist, LV_ALIGN_OUT_BOTTOM_MID, 0, 14); lv_bar_set_range(barTrackDuration, 0, 1000); lv_bar_set_value(barTrackDuration, 0, LV_ANIM_OFF); + // time labels 20px below the bar, left and right aligned txtCurrentPosition = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtCurrentPosition, LV_LABEL_LONG_SROLL); - lv_obj_align(txtCurrentPosition, nullptr, LV_ALIGN_IN_LEFT_MID, 0, 25); + lv_obj_align(txtCurrentPosition, barTrackDuration, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); lv_label_set_text_static(txtCurrentPosition, "--:--"); lv_label_set_align(txtCurrentPosition, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtCurrentPosition, LV_HOR_RES); @@ -146,12 +149,20 @@ Music::Music(Pinetime::Controllers::MusicService& music, txtTrackDuration = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtTrackDuration, LV_LABEL_LONG_SROLL); - lv_obj_align(txtTrackDuration, nullptr, LV_ALIGN_IN_RIGHT_MID, -13, 25); + lv_obj_align(txtTrackDuration, barTrackDuration, LV_ALIGN_OUT_BOTTOM_RIGHT, -13, 0); lv_label_set_text_static(txtTrackDuration, "--:--"); lv_label_set_align(txtTrackDuration, LV_ALIGN_IN_RIGHT_MID); lv_obj_set_width(txtTrackDuration, LV_HOR_RES); lv_obj_set_style_local_text_color(txtTrackDuration, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + // status time at the very top, keep independent of the chain + labelTime = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_align(labelTime, LV_LABEL_ALIGN_CENTER); + lv_obj_align(labelTime, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0); + lv_obj_set_auto_realign(labelTime, true); + lv_label_set_text_static(labelTime, "09:41"); + lv_obj_set_hidden(labelTime, true); + /* Init animation imgDisc = lv_img_create(lv_scr_act(), nullptr); lv_img_set_src_arr(imgDisc, &disc); @@ -162,12 +173,6 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_align(imgDiscAnim, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0 - 32, 0); */ - labelTime = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_align(labelTime, LV_LABEL_ALIGN_CENTER); - lv_obj_align(labelTime, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0); - lv_obj_set_auto_realign(labelTime, true); - lv_label_set_text_static(labelTime, "09:41"); - frameB = false; musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); From d87126a955855ca0306b72ebe206da38f39644fb Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 18 Aug 2025 19:30:18 +0200 Subject: [PATCH 31/67] tweak code for much easier alignment testing --- src/displayapp/screens/Music.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 0db5a3da6e..14042a4ddd 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -116,7 +116,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 0, BASE_Y); lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtTrack, LV_HOR_RES); - lv_label_set_text_static(txtTrack, ""); + lv_label_set_text_static(txtTrack, "Some Track"); // 27px below txtTrack (12 + 15 previously), hard coded txtArtist = lv_label_create(lv_scr_act(), nullptr); From d11a71b0c32bfa63e9d4c2eb447a34f80c5311a0 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 18 Aug 2025 20:19:02 +0200 Subject: [PATCH 32/67] change controls button --- src/displayapp/fonts/fonts.json | 2 +- src/displayapp/screens/Music.cpp | 37 ++++++++++++++++++++++++++++++-- src/displayapp/screens/Music.h | 4 ++++ src/displayapp/screens/Symbols.h | 1 + 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index fea3160572..f6567f3f6e 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -7,7 +7,7 @@ }, { "file": "FontAwesome5-Solid+Brands+Regular.woff", - "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf1ec, 0xf55a" + "range": "0xf079, 0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf1ec, 0xf55a" } ], "bpp": 1, diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 14042a4ddd..017dcce6d7 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -109,7 +109,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_label_set_text_static(txtPlayPause, Symbols::play); // top anchor for the whole stack, move this and everything follows - constexpr int16_t BASE_Y = -70; // was txtTrack's previous y, 70 looks good for current default + constexpr int16_t BASE_Y = -90; // was txtTrack's previous y, 70 looks good for current default txtTrack = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC); @@ -121,7 +121,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, // 27px below txtTrack (12 + 15 previously), hard coded txtArtist = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC); - lv_obj_align(txtArtist, txtTrack, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 27); + lv_obj_align(txtArtist, txtTrack, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtArtist, LV_HOR_RES); lv_label_set_text_static(txtArtist, ""); @@ -163,6 +163,19 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_label_set_text_static(labelTime, "09:41"); lv_obj_set_hidden(labelTime, true); + btnSwapControls = lv_btn_create(lv_scr_act(), nullptr); + btnSwapControls->user_data = this; + lv_obj_set_event_cb(btnSwapControls, event_handler); + lv_obj_set_style_local_radius(btnSwapControls, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20); + lv_obj_set_style_local_bg_color(btnSwapControls, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + txtSwapControls = lv_label_create(btnSwapControls, nullptr); + lv_label_set_text_fmt(txtSwapControls, "%s Volume Controls", Symbols::swap); + lv_obj_set_style_local_text_color(txtSwapControls, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + lv_obj_set_width(btnSwapControls, lv_obj_get_width(txtSwapControls) + 18); // +padding + lv_obj_set_height(btnSwapControls, lv_obj_get_height(txtSwapControls) + 8); // +padding + lv_obj_align(btnSwapControls, nullptr, LV_ALIGN_CENTER, 0, 20); + + /* Init animation imgDisc = lv_img_create(lv_scr_act(), nullptr); lv_img_set_src_arr(imgDisc, &disc); @@ -303,12 +316,31 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { } } else if (obj == btnNext) { musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT); + } else if (obj == btnSwapControls) { + showingVolumeControls = !showingVolumeControls; // flip the state + + if (showingVolumeControls) { + // show volume buttons, hide track buttons + lv_obj_set_hidden(btnVolDown, false); + lv_obj_set_hidden(btnVolUp, false); + lv_obj_set_hidden(btnNext, true); + lv_obj_set_hidden(btnPrev, true); + lv_label_set_text_fmt(txtSwapControls, "%s Track Controls", Symbols::swap); + } else { + // show track buttons, hide volume buttons + lv_obj_set_hidden(btnNext, false); + lv_obj_set_hidden(btnPrev, false); + lv_obj_set_hidden(btnVolDown, true); + lv_obj_set_hidden(btnVolUp, true); + lv_label_set_text_fmt(txtSwapControls, "%s Volume Controls", Symbols::swap); + } } } } bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) { switch (event) { + /* case TouchEvents::SwipeUp: { lv_obj_set_hidden(btnVolDown, false); lv_obj_set_hidden(btnVolUp, false); @@ -327,6 +359,7 @@ bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) { } return false; } + */ case TouchEvents::SwipeLeft: { musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT); return true; diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index eccfb138e6..ff2fd2ea51 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -56,9 +56,11 @@ namespace Pinetime { lv_obj_t* btnNext; lv_obj_t* btnVolDown; lv_obj_t* btnVolUp; + lv_obj_t* btnSwapControls; lv_obj_t* txtArtist; lv_obj_t* txtTrack; lv_obj_t* txtPlayPause; + lv_obj_t* txtSwapControls; lv_obj_t* labelTime; lv_obj_t* imgDisc; @@ -67,6 +69,8 @@ namespace Pinetime { lv_obj_t* txtCurrentPosition; lv_obj_t* barTrackDuration; + bool showingVolumeControls = false; + lv_style_t btn_style; /** For the spinning disc animation */ diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index 40699b3d65..4482fb0be2 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -41,6 +41,7 @@ namespace Pinetime { static constexpr const char* sleep = "\xEE\xBD\x84"; static constexpr const char* calculator = "\xEF\x87\xAC"; static constexpr const char* backspace = "\xEF\x95\x9A"; + static constexpr const char* swap = "\xef\x81\xb9"; // fontawesome_weathericons.c // static constexpr const char* sun = "\xEF\x86\x85"; From 8d036eecdb593b23fd910ab7f6c01e5aec027318 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 18 Aug 2025 20:47:28 +0200 Subject: [PATCH 33/67] tweaks to the new swap controls button --- src/displayapp/screens/Music.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 017dcce6d7..ea9af54ddc 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -116,7 +116,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 0, BASE_Y); lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtTrack, LV_HOR_RES); - lv_label_set_text_static(txtTrack, "Some Track"); + lv_label_set_text_static(txtTrack, ""); // 27px below txtTrack (12 + 15 previously), hard coded txtArtist = lv_label_create(lv_scr_act(), nullptr); @@ -174,6 +174,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_set_width(btnSwapControls, lv_obj_get_width(txtSwapControls) + 18); // +padding lv_obj_set_height(btnSwapControls, lv_obj_get_height(txtSwapControls) + 8); // +padding lv_obj_align(btnSwapControls, nullptr, LV_ALIGN_CENTER, 0, 20); + lv_obj_set_auto_realign(btnSwapControls, true); /* Init animation @@ -234,15 +235,20 @@ void Music::Refresh() { bleRadioEnabled = bleController.IsRadioEnabled(); if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { if (bleState.Get() == false) { - lv_label_set_text_fmt(txtArtist, "Disconnected"); + lv_label_set_text_static(txtArtist, "Disconnected"); + lv_label_set_text_static(txtTrack, ""); lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); } else { lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); } } @@ -326,6 +332,8 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { lv_obj_set_hidden(btnNext, true); lv_obj_set_hidden(btnPrev, true); lv_label_set_text_fmt(txtSwapControls, "%s Track Controls", Symbols::swap); + lv_obj_set_width(btnSwapControls, lv_obj_get_width(txtSwapControls) + 18); // +padding + lv_obj_set_height(btnSwapControls, lv_obj_get_height(txtSwapControls) + 8); // +padding } else { // show track buttons, hide volume buttons lv_obj_set_hidden(btnNext, false); @@ -333,6 +341,9 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { lv_obj_set_hidden(btnVolDown, true); lv_obj_set_hidden(btnVolUp, true); lv_label_set_text_fmt(txtSwapControls, "%s Volume Controls", Symbols::swap); + lv_obj_set_width(btnSwapControls, lv_obj_get_width(txtSwapControls) + 18); // +padding + lv_obj_set_height(btnSwapControls, lv_obj_get_height(txtSwapControls) + 8); // +padding + } } } From 4ed2d1872ed4925a55cc9bdf4aa0f19f09e85e9f Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Fri, 22 Aug 2025 18:21:39 +0200 Subject: [PATCH 34/67] Different version of the music app, where all buttons are on one screen --- src/displayapp/screens/Music.cpp | 28 +++++++++++++++++----------- src/displayapp/screens/Music.h | 4 ++-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index ea9af54ddc..c06f857eae 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -64,28 +64,26 @@ Music::Music(Pinetime::Controllers::MusicService& music, btnVolDown = lv_btn_create(lv_scr_act(), nullptr); btnVolDown->user_data = this; lv_obj_set_event_cb(btnVolDown, event_handler); - lv_obj_set_size(btnVolDown, 76, 76); + lv_obj_set_size(btnVolDown, 115, 50); lv_obj_align(btnVolDown, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_obj_add_style(btnVolDown, LV_STATE_DEFAULT, &btn_style); label = lv_label_create(btnVolDown, nullptr); lv_label_set_text_static(label, Symbols::volumDown); - lv_obj_set_hidden(btnVolDown, true); btnVolUp = lv_btn_create(lv_scr_act(), nullptr); btnVolUp->user_data = this; lv_obj_set_event_cb(btnVolUp, event_handler); - lv_obj_set_size(btnVolUp, 76, 76); + lv_obj_set_size(btnVolUp, 115, 50); lv_obj_align(btnVolUp, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); lv_obj_add_style(btnVolUp, LV_STATE_DEFAULT, &btn_style); label = lv_label_create(btnVolUp, nullptr); lv_label_set_text_static(label, Symbols::volumUp); - lv_obj_set_hidden(btnVolUp, true); btnPrev = lv_btn_create(lv_scr_act(), nullptr); btnPrev->user_data = this; lv_obj_set_event_cb(btnPrev, event_handler); lv_obj_set_size(btnPrev, 76, 76); - lv_obj_align(btnPrev, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_align(btnPrev, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, -56); lv_obj_add_style(btnPrev, LV_STATE_DEFAULT, &btn_style); label = lv_label_create(btnPrev, nullptr); lv_label_set_text_static(label, Symbols::stepBackward); @@ -94,7 +92,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, btnNext->user_data = this; lv_obj_set_event_cb(btnNext, event_handler); lv_obj_set_size(btnNext, 76, 76); - lv_obj_align(btnNext, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + lv_obj_align(btnNext, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, -56); lv_obj_add_style(btnNext, LV_STATE_DEFAULT, &btn_style); label = lv_label_create(btnNext, nullptr); lv_label_set_text_static(label, Symbols::stepForward); @@ -103,13 +101,15 @@ Music::Music(Pinetime::Controllers::MusicService& music, btnPlayPause->user_data = this; lv_obj_set_event_cb(btnPlayPause, event_handler); lv_obj_set_size(btnPlayPause, 76, 76); - lv_obj_align(btnPlayPause, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_obj_align(btnPlayPause, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, -56); lv_obj_add_style(btnPlayPause, LV_STATE_DEFAULT, &btn_style); txtPlayPause = lv_label_create(btnPlayPause, nullptr); lv_label_set_text_static(txtPlayPause, Symbols::play); - // top anchor for the whole stack, move this and everything follows - constexpr int16_t BASE_Y = -90; // was txtTrack's previous y, 70 looks good for current default + // I'm using the txtTrack label as the top anchor for the whole lot + // of song, artist, progress bar and duration text (0:00 and -0:00) so + // its much easier to move that around and mess with the buttons + constexpr int16_t BASE_Y = -100; txtTrack = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC); @@ -118,7 +118,6 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_set_width(txtTrack, LV_HOR_RES); lv_label_set_text_static(txtTrack, ""); - // 27px below txtTrack (12 + 15 previously), hard coded txtArtist = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC); lv_obj_align(txtArtist, txtTrack, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); @@ -127,7 +126,6 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_label_set_text_static(txtArtist, ""); lv_obj_set_style_local_text_color(txtArtist, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - // bar sits 36px below txtArtist (to match old layout) barTrackDuration = lv_bar_create(lv_scr_act(), nullptr); lv_obj_set_style_local_bg_color(barTrackDuration, LV_BAR_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_style_local_bg_color(barTrackDuration, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Colors::lightGray); @@ -155,6 +153,9 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_set_width(txtTrackDuration, LV_HOR_RES); lv_obj_set_style_local_text_color(txtTrackDuration, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + // Only commented out until we figure out the final version of this over on GitHub. Can be fully removed after that + + /* // status time at the very top, keep independent of the chain labelTime = lv_label_create(lv_scr_act(), nullptr); lv_label_set_align(labelTime, LV_LABEL_ALIGN_CENTER); @@ -175,6 +176,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_set_height(btnSwapControls, lv_obj_get_height(txtSwapControls) + 8); // +padding lv_obj_align(btnSwapControls, nullptr, LV_ALIGN_CENTER, 0, 20); lv_obj_set_auto_realign(btnSwapControls, true); + */ /* Init animation @@ -322,6 +324,8 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { } } else if (obj == btnNext) { musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT); + // Only commented out until we figure out the final version of this over on GitHub. Can be fully removed after that + /* } else if (obj == btnSwapControls) { showingVolumeControls = !showingVolumeControls; // flip the state @@ -345,12 +349,14 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { lv_obj_set_height(btnSwapControls, lv_obj_get_height(txtSwapControls) + 8); // +padding } + */ } } } bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) { switch (event) { + // Only commented out until we figure out the final version of this over on GitHub. Can be fully removed after that /* case TouchEvents::SwipeUp: { lv_obj_set_hidden(btnVolDown, false); diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index ff2fd2ea51..e0f6a936a3 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -56,11 +56,11 @@ namespace Pinetime { lv_obj_t* btnNext; lv_obj_t* btnVolDown; lv_obj_t* btnVolUp; - lv_obj_t* btnSwapControls; + // lv_obj_t* btnSwapControls; lv_obj_t* txtArtist; lv_obj_t* txtTrack; lv_obj_t* txtPlayPause; - lv_obj_t* txtSwapControls; + // lv_obj_t* txtSwapControls; lv_obj_t* labelTime; lv_obj_t* imgDisc; From e02a795a1a05eb4127a217b887a86b50c0bc50db Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Fri, 22 Aug 2025 22:50:38 +0200 Subject: [PATCH 35/67] another UI iteration, my favorite (volume buttons above track buttons) --- src/displayapp/screens/Music.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index c06f857eae..63d55d5c74 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -65,7 +65,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, btnVolDown->user_data = this; lv_obj_set_event_cb(btnVolDown, event_handler); lv_obj_set_size(btnVolDown, 115, 50); - lv_obj_align(btnVolDown, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_align(btnVolDown, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, -86); lv_obj_add_style(btnVolDown, LV_STATE_DEFAULT, &btn_style); label = lv_label_create(btnVolDown, nullptr); lv_label_set_text_static(label, Symbols::volumDown); @@ -74,7 +74,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, btnVolUp->user_data = this; lv_obj_set_event_cb(btnVolUp, event_handler); lv_obj_set_size(btnVolUp, 115, 50); - lv_obj_align(btnVolUp, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + lv_obj_align(btnVolUp, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, -86); lv_obj_add_style(btnVolUp, LV_STATE_DEFAULT, &btn_style); label = lv_label_create(btnVolUp, nullptr); lv_label_set_text_static(label, Symbols::volumUp); @@ -83,7 +83,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, btnPrev->user_data = this; lv_obj_set_event_cb(btnPrev, event_handler); lv_obj_set_size(btnPrev, 76, 76); - lv_obj_align(btnPrev, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, -56); + lv_obj_align(btnPrev, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_obj_add_style(btnPrev, LV_STATE_DEFAULT, &btn_style); label = lv_label_create(btnPrev, nullptr); lv_label_set_text_static(label, Symbols::stepBackward); @@ -92,7 +92,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, btnNext->user_data = this; lv_obj_set_event_cb(btnNext, event_handler); lv_obj_set_size(btnNext, 76, 76); - lv_obj_align(btnNext, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, -56); + lv_obj_align(btnNext, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); lv_obj_add_style(btnNext, LV_STATE_DEFAULT, &btn_style); label = lv_label_create(btnNext, nullptr); lv_label_set_text_static(label, Symbols::stepForward); @@ -101,7 +101,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, btnPlayPause->user_data = this; lv_obj_set_event_cb(btnPlayPause, event_handler); lv_obj_set_size(btnPlayPause, 76, 76); - lv_obj_align(btnPlayPause, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, -56); + lv_obj_align(btnPlayPause, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); lv_obj_add_style(btnPlayPause, LV_STATE_DEFAULT, &btn_style); txtPlayPause = lv_label_create(btnPlayPause, nullptr); lv_label_set_text_static(txtPlayPause, Symbols::play); @@ -109,7 +109,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, // I'm using the txtTrack label as the top anchor for the whole lot // of song, artist, progress bar and duration text (0:00 and -0:00) so // its much easier to move that around and mess with the buttons - constexpr int16_t BASE_Y = -100; + constexpr int16_t BASE_Y = -110; txtTrack = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC); @@ -231,7 +231,7 @@ void Music::Refresh() { UpdateLength(); } - lv_label_set_text(labelTime, dateTimeController.FormattedTime().c_str()); + //lv_label_set_text(labelTime, dateTimeController.FormattedTime().c_str()); bleState = bleController.IsConnected(); bleRadioEnabled = bleController.IsRadioEnabled(); From e2514b05d1345bc1dbac1c60edaefc5be275a5b5 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Sat, 23 Aug 2025 18:41:05 +0200 Subject: [PATCH 36/67] version with buttons up top --- src/displayapp/screens/Music.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 63d55d5c74..7027172298 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -64,8 +64,8 @@ Music::Music(Pinetime::Controllers::MusicService& music, btnVolDown = lv_btn_create(lv_scr_act(), nullptr); btnVolDown->user_data = this; lv_obj_set_event_cb(btnVolDown, event_handler); - lv_obj_set_size(btnVolDown, 115, 50); - lv_obj_align(btnVolDown, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, -86); + lv_obj_set_size(btnVolDown, 117, 60); + lv_obj_align(btnVolDown, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); lv_obj_add_style(btnVolDown, LV_STATE_DEFAULT, &btn_style); label = lv_label_create(btnVolDown, nullptr); lv_label_set_text_static(label, Symbols::volumDown); @@ -73,8 +73,8 @@ Music::Music(Pinetime::Controllers::MusicService& music, btnVolUp = lv_btn_create(lv_scr_act(), nullptr); btnVolUp->user_data = this; lv_obj_set_event_cb(btnVolUp, event_handler); - lv_obj_set_size(btnVolUp, 115, 50); - lv_obj_align(btnVolUp, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, -86); + lv_obj_set_size(btnVolUp, 117, 60); + lv_obj_align(btnVolUp, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); lv_obj_add_style(btnVolUp, LV_STATE_DEFAULT, &btn_style); label = lv_label_create(btnVolUp, nullptr); lv_label_set_text_static(label, Symbols::volumUp); @@ -109,14 +109,14 @@ Music::Music(Pinetime::Controllers::MusicService& music, // I'm using the txtTrack label as the top anchor for the whole lot // of song, artist, progress bar and duration text (0:00 and -0:00) so // its much easier to move that around and mess with the buttons - constexpr int16_t BASE_Y = -110; + constexpr int16_t BASE_Y = -45; // -45 for buttons at the top txtTrack = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC); lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 0, BASE_Y); lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtTrack, LV_HOR_RES); - lv_label_set_text_static(txtTrack, ""); + lv_label_set_text_static(txtTrack, "Some Track"); txtArtist = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC); From 1f902b165ed31f04ac0d6e39f2e965690861a749 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 25 Aug 2025 20:25:24 +0200 Subject: [PATCH 37/67] clean up code --- src/displayapp/screens/Music.cpp | 152 +++++-------------------------- 1 file changed, 24 insertions(+), 128 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 7027172298..0b5e16f3b0 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -108,7 +108,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, // I'm using the txtTrack label as the top anchor for the whole lot // of song, artist, progress bar and duration text (0:00 and -0:00) so - // its much easier to move that around and mess with the buttons + // its much easier to move that around and mess with the buttons separately constexpr int16_t BASE_Y = -45; // -45 for buttons at the top txtTrack = lv_label_create(lv_scr_act(), nullptr); @@ -116,7 +116,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 0, BASE_Y); lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID); lv_obj_set_width(txtTrack, LV_HOR_RES); - lv_label_set_text_static(txtTrack, "Some Track"); + lv_label_set_text_static(txtTrack, ""); txtArtist = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL_CIRC); @@ -136,7 +136,6 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_bar_set_range(barTrackDuration, 0, 1000); lv_bar_set_value(barTrackDuration, 0, LV_ANIM_OFF); - // time labels 20px below the bar, left and right aligned txtCurrentPosition = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtCurrentPosition, LV_LABEL_LONG_SROLL); lv_obj_align(txtCurrentPosition, barTrackDuration, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); @@ -153,42 +152,6 @@ Music::Music(Pinetime::Controllers::MusicService& music, lv_obj_set_width(txtTrackDuration, LV_HOR_RES); lv_obj_set_style_local_text_color(txtTrackDuration, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - // Only commented out until we figure out the final version of this over on GitHub. Can be fully removed after that - - /* - // status time at the very top, keep independent of the chain - labelTime = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_align(labelTime, LV_LABEL_ALIGN_CENTER); - lv_obj_align(labelTime, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0); - lv_obj_set_auto_realign(labelTime, true); - lv_label_set_text_static(labelTime, "09:41"); - lv_obj_set_hidden(labelTime, true); - - btnSwapControls = lv_btn_create(lv_scr_act(), nullptr); - btnSwapControls->user_data = this; - lv_obj_set_event_cb(btnSwapControls, event_handler); - lv_obj_set_style_local_radius(btnSwapControls, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 20); - lv_obj_set_style_local_bg_color(btnSwapControls, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - txtSwapControls = lv_label_create(btnSwapControls, nullptr); - lv_label_set_text_fmt(txtSwapControls, "%s Volume Controls", Symbols::swap); - lv_obj_set_style_local_text_color(txtSwapControls, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - lv_obj_set_width(btnSwapControls, lv_obj_get_width(txtSwapControls) + 18); // +padding - lv_obj_set_height(btnSwapControls, lv_obj_get_height(txtSwapControls) + 8); // +padding - lv_obj_align(btnSwapControls, nullptr, LV_ALIGN_CENTER, 0, 20); - lv_obj_set_auto_realign(btnSwapControls, true); - */ - - - /* Init animation - imgDisc = lv_img_create(lv_scr_act(), nullptr); - lv_img_set_src_arr(imgDisc, &disc); - lv_obj_align(imgDisc, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); - - imgDiscAnim = lv_img_create(lv_scr_act(), nullptr); - lv_img_set_src_arr(imgDiscAnim, &disc_f_1); - lv_obj_align(imgDiscAnim, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0 - 32, 0); - */ - frameB = false; musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); @@ -203,6 +166,27 @@ Music::~Music() { } void Music::Refresh() { + bleState = bleController.IsConnected(); + bleRadioEnabled = bleController.IsRadioEnabled(); + if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { + if (bleState.Get() == false) { + lv_label_set_text_static(txtArtist, "Disconnected"); + lv_label_set_text_static(txtTrack, ""); + lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + } + else { + lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + } + } + if (artist != musicService.getArtist()) { artist = musicService.getArtist(); lv_label_set_text(txtArtist, artist.data()); @@ -230,51 +214,10 @@ void Music::Refresh() { totalLength = musicService.getTrackLength(); UpdateLength(); } - - //lv_label_set_text(labelTime, dateTimeController.FormattedTime().c_str()); - - bleState = bleController.IsConnected(); - bleRadioEnabled = bleController.IsRadioEnabled(); - if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { - if (bleState.Get() == false) { - lv_label_set_text_static(txtArtist, "Disconnected"); - lv_label_set_text_static(txtTrack, ""); - lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - } - else { - lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - } - } if (playing) { lv_label_set_text_static(txtPlayPause, Symbols::pause); - if (xTaskGetTickCount() - 1024 >= lastIncrement) { - - /* - if (frameB) { - lv_img_set_src(imgDiscAnim, &disc_f_1); - } else { - lv_img_set_src(imgDiscAnim, &disc_f_2); - } - frameB = !frameB; - */ - - if (currentPosition >= totalLength) { - // Let's assume the getTrack finished, paused when the timer ends - // and there's no new getTrack being sent to us - playing = false; - } - lastIncrement = xTaskGetTickCount(); - } } else { lv_label_set_text_static(txtPlayPause, Symbols::play); } @@ -296,7 +239,7 @@ void Music::UpdateLength() { } else { lv_label_set_text_fmt(txtCurrentPosition, "%d:%02d", (currentPosition / 60) % 100, (currentPosition % 60) % 100); lv_label_set_text_fmt(txtTrackDuration, "-%d:%02d", (remaining / 60) % 100, (remaining % 60) % 100); - lv_bar_set_range(barTrackDuration, 0, totalLength); + lv_bar_set_range(barTrackDuration, 0, totalLength > 0 ? totalLength : 1); lv_bar_set_value(barTrackDuration, currentPosition, LV_ANIM_OFF); } } @@ -324,59 +267,12 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { } } else if (obj == btnNext) { musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT); - // Only commented out until we figure out the final version of this over on GitHub. Can be fully removed after that - /* - } else if (obj == btnSwapControls) { - showingVolumeControls = !showingVolumeControls; // flip the state - - if (showingVolumeControls) { - // show volume buttons, hide track buttons - lv_obj_set_hidden(btnVolDown, false); - lv_obj_set_hidden(btnVolUp, false); - lv_obj_set_hidden(btnNext, true); - lv_obj_set_hidden(btnPrev, true); - lv_label_set_text_fmt(txtSwapControls, "%s Track Controls", Symbols::swap); - lv_obj_set_width(btnSwapControls, lv_obj_get_width(txtSwapControls) + 18); // +padding - lv_obj_set_height(btnSwapControls, lv_obj_get_height(txtSwapControls) + 8); // +padding - } else { - // show track buttons, hide volume buttons - lv_obj_set_hidden(btnNext, false); - lv_obj_set_hidden(btnPrev, false); - lv_obj_set_hidden(btnVolDown, true); - lv_obj_set_hidden(btnVolUp, true); - lv_label_set_text_fmt(txtSwapControls, "%s Volume Controls", Symbols::swap); - lv_obj_set_width(btnSwapControls, lv_obj_get_width(txtSwapControls) + 18); // +padding - lv_obj_set_height(btnSwapControls, lv_obj_get_height(txtSwapControls) + 8); // +padding - - } - */ } } } bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) { switch (event) { - // Only commented out until we figure out the final version of this over on GitHub. Can be fully removed after that - /* - case TouchEvents::SwipeUp: { - lv_obj_set_hidden(btnVolDown, false); - lv_obj_set_hidden(btnVolUp, false); - - lv_obj_set_hidden(btnNext, true); - lv_obj_set_hidden(btnPrev, true); - return true; - } - case TouchEvents::SwipeDown: { - if (lv_obj_get_hidden(btnNext)) { - lv_obj_set_hidden(btnNext, false); - lv_obj_set_hidden(btnPrev, false); - lv_obj_set_hidden(btnVolDown, true); - lv_obj_set_hidden(btnVolUp, true); - return true; - } - return false; - } - */ case TouchEvents::SwipeLeft: { musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT); return true; From 2201ee8ee10240bc85db1048935527adab63bf4c Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 25 Aug 2025 20:39:58 +0200 Subject: [PATCH 38/67] finally got a formatting extension, so this is hopefully the last formatting commit --- src/displayapp/screens/Music.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 0b5e16f3b0..efb661346e 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -49,12 +49,9 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ -Music::Music(Pinetime::Controllers::MusicService& music, - const Controllers::Ble& bleController, - Controllers::DateTime& dateTimeController) - : musicService(music), bleController {bleController}, - dateTimeController {dateTimeController} { - +Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController, Controllers::DateTime& dateTimeController) + : musicService(music), bleController {bleController}, dateTimeController {dateTimeController} { + lv_obj_t* label; lv_style_init(&btn_style); @@ -177,8 +174,7 @@ void Music::Refresh() { lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - } - else { + } else { lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); @@ -214,7 +210,6 @@ void Music::Refresh() { totalLength = musicService.getTrackLength(); UpdateLength(); } - if (playing) { lv_label_set_text_static(txtPlayPause, Symbols::pause); From 3e18fcb836d941cbb6775f3b0f21c224d061ef4c Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 25 Aug 2025 20:40:19 +0200 Subject: [PATCH 39/67] finally got a formatting extension, so this is hopefully the last formatting commit (ironically one more) --- src/displayapp/screens/Music.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index e0f6a936a3..29a0ef4a4e 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -36,9 +36,7 @@ namespace Pinetime { namespace Screens { class Music : public Screen { public: - Music(Pinetime::Controllers::MusicService& music, - const Controllers::Ble& bleController, - Controllers::DateTime& dateTimeController); + Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController, Controllers::DateTime& dateTimeController); ~Music() override; @@ -108,9 +106,7 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::music; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Music(*controllers.musicService, - controllers.bleController, - controllers.dateTimeController); + return new Screens::Music(*controllers.musicService, controllers.bleController, controllers.dateTimeController); }; static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { From 0b3427e00b69e55a2b610d2da514fb2729e8f66d Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 25 Aug 2025 20:55:36 +0200 Subject: [PATCH 40/67] some final spacing optimizations --- src/displayapp/screens/Music.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index efb661346e..776b592d3e 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -106,7 +106,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& // I'm using the txtTrack label as the top anchor for the whole lot // of song, artist, progress bar and duration text (0:00 and -0:00) so // its much easier to move that around and mess with the buttons separately - constexpr int16_t BASE_Y = -45; // -45 for buttons at the top + constexpr int16_t BASE_Y = -40; // -45 for buttons at the top txtTrack = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL_CIRC); @@ -129,7 +129,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& lv_obj_set_style_local_bg_opa(barTrackDuration, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100); lv_obj_set_style_local_radius(barTrackDuration, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_obj_set_size(barTrackDuration, 240, 10); - lv_obj_align(barTrackDuration, txtArtist, LV_ALIGN_OUT_BOTTOM_MID, 0, 14); + lv_obj_align(barTrackDuration, txtArtist, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); lv_bar_set_range(barTrackDuration, 0, 1000); lv_bar_set_value(barTrackDuration, 0, LV_ANIM_OFF); From b965144ad3ee13535e6cc263232d9a12fd337935 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 25 Aug 2025 21:01:35 +0200 Subject: [PATCH 41/67] remove some more (now) unused lines --- src/displayapp/screens/Music.cpp | 3 --- src/displayapp/screens/Music.h | 10 ---------- 2 files changed, 13 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 776b592d3e..ce0a83f96d 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -20,9 +20,6 @@ #include #include "displayapp/DisplayApp.h" #include "components/ble/MusicService.h" -#include "displayapp/icons/music/disc.c" -#include "displayapp/icons/music/disc_f_1.c" -#include "displayapp/icons/music/disc_f_2.c" #include "displayapp/InfiniTimeTheme.h" #include "components/ble/BleController.h" diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 29a0ef4a4e..4171a83ea3 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -54,12 +54,9 @@ namespace Pinetime { lv_obj_t* btnNext; lv_obj_t* btnVolDown; lv_obj_t* btnVolUp; - // lv_obj_t* btnSwapControls; lv_obj_t* txtArtist; lv_obj_t* txtTrack; lv_obj_t* txtPlayPause; - // lv_obj_t* txtSwapControls; - lv_obj_t* labelTime; lv_obj_t* imgDisc; lv_obj_t* imgDiscAnim; @@ -67,13 +64,8 @@ namespace Pinetime { lv_obj_t* txtCurrentPosition; lv_obj_t* barTrackDuration; - bool showingVolumeControls = false; - lv_style_t btn_style; - /** For the spinning disc animation */ - bool frameB; - Pinetime::Controllers::MusicService& musicService; const Controllers::Ble& bleController; Pinetime::Controllers::DateTime& dateTimeController; @@ -86,8 +78,6 @@ namespace Pinetime { int totalLength = 0; /** Current position in seconds */ int currentPosition; - /** Last time an animation update or timer was incremented */ - TickType_t lastIncrement = 0; bool playing; From a1cef42322e5ac17c057dc9a8c98d6d691dc6ceb Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 25 Aug 2025 23:29:07 +0200 Subject: [PATCH 42/67] lots of code optimization, mainly to get the reconnection smoother --- .vscode/settings.json | 3 +- src/displayapp/screens/Music.cpp | 77 +++++++++++++++++++------------- src/displayapp/screens/Music.h | 8 ++++ 3 files changed, 55 insertions(+), 33 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a7b04eea3c..519d4471f9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,6 +65,7 @@ "stdexcept": "cpp", "streambuf": "cpp", "cinttypes": "cpp", - "typeinfo": "cpp" + "typeinfo": "cpp", + "span": "cpp" } } diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index ce0a83f96d..176f68af82 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -146,8 +146,6 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& lv_obj_set_width(txtTrackDuration, LV_HOR_RES); lv_obj_set_style_local_text_color(txtTrackDuration, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - frameB = false; - musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); @@ -161,58 +159,73 @@ Music::~Music() { void Music::Refresh() { bleState = bleController.IsConnected(); - bleRadioEnabled = bleController.IsRadioEnabled(); - if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { - if (bleState.Get() == false) { - lv_label_set_text_static(txtArtist, "Disconnected"); - lv_label_set_text_static(txtTrack, ""); - lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + if (bleState.Get() == false) { + SetDisconnectedUI(); + lastConnected = false; + } else { + if (!lastConnected) { + // just reconnected + musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); + SetConnectedUI(); + RefreshTrackInfo(true); } else { - lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + RefreshTrackInfo(false); } + lastConnected = true; } +} - if (artist != musicService.getArtist()) { +void Music::SetDisconnectedUI() { + lv_label_set_text_static(txtArtist, "Disconnected"); + lv_label_set_text_static(txtTrack, ""); + lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_label_set_text_static(txtCurrentPosition, "--:--"); + lv_label_set_text_static(txtTrackDuration, "--:--"); + lv_bar_set_range(barTrackDuration, 0, 1000); + lv_bar_set_value(barTrackDuration, 0, LV_ANIM_OFF); +} + +void Music::SetConnectedUI() { + lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); +} + +void Music::RefreshTrackInfo(bool force) { + if (force || playing != musicService.isPlaying()) { + playing = musicService.isPlaying(); + lv_label_set_text_static(txtPlayPause, playing ? Symbols::pause : Symbols::play); + } + + if (force || artist != musicService.getArtist()) { artist = musicService.getArtist(); lv_label_set_text(txtArtist, artist.data()); } - if (track != musicService.getTrack()) { + if (force || track != musicService.getTrack()) { track = musicService.getTrack(); lv_label_set_text(txtTrack, track.data()); } - if (album != musicService.getAlbum()) { + if (force || album != musicService.getAlbum()) { album = musicService.getAlbum(); } - if (playing != musicService.isPlaying()) { - playing = musicService.isPlaying(); - } - - if (currentPosition != musicService.getProgress()) { + if (force || currentPosition != musicService.getProgress()) { currentPosition = musicService.getProgress(); UpdateLength(); } - if (totalLength != musicService.getTrackLength()) { + if (force || totalLength != musicService.getTrackLength()) { totalLength = musicService.getTrackLength(); UpdateLength(); } - - if (playing) { - lv_label_set_text_static(txtPlayPause, Symbols::pause); - } else { - lv_label_set_text_static(txtPlayPause, Symbols::play); - } } void Music::UpdateLength() { diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 4171a83ea3..8d2bbe110e 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -49,6 +49,12 @@ namespace Pinetime { void UpdateLength(); + void RefreshTrackInfo(bool force); + + void SetDisconnectedUI(); + + void SetConnectedUI(); + lv_obj_t* btnPrev; lv_obj_t* btnPlayPause; lv_obj_t* btnNext; @@ -81,6 +87,8 @@ namespace Pinetime { bool playing; + bool lastConnected = false; + lv_task_t* taskRefresh; Utility::DirtyValue bleState {}; From 4d34f706d65efaf2c018462f5cd65d72faacf9c5 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Sat, 13 Sep 2025 13:48:38 +0200 Subject: [PATCH 43/67] remove unused emoji --- src/displayapp/fonts/fonts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index f6567f3f6e..fea3160572 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -7,7 +7,7 @@ }, { "file": "FontAwesome5-Solid+Brands+Regular.woff", - "range": "0xf079, 0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf1ec, 0xf55a" + "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf1ec, 0xf55a" } ], "bpp": 1, From 08c5596a45fc45def6b55f4a75d18e25e4336752 Mon Sep 17 00:00:00 2001 From: Titus <154823939+tituscmd@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:09:20 +0100 Subject: [PATCH 44/67] Update Music.cpp Co-authored-by: mark9064 <30447455+mark9064@users.noreply.github.com> --- src/displayapp/screens/Music.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 176f68af82..096d4d1810 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -159,7 +159,7 @@ Music::~Music() { void Music::Refresh() { bleState = bleController.IsConnected(); - if (bleState.Get() == false) { + if (!bleState.Get()) { SetDisconnectedUI(); lastConnected = false; } else { From 799f10ea6b495c8b8ad50a5ac2ba7fdd8e42ecd0 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Mon, 15 Dec 2025 23:38:48 +0000 Subject: [PATCH 45/67] Split oversized SPI reads --- src/drivers/SpiMaster.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 19422ef3c3..5002ea37d0 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -161,6 +161,7 @@ void SpiMaster::OnStartedEvent() { } void SpiMaster::PrepareTx(const uint32_t bufferAddress, const size_t size) { + ASSERT(size < 256); spiBaseAddress->TXD.PTR = bufferAddress; spiBaseAddress->TXD.MAXCNT = size; spiBaseAddress->TXD.LIST = 0; @@ -171,6 +172,7 @@ void SpiMaster::PrepareTx(const uint32_t bufferAddress, const size_t size) { } void SpiMaster::PrepareRx(const uint32_t bufferAddress, const size_t size) { + ASSERT(size < 256); spiBaseAddress->TXD.PTR = 0; spiBaseAddress->TXD.MAXCNT = 0; spiBaseAddress->TXD.LIST = 0; @@ -240,12 +242,17 @@ bool SpiMaster::Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data spiBaseAddress->TASKS_START = 1; while (spiBaseAddress->EVENTS_END == 0) ; + while (dataSize > 0) { + size_t readSize = std::min(dataSize, 255U); + PrepareRx((uint32_t) data, readSize); + spiBaseAddress->TASKS_START = 1; - PrepareRx((uint32_t) data, dataSize); - spiBaseAddress->TASKS_START = 1; - - while (spiBaseAddress->EVENTS_END == 0) - ; + while (spiBaseAddress->EVENTS_END == 0) { + ; + } + data += readSize; + dataSize -= readSize; + } nrf_gpio_pin_set(this->pinCsn); xSemaphoreGive(mutex); From dec9f4a6953ad0a76c04b5d25aec24221ac3ecea Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 22 Dec 2025 19:57:12 +0100 Subject: [PATCH 46/67] react to review, most notably change artist, track and album to use DirtyValue --- .vscode/settings.json | 19 ++++++++++++++++++- src/displayapp/screens/Music.cpp | 23 ++++++++++++----------- src/displayapp/screens/Music.h | 11 +++++------ src/displayapp/screens/Symbols.h | 1 - 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 519d4471f9..3d8ecc68e2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -66,6 +66,23 @@ "streambuf": "cpp", "cinttypes": "cpp", "typeinfo": "cpp", - "span": "cpp" + "charconv": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstring": "cpp", + "list": "cpp", + "netfwd": "cpp", + "iomanip": "cpp", + "mutex": "cpp", + "numbers": "cpp", + "semaphore": "cpp", + "span": "cpp", + "stop_token": "cpp", + "thread": "cpp", + "cfenv": "cpp", + "variant": "cpp", + "format": "cpp", + "__nullptr": "cpp" } } diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 176f68af82..3a62d467dc 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -46,8 +46,8 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { * * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration */ -Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController, Controllers::DateTime& dateTimeController) - : musicService(music), bleController {bleController}, dateTimeController {dateTimeController} { +Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController) + : musicService(music), bleController {bleController} { lv_obj_t* label; @@ -203,18 +203,18 @@ void Music::RefreshTrackInfo(bool force) { lv_label_set_text_static(txtPlayPause, playing ? Symbols::pause : Symbols::play); } - if (force || artist != musicService.getArtist()) { - artist = musicService.getArtist(); - lv_label_set_text(txtArtist, artist.data()); + artist = musicService.getArtist(); + if (force || artist.IsUpdated()) { + lv_label_set_text(txtArtist, artist.Get().data()); } - if (force || track != musicService.getTrack()) { - track = musicService.getTrack(); - lv_label_set_text(txtTrack, track.data()); + track = musicService.getTrack(); + if (force || track.IsUpdated()) { + lv_label_set_text(txtTrack, track.Get().data()); } - if (force || album != musicService.getAlbum()) { - album = musicService.getAlbum(); + album = musicService.getAlbum(); + if (force || album.IsUpdated()) { } if (force || currentPosition != musicService.getProgress()) { @@ -230,8 +230,9 @@ void Music::RefreshTrackInfo(bool force) { void Music::UpdateLength() { int remaining = totalLength - currentPosition; - if (remaining < 0) + if (remaining < 0) { remaining = 0; + } if (totalLength > (99 * 60 * 60)) { lv_label_set_text_static(txtCurrentPosition, "Inf"); diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 8d2bbe110e..a0a41d111f 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -36,7 +36,7 @@ namespace Pinetime { namespace Screens { class Music : public Screen { public: - Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController, Controllers::DateTime& dateTimeController); + Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController); ~Music() override; @@ -74,11 +74,10 @@ namespace Pinetime { Pinetime::Controllers::MusicService& musicService; const Controllers::Ble& bleController; - Pinetime::Controllers::DateTime& dateTimeController; - std::string artist; - std::string album; - std::string track; + Utility::DirtyValue artist; + Utility::DirtyValue album; + Utility::DirtyValue track; /** Total length in seconds */ int totalLength = 0; @@ -104,7 +103,7 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::music; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Music(*controllers.musicService, controllers.bleController, controllers.dateTimeController); + return new Screens::Music(*controllers.musicService, controllers.bleController); }; static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index 4482fb0be2..40699b3d65 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -41,7 +41,6 @@ namespace Pinetime { static constexpr const char* sleep = "\xEE\xBD\x84"; static constexpr const char* calculator = "\xEF\x87\xAC"; static constexpr const char* backspace = "\xEF\x95\x9A"; - static constexpr const char* swap = "\xef\x81\xb9"; // fontawesome_weathericons.c // static constexpr const char* sun = "\xEF\x86\x85"; From 72911f41b5e5f868951e25d1c3066357feddf929 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 22 Dec 2025 20:05:35 +0100 Subject: [PATCH 47/67] use bleState.isUpdated() instead of manual lastConnected approach --- src/displayapp/screens/Music.cpp | 23 ++++++++++++++--------- src/displayapp/screens/Music.h | 2 -- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 4ac6d02637..f912b8911b 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -159,19 +159,24 @@ Music::~Music() { void Music::Refresh() { bleState = bleController.IsConnected(); - if (!bleState.Get()) { - SetDisconnectedUI(); - lastConnected = false; - } else { - if (!lastConnected) { - // just reconnected + + if (bleState.IsUpdated()) { + if (!bleState.Get()) { + // just disconnected + SetDisconnectedUI(); + return; + } else { + // just connected musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); SetConnectedUI(); RefreshTrackInfo(true); - } else { - RefreshTrackInfo(false); + return; } - lastConnected = true; + } + + // still connected, no state change + if (bleState.Get()) { + RefreshTrackInfo(false); } } diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index a0a41d111f..827e9dc63f 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -86,8 +86,6 @@ namespace Pinetime { bool playing; - bool lastConnected = false; - lv_task_t* taskRefresh; Utility::DirtyValue bleState {}; From c904749305fe98cef6d399914e768231678e32e8 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 22 Dec 2025 20:41:55 +0100 Subject: [PATCH 48/67] change behavior of Refresh cycle --- src/displayapp/screens/Music.cpp | 31 ++++++++++++++++--------------- src/displayapp/screens/Music.h | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index d18b3d83a3..f5a139a6f7 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -146,8 +146,6 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& lv_obj_set_width(txtTrackDuration, LV_HOR_RES); lv_obj_set_style_local_text_color(txtTrackDuration, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); - musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); - taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); } @@ -161,22 +159,21 @@ void Music::Refresh() { bleState = bleController.IsConnected(); if (bleState.IsUpdated()) { - if (!bleState.Get()) { - // just disconnected + const bool connected = bleState.Get(); + + if (!connected) { SetDisconnectedUI(); return; } else { - // just connected musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); SetConnectedUI(); - RefreshTrackInfo(true); + RefreshTrackInfo(); return; } } - // still connected, no state change if (bleState.Get()) { - RefreshTrackInfo(false); + RefreshTrackInfo(); } } @@ -192,6 +189,10 @@ void Music::SetDisconnectedUI() { lv_label_set_text_static(txtTrackDuration, "--:--"); lv_bar_set_range(barTrackDuration, 0, 1000); lv_bar_set_value(barTrackDuration, 0, LV_ANIM_OFF); + // empty these so they are successfully updated on reconnect because of how DirtyValue works + artist = ""; + track = ""; + album = ""; } void Music::SetConnectedUI() { @@ -202,32 +203,32 @@ void Music::SetConnectedUI() { lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); } -void Music::RefreshTrackInfo(bool force) { - if (force || playing != musicService.isPlaying()) { +void Music::RefreshTrackInfo() { + if (playing != musicService.isPlaying()) { playing = musicService.isPlaying(); lv_label_set_text_static(txtPlayPause, playing ? Symbols::pause : Symbols::play); } artist = musicService.getArtist(); - if (force || artist.IsUpdated()) { + if (artist.IsUpdated()) { lv_label_set_text(txtArtist, artist.Get().data()); } track = musicService.getTrack(); - if (force || track.IsUpdated()) { + if (track.IsUpdated()) { lv_label_set_text(txtTrack, track.Get().data()); } album = musicService.getAlbum(); - if (force || album.IsUpdated()) { + if (album.IsUpdated()) { } - if (force || currentPosition != musicService.getProgress()) { + if (currentPosition != musicService.getProgress()) { currentPosition = musicService.getProgress(); UpdateLength(); } - if (force || totalLength != musicService.getTrackLength()) { + if (totalLength != musicService.getTrackLength()) { totalLength = musicService.getTrackLength(); UpdateLength(); } diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 20c730ffa4..c0f0063211 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -50,7 +50,7 @@ namespace Pinetime { void UpdateLength(); - void RefreshTrackInfo(bool force); + void RefreshTrackInfo(); void SetDisconnectedUI(); From 05cec881ebb6865ed0f7729852a0c36e30e6dd5f Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 22 Dec 2025 20:51:19 +0100 Subject: [PATCH 49/67] I'll never understand why it does this --- .vscode/settings.json | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3d8ecc68e2..a7b04eea3c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,24 +65,6 @@ "stdexcept": "cpp", "streambuf": "cpp", "cinttypes": "cpp", - "typeinfo": "cpp", - "charconv": "cpp", - "compare": "cpp", - "concepts": "cpp", - "condition_variable": "cpp", - "cstring": "cpp", - "list": "cpp", - "netfwd": "cpp", - "iomanip": "cpp", - "mutex": "cpp", - "numbers": "cpp", - "semaphore": "cpp", - "span": "cpp", - "stop_token": "cpp", - "thread": "cpp", - "cfenv": "cpp", - "variant": "cpp", - "format": "cpp", - "__nullptr": "cpp" + "typeinfo": "cpp" } } From 5e3f4831334dc17ad9cb5d36172b678693f93915 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Sat, 27 Dec 2025 22:36:19 +0100 Subject: [PATCH 50/67] remove album as member, remove unused members --- src/displayapp/screens/Music.cpp | 5 ----- src/displayapp/screens/Music.h | 4 ---- 2 files changed, 9 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index f5a139a6f7..05d31b7723 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -192,7 +192,6 @@ void Music::SetDisconnectedUI() { // empty these so they are successfully updated on reconnect because of how DirtyValue works artist = ""; track = ""; - album = ""; } void Music::SetConnectedUI() { @@ -219,10 +218,6 @@ void Music::RefreshTrackInfo() { lv_label_set_text(txtTrack, track.Get().data()); } - album = musicService.getAlbum(); - if (album.IsUpdated()) { - } - if (currentPosition != musicService.getProgress()) { currentPosition = musicService.getProgress(); UpdateLength(); diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index c0f0063211..768c7105db 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -65,8 +65,6 @@ namespace Pinetime { lv_obj_t* txtTrack; lv_obj_t* txtPlayPause; - lv_obj_t* imgDisc; - lv_obj_t* imgDiscAnim; lv_obj_t* txtTrackDuration; lv_obj_t* txtCurrentPosition; lv_obj_t* barTrackDuration; @@ -77,7 +75,6 @@ namespace Pinetime { const Controllers::Ble& bleController; Utility::DirtyValue artist; - Utility::DirtyValue album; Utility::DirtyValue track; /** Total length in seconds */ @@ -90,7 +87,6 @@ namespace Pinetime { lv_task_t* taskRefresh; Utility::DirtyValue bleState {}; - Utility::DirtyValue bleRadioEnabled {}; /** Watchapp */ }; From 35094e7d04304b0fa95b925da1e89fecf745b81f Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Sun, 28 Dec 2025 00:51:51 +0100 Subject: [PATCH 51/67] remove now unused music disc files --- src/displayapp/icons/music/disc.c | 110 ------------------------ src/displayapp/icons/music/disc.png | Bin 516 -> 0 bytes src/displayapp/icons/music/disc_f_1.c | 79 ----------------- src/displayapp/icons/music/disc_f_1.png | Bin 200 -> 0 bytes src/displayapp/icons/music/disc_f_2.c | 79 ----------------- src/displayapp/icons/music/disc_f_2.png | Bin 197 -> 0 bytes 6 files changed, 268 deletions(-) delete mode 100644 src/displayapp/icons/music/disc.c delete mode 100644 src/displayapp/icons/music/disc.png delete mode 100644 src/displayapp/icons/music/disc_f_1.c delete mode 100644 src/displayapp/icons/music/disc_f_1.png delete mode 100644 src/displayapp/icons/music/disc_f_2.c delete mode 100644 src/displayapp/icons/music/disc_f_2.png diff --git a/src/displayapp/icons/music/disc.c b/src/displayapp/icons/music/disc.c deleted file mode 100644 index 0957873f87..0000000000 --- a/src/displayapp/icons/music/disc.c +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (C) 2020 Avamander - - This file is part of InfiniTime. - - InfiniTime is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - InfiniTime is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#pragma once - -#include "lvgl/lvgl.h" - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_DISC -#define LV_ATTRIBUTE_IMG_DISC -#endif - -const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_DISC uint8_t disc_map[] = { - 0xbd, 0xc1, 0xbe, 0xff, /* Color of index 0: foreground */ - 0x00, 0x00, 0x00, 0x00, /* Color of index 1: background */ - - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x0f, 0xf8, 0x07, 0xff, 0xff, - 0xff, 0xff, 0xc0, 0xff, 0xff, 0x81, 0xff, 0xff, - 0xff, 0xff, 0x07, 0xff, 0xff, 0xf0, 0x7f, 0xff, - 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xfc, 0x1f, 0xff, - 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0x0f, 0xff, - 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, - 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, - 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, - 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, - 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, - 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, - 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, - 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, - 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, - 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, - 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, - 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, - 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, - 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, - 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, - 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, - 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, - 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0x8f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xf8, - 0x9f, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xfc, - 0x9f, 0xff, 0xff, 0xe3, 0xe3, 0xff, 0xff, 0xfc, - 0x9f, 0xff, 0xff, 0xe7, 0xf3, 0xff, 0xff, 0xfc, - 0x9f, 0xff, 0xff, 0xe7, 0xf3, 0xff, 0xff, 0xfc, - 0x9f, 0xff, 0xff, 0xe7, 0xf3, 0xff, 0xff, 0xfc, - 0x9f, 0xff, 0xff, 0xe7, 0xf3, 0xff, 0xff, 0xfc, - 0x9f, 0xff, 0xff, 0xe7, 0xf3, 0xff, 0xff, 0xfc, - 0x9f, 0xff, 0xff, 0xe3, 0xe3, 0xff, 0xff, 0xfc, - 0x9f, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xfc, - 0x8f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xf8, - 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, - 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, - 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, - 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, - 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, - 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, - 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, - 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, - 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, - 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, - 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, - 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, - 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, - 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, - 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, - 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, - 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, - 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0x0f, 0xff, - 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xfc, 0x1f, 0xff, - 0xff, 0xff, 0x07, 0xff, 0xff, 0xf0, 0x7f, 0xff, - 0xff, 0xff, 0xc0, 0xff, 0xff, 0x81, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x0f, 0xf8, 0x07, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, -}; - -const lv_img_dsc_t disc = { - { - LV_IMG_CF_INDEXED_1BIT, - 0, - 0, - 64, - 64 - }, - 520, - disc_map -}; \ No newline at end of file diff --git a/src/displayapp/icons/music/disc.png b/src/displayapp/icons/music/disc.png deleted file mode 100644 index 699734fb9c7f8b8069857730bce2860cfb672460..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 516 zcmV+f0{i`mP)PbC2?f~SxGC+8PfjXqWdAblQ}XqK`B^fNYxgc~{ujzB`qcprITLfgK;QJ=_V@aTeqCh%1X z$N_h=GbBlbnyoQxziobRka~bJyE)2nk{n`pxFsPRN%aHbSs=<6z5CMu0000. -*/ -#pragma once - -#include "lvgl/lvgl.h" - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_DISC_F_1 -#define LV_ATTRIBUTE_IMG_DISC_F_1 -#endif - -const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_DISC_F_1 uint8_t disc_f_1_map[] = { - 0xbd, 0xc1, 0xbe, 0xff, /* Color of index 0: foreground */ - 0x00, 0x00, 0x00, 0x00, /* Color of index 1: background */ - - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, - 0xff, 0xff, 0xf0, 0x0f, - 0xff, 0xff, 0xc0, 0xff, - 0xff, 0xff, 0x07, 0xff, - 0xff, 0xfc, 0x1f, 0xff, - 0xff, 0xf8, 0x7f, 0xff, - 0xff, 0xf0, 0xff, 0xff, - 0xff, 0xe3, 0xff, 0xff, - 0xff, 0xc7, 0xf3, 0xff, - 0xff, 0x8f, 0xc3, 0xff, - 0xff, 0x1f, 0x87, 0xff, - 0xfe, 0x3f, 0x0f, 0xff, - 0xfc, 0x7e, 0x1f, 0xff, - 0xfc, 0x7c, 0x3f, 0xff, - 0xf8, 0xfc, 0x7f, 0xff, - 0xf9, 0xfc, 0xff, 0xff, - 0xf1, 0xff, 0xff, 0xff, - 0xf3, 0xff, 0xff, 0xff, - 0xe3, 0xff, 0xff, 0xff, - 0xe7, 0xff, 0xff, 0xff, - 0xc7, 0xff, 0xff, 0xff, - 0xc7, 0xff, 0xff, 0xff, - 0xcf, 0xff, 0xff, 0xff, - 0xcf, 0xff, 0xff, 0xff, - 0x8f, 0xff, 0xff, 0xff, - 0x8f, 0xff, 0xff, 0xf8, - 0x9f, 0xff, 0xff, 0xf0, - 0x9f, 0xff, 0xff, 0xe3, - 0x9f, 0xff, 0xff, 0xe7, - 0x9f, 0xff, 0xff, 0xe7, -}; - -const lv_img_dsc_t disc_f_1 = { - { - LV_IMG_CF_INDEXED_1BIT, - 0, - 0, - 32, - 32 - }, - 136, - disc_f_1_map -}; - diff --git a/src/displayapp/icons/music/disc_f_1.png b/src/displayapp/icons/music/disc_f_1.png deleted file mode 100644 index 946577344afa6d87ed4be12d174b4f779acdc287..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnL3?x0byx0z;*aCb)Tn`*Lkn<<2zGSN?P=vF< zBeIx*LAD))8T+4pOa%&Nc)B=-a9p=NyOFm+L7?^FYaPkPz=$&$nI}2cIVCy16cE`W zA?2g@sQQ>gQGDUgVvpm(J`7q5Bm{QMZiu=N7H~sVNc#i(hUn?XXX@=*aQS9wX4j9f t5^??TNgis21$=+}C(G`i?DFY2xBcJz`0X3|P6F*@@O1TaS?83{1OQm8N4Ed~ diff --git a/src/displayapp/icons/music/disc_f_2.c b/src/displayapp/icons/music/disc_f_2.c deleted file mode 100644 index 3d2331d171..0000000000 --- a/src/displayapp/icons/music/disc_f_2.c +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright (C) 2020 Avamander - - This file is part of InfiniTime. - - InfiniTime is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - InfiniTime is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#pragma once - -#include "lvgl/lvgl.h" - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_DISC_F_2 -#define LV_ATTRIBUTE_IMG_DISC_F_2 -#endif - -const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_DISC_F_2 uint8_t disc_f_2_map[] = { - 0xbd, 0xc1, 0xbe, 0xff, /* Color of index 0: foreground */ - 0x00, 0x00, 0x00, 0x00, /* Color of index 1: background */ - - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, - 0xff, 0xff, 0xf0, 0x0f, - 0xff, 0xff, 0xc0, 0xff, - 0xff, 0xff, 0x07, 0xff, - 0xff, 0xfc, 0x1f, 0xff, - 0xff, 0xf8, 0x7f, 0xf1, - 0xff, 0xf0, 0xff, 0x00, - 0xff, 0xe3, 0xfc, 0x03, - 0xff, 0xc7, 0xf0, 0x3f, - 0xff, 0x8f, 0xf0, 0xff, - 0xff, 0x1f, 0xf3, 0xff, - 0xfe, 0x3f, 0xff, 0xff, - 0xfc, 0x7f, 0xff, 0xff, - 0xfc, 0x7f, 0xff, 0xff, - 0xf8, 0xff, 0xff, 0xff, - 0xf9, 0xff, 0xff, 0xff, - 0xf1, 0xff, 0xff, 0xff, - 0xf3, 0xff, 0xff, 0xff, - 0xe3, 0xff, 0xff, 0xff, - 0xe7, 0xff, 0xff, 0xff, - 0xc7, 0xff, 0xff, 0xff, - 0xc7, 0xff, 0xff, 0xff, - 0xcf, 0xff, 0xff, 0xff, - 0xcf, 0xff, 0xff, 0xff, - 0x8f, 0xff, 0xff, 0xff, - 0x8f, 0xff, 0xff, 0xf8, - 0x9f, 0xff, 0xff, 0xf0, - 0x9f, 0xff, 0xff, 0xe3, - 0x9f, 0xff, 0xff, 0xe7, - 0x9f, 0xff, 0xff, 0xe7, -}; - -const lv_img_dsc_t disc_f_2 = { - { - LV_IMG_CF_INDEXED_1BIT, - 0, - 0, - 32, - 32 - }, - 136, - disc_f_2_map -}; - diff --git a/src/displayapp/icons/music/disc_f_2.png b/src/displayapp/icons/music/disc_f_2.png deleted file mode 100644 index 4d9a4a388a00c95eac16b501a7c4dac326d029cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnL3?x0byx0z;*aCb)Tn`*Lkn<<2zGSN?P=vF< zBeIx*LAD))8T+4pOa%(2db&7c1# pLw%;mB(>)%H9VFd=B5P2$$6bCa1OI**blUj!PC{xWt~$(696G%LhAqk From bc236457a74910b4d2d885b315f7ef654cde50cb Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Sun, 28 Dec 2025 01:29:49 +0100 Subject: [PATCH 52/67] de-clutter the SetDisconnectedUI and SetConnectedUI functions by using an array for the buttons and labels --- src/displayapp/screens/Music.cpp | 58 ++++++++++++++++++++------------ src/displayapp/screens/Music.h | 12 ++++++- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 05d31b7723..3d7e896eb3 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -49,8 +49,6 @@ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& bleController) : musicService(music), bleController {bleController} { - lv_obj_t* label; - lv_style_init(&btn_style); lv_style_set_radius(&btn_style, LV_STATE_DEFAULT, 20); lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, Colors::bgAlt); @@ -61,8 +59,8 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& lv_obj_set_size(btnVolDown, 117, 60); lv_obj_align(btnVolDown, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); lv_obj_add_style(btnVolDown, LV_STATE_DEFAULT, &btn_style); - label = lv_label_create(btnVolDown, nullptr); - lv_label_set_text_static(label, Symbols::volumDown); + txtVolDown = lv_label_create(btnVolDown, nullptr); + lv_label_set_text_static(txtVolDown, Symbols::volumDown); btnVolUp = lv_btn_create(lv_scr_act(), nullptr); btnVolUp->user_data = this; @@ -70,8 +68,8 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& lv_obj_set_size(btnVolUp, 117, 60); lv_obj_align(btnVolUp, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); lv_obj_add_style(btnVolUp, LV_STATE_DEFAULT, &btn_style); - label = lv_label_create(btnVolUp, nullptr); - lv_label_set_text_static(label, Symbols::volumUp); + txtVolUp = lv_label_create(btnVolUp, nullptr); + lv_label_set_text_static(txtVolUp, Symbols::volumUp); btnPrev = lv_btn_create(lv_scr_act(), nullptr); btnPrev->user_data = this; @@ -79,8 +77,8 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& lv_obj_set_size(btnPrev, 76, 76); lv_obj_align(btnPrev, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 3, 0); lv_obj_add_style(btnPrev, LV_STATE_DEFAULT, &btn_style); - label = lv_label_create(btnPrev, nullptr); - lv_label_set_text_static(label, Symbols::stepBackward); + txtBtnPrev = lv_label_create(btnPrev, nullptr); + lv_label_set_text_static(txtBtnPrev, Symbols::stepBackward); btnNext = lv_btn_create(lv_scr_act(), nullptr); btnNext->user_data = this; @@ -88,8 +86,8 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& lv_obj_set_size(btnNext, 76, 76); lv_obj_align(btnNext, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, -3, 0); lv_obj_add_style(btnNext, LV_STATE_DEFAULT, &btn_style); - label = lv_label_create(btnNext, nullptr); - lv_label_set_text_static(label, Symbols::stepForward); + txtBtnNext = lv_label_create(btnNext, nullptr); + lv_label_set_text_static(txtBtnNext, Symbols::stepForward); btnPlayPause = lv_btn_create(lv_scr_act(), nullptr); btnPlayPause->user_data = this; @@ -100,6 +98,18 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& txtPlayPause = lv_label_create(btnPlayPause, nullptr); lv_label_set_text_static(txtPlayPause, Symbols::play); + buttons[0] = btnPrev; + buttons[1] = btnPlayPause; + buttons[2] = btnNext; + buttons[3] = btnVolDown; + buttons[4] = btnVolUp; + + controlLabels[0] = txtBtnPrev; + controlLabels[1] = txtPlayPause; + controlLabels[2] = txtBtnNext; + controlLabels[3] = txtVolDown; + controlLabels[4] = txtVolUp; + // I'm using the txtTrack label as the top anchor for the whole lot // of song, artist, progress bar and duration text (0:00 and -0:00) so // its much easier to move that around and mess with the buttons separately @@ -180,26 +190,32 @@ void Music::Refresh() { void Music::SetDisconnectedUI() { lv_label_set_text_static(txtArtist, "Disconnected"); lv_label_set_text_static(txtTrack, ""); - lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); - lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + + for (auto btn : buttons) { + lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + } + + for (auto lbl : controlLabels) { + lv_obj_set_style_local_text_color(lbl, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + } + lv_label_set_text_static(txtCurrentPosition, "--:--"); lv_label_set_text_static(txtTrackDuration, "--:--"); lv_bar_set_range(barTrackDuration, 0, 1000); lv_bar_set_value(barTrackDuration, 0, LV_ANIM_OFF); - // empty these so they are successfully updated on reconnect because of how DirtyValue works + artist = ""; track = ""; } void Music::SetConnectedUI() { - lv_obj_set_style_local_bg_color(btnPrev, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnNext, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnVolDown, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnVolUp, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + for (auto btn : buttons) { + lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + } + + for (auto lbl : controlLabels) { + lv_obj_set_style_local_text_color(lbl, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + } } void Music::RefreshTrackInfo() { diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index 768c7105db..e143bf493d 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -61,9 +61,19 @@ namespace Pinetime { lv_obj_t* btnNext; lv_obj_t* btnVolDown; lv_obj_t* btnVolUp; + + lv_obj_t* buttons[5]; + + lv_obj_t* txtBtnPrev; + lv_obj_t* txtPlayPause; + lv_obj_t* txtBtnNext; + lv_obj_t* txtVolDown; + lv_obj_t* txtVolUp; + + lv_obj_t* controlLabels[5]; + lv_obj_t* txtArtist; lv_obj_t* txtTrack; - lv_obj_t* txtPlayPause; lv_obj_t* txtTrackDuration; lv_obj_t* txtCurrentPosition; From 2c32e4b270018a27cc85644576eb2b7cddbb7a49 Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 29 Dec 2025 19:49:11 +0100 Subject: [PATCH 53/67] apply patch from github, thanks mark! --- src/displayapp/screens/Music.cpp | 87 +++++++++++++------------------- src/displayapp/screens/Music.h | 12 +++-- 2 files changed, 44 insertions(+), 55 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 3d7e896eb3..67ff5abbc3 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -25,20 +25,22 @@ using namespace Pinetime::Applications::Screens; -static void event_handler(lv_obj_t* obj, lv_event_t event) { - Music* screen = static_cast(obj->user_data); - screen->OnObjectEvent(obj, event); -} +namespace { + void EventHandler(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + screen->OnObjectEvent(obj, event); + } -/** - * Set the pixel array to display by the image - * This just calls lv_img_set_src but adds type safety - * - * @param img pointer to an image object - * @param data the image array - */ -inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { - lv_img_set_src(img, src_img); + /** + * Set the pixel array to display by the image + * This just calls lv_img_set_src but adds type safety + * + * @param img pointer to an image object + * @param data the image array + */ + inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { + lv_img_set_src(img, src_img); + } } /** @@ -55,7 +57,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& btnVolDown = lv_btn_create(lv_scr_act(), nullptr); btnVolDown->user_data = this; - lv_obj_set_event_cb(btnVolDown, event_handler); + lv_obj_set_event_cb(btnVolDown, EventHandler); lv_obj_set_size(btnVolDown, 117, 60); lv_obj_align(btnVolDown, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); lv_obj_add_style(btnVolDown, LV_STATE_DEFAULT, &btn_style); @@ -64,7 +66,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& btnVolUp = lv_btn_create(lv_scr_act(), nullptr); btnVolUp->user_data = this; - lv_obj_set_event_cb(btnVolUp, event_handler); + lv_obj_set_event_cb(btnVolUp, EventHandler); lv_obj_set_size(btnVolUp, 117, 60); lv_obj_align(btnVolUp, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); lv_obj_add_style(btnVolUp, LV_STATE_DEFAULT, &btn_style); @@ -73,7 +75,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& btnPrev = lv_btn_create(lv_scr_act(), nullptr); btnPrev->user_data = this; - lv_obj_set_event_cb(btnPrev, event_handler); + lv_obj_set_event_cb(btnPrev, EventHandler); lv_obj_set_size(btnPrev, 76, 76); lv_obj_align(btnPrev, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 3, 0); lv_obj_add_style(btnPrev, LV_STATE_DEFAULT, &btn_style); @@ -82,7 +84,7 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& btnNext = lv_btn_create(lv_scr_act(), nullptr); btnNext->user_data = this; - lv_obj_set_event_cb(btnNext, event_handler); + lv_obj_set_event_cb(btnNext, EventHandler); lv_obj_set_size(btnNext, 76, 76); lv_obj_align(btnNext, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, -3, 0); lv_obj_add_style(btnNext, LV_STATE_DEFAULT, &btn_style); @@ -91,25 +93,13 @@ Music::Music(Pinetime::Controllers::MusicService& music, const Controllers::Ble& btnPlayPause = lv_btn_create(lv_scr_act(), nullptr); btnPlayPause->user_data = this; - lv_obj_set_event_cb(btnPlayPause, event_handler); + lv_obj_set_event_cb(btnPlayPause, EventHandler); lv_obj_set_size(btnPlayPause, 76, 76); lv_obj_align(btnPlayPause, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); lv_obj_add_style(btnPlayPause, LV_STATE_DEFAULT, &btn_style); txtPlayPause = lv_label_create(btnPlayPause, nullptr); lv_label_set_text_static(txtPlayPause, Symbols::play); - buttons[0] = btnPrev; - buttons[1] = btnPlayPause; - buttons[2] = btnNext; - buttons[3] = btnVolDown; - buttons[4] = btnVolUp; - - controlLabels[0] = txtBtnPrev; - controlLabels[1] = txtPlayPause; - controlLabels[2] = txtBtnNext; - controlLabels[3] = txtVolDown; - controlLabels[4] = txtVolUp; - // I'm using the txtTrack label as the top anchor for the whole lot // of song, artist, progress bar and duration text (0:00 and -0:00) so // its much easier to move that around and mess with the buttons separately @@ -174,12 +164,11 @@ void Music::Refresh() { if (!connected) { SetDisconnectedUI(); return; - } else { - musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); - SetConnectedUI(); - RefreshTrackInfo(); - return; } + musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN); + SetConnectedUI(); + RefreshTrackInfo(); + return; } if (bleState.Get()) { @@ -191,11 +180,11 @@ void Music::SetDisconnectedUI() { lv_label_set_text_static(txtArtist, "Disconnected"); lv_label_set_text_static(txtTrack, ""); - for (auto btn : buttons) { + for (auto* btn : GetButtons()) { lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); } - for (auto lbl : controlLabels) { + for (auto* lbl : GetButtonLabels()) { lv_obj_set_style_local_text_color(lbl, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); } @@ -209,11 +198,11 @@ void Music::SetDisconnectedUI() { } void Music::SetConnectedUI() { - for (auto btn : buttons) { + for (auto* btn : GetButtons()) { lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); } - for (auto lbl : controlLabels) { + for (auto* lbl : GetButtonLabels()) { lv_obj_set_style_local_text_color(lbl, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); } } @@ -246,10 +235,7 @@ void Music::RefreshTrackInfo() { } void Music::UpdateLength() { - int remaining = totalLength - currentPosition; - if (remaining < 0) { - remaining = 0; - } + int remaining = std::max(totalLength - currentPosition, 0); if (totalLength > (99 * 60 * 60)) { lv_label_set_text_static(txtCurrentPosition, "Inf"); @@ -257,6 +243,9 @@ void Music::UpdateLength() { } else if (totalLength > (99 * 60)) { lv_label_set_text_fmt(txtCurrentPosition, "%d:%02d", (currentPosition / (60 * 60)) % 100, ((currentPosition % (60 * 60)) / 60) % 100); lv_label_set_text_fmt(txtTrackDuration, "-%d:%02d", (remaining / (60 * 60)) % 100, ((remaining % (60 * 60)) / 60) % 100); + // These conversions are narrowing: lv_bar_set_range accepts int16_t args + // resolve by normalising? + // same for else branch below lv_bar_set_range(barTrackDuration, 0, totalLength > 0 ? totalLength : 1); lv_bar_set_value(barTrackDuration, currentPosition, LV_ANIM_OFF); } else { @@ -276,18 +265,14 @@ void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event) { } else if (obj == btnPrev) { musicService.event(Controllers::MusicService::EVENT_MUSIC_PREV); } else if (obj == btnPlayPause) { - if (playing == Pinetime::Controllers::MusicService::MusicStatus::Playing) { + if (playing) { musicService.event(Controllers::MusicService::EVENT_MUSIC_PAUSE); - - // Let's assume it stops playing instantly - playing = Controllers::MusicService::NotPlaying; } else { musicService.event(Controllers::MusicService::EVENT_MUSIC_PLAY); - - // Let's assume it starts playing instantly - // TODO: In the future should check for BT connection for better UX - playing = Controllers::MusicService::Playing; } + // Let's assume it stops/starts playing instantly + // TODO: In the future should check for BT connection for better UX + playing = !playing; } else if (obj == btnNext) { musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT); } diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h index e143bf493d..5487c1f900 100644 --- a/src/displayapp/screens/Music.h +++ b/src/displayapp/screens/Music.h @@ -19,9 +19,9 @@ #include #include +#include #include #include "displayapp/screens/Screen.h" -#include "displayapp/widgets/PageIndicator.h" #include "displayapp/apps/Apps.h" #include "displayapp/Controllers.h" #include "Symbols.h" @@ -62,7 +62,9 @@ namespace Pinetime { lv_obj_t* btnVolDown; lv_obj_t* btnVolUp; - lv_obj_t* buttons[5]; + std::array GetButtons() { + return {btnPrev, btnPlayPause, btnNext, btnVolDown, btnVolUp}; + } lv_obj_t* txtBtnPrev; lv_obj_t* txtPlayPause; @@ -70,7 +72,9 @@ namespace Pinetime { lv_obj_t* txtVolDown; lv_obj_t* txtVolUp; - lv_obj_t* controlLabels[5]; + std::array GetButtonLabels() { + return {txtBtnPrev, txtPlayPause, txtBtnNext, txtVolDown, txtVolUp}; + } lv_obj_t* txtArtist; lv_obj_t* txtTrack; @@ -96,7 +100,7 @@ namespace Pinetime { lv_task_t* taskRefresh; - Utility::DirtyValue bleState {}; + Utility::DirtyValue bleState; /** Watchapp */ }; From ad2aa15a2a1ad7330d87e14c51ffec0538ec421f Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 29 Dec 2025 19:51:49 +0100 Subject: [PATCH 54/67] formatting --- src/displayapp/screens/Music.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 67ff5abbc3..0db253a7c6 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -32,12 +32,12 @@ namespace { } /** - * Set the pixel array to display by the image - * This just calls lv_img_set_src but adds type safety - * - * @param img pointer to an image object - * @param data the image array - */ + * Set the pixel array to display by the image + * This just calls lv_img_set_src but adds type safety + * + * @param img pointer to an image object + * @param data the image array + */ inline void lv_img_set_src_arr(lv_obj_t* img, const lv_img_dsc_t* src_img) { lv_img_set_src(img, src_img); } From d17d0919c95beb80a814ee33ad1bda0377e1f3bc Mon Sep 17 00:00:00 2001 From: Titus Kendzorra Date: Mon, 29 Dec 2025 20:06:55 +0100 Subject: [PATCH 55/67] clamp track duration to bar range to avoid any possible overflow --- src/displayapp/screens/Music.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index 0db253a7c6..0745c50e50 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -236,6 +236,7 @@ void Music::RefreshTrackInfo() { void Music::UpdateLength() { int remaining = std::max(totalLength - currentPosition, 0); + int range = std::min(totalLength > 0 ? totalLength : 1, static_cast(std::numeric_limits::max())); if (totalLength > (99 * 60 * 60)) { lv_label_set_text_static(txtCurrentPosition, "Inf"); @@ -243,16 +244,13 @@ void Music::UpdateLength() { } else if (totalLength > (99 * 60)) { lv_label_set_text_fmt(txtCurrentPosition, "%d:%02d", (currentPosition / (60 * 60)) % 100, ((currentPosition % (60 * 60)) / 60) % 100); lv_label_set_text_fmt(txtTrackDuration, "-%d:%02d", (remaining / (60 * 60)) % 100, ((remaining % (60 * 60)) / 60) % 100); - // These conversions are narrowing: lv_bar_set_range accepts int16_t args - // resolve by normalising? - // same for else branch below - lv_bar_set_range(barTrackDuration, 0, totalLength > 0 ? totalLength : 1); - lv_bar_set_value(barTrackDuration, currentPosition, LV_ANIM_OFF); + lv_bar_set_range(barTrackDuration, 0, range); + lv_bar_set_value(barTrackDuration, std::min(currentPosition, range), LV_ANIM_OFF); } else { lv_label_set_text_fmt(txtCurrentPosition, "%d:%02d", (currentPosition / 60) % 100, (currentPosition % 60) % 100); lv_label_set_text_fmt(txtTrackDuration, "-%d:%02d", (remaining / 60) % 100, (remaining % 60) % 100); - lv_bar_set_range(barTrackDuration, 0, totalLength > 0 ? totalLength : 1); - lv_bar_set_value(barTrackDuration, currentPosition, LV_ANIM_OFF); + lv_bar_set_range(barTrackDuration, 0, range); + lv_bar_set_value(barTrackDuration, std::min(currentPosition, range), LV_ANIM_OFF); } } From ab47be5f6107ea3a11d4c5791147b34a5bf7b2e8 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Fri, 3 Oct 2025 14:35:26 -0400 Subject: [PATCH 56/67] timer: Add launcher with recent timer history Replace timer UI with launcher screen showing 4 quick-start options: - Three most recently used timers - Add button for manual entry Recent timers display MM:SS format and auto-start when selected. Using a recent timer moves it to front of history. The + button opens timer UI to allow the user to set a new timer manually. --- src/displayapp/DisplayApp.cpp | 7 +- src/displayapp/fonts/fonts.json | 2 +- src/displayapp/screens/Timer.cpp | 282 +++++++++++++++++++++++++------ src/displayapp/screens/Timer.h | 16 ++ 4 files changed, 255 insertions(+), 52 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 84fa603622..6f33635e20 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -377,11 +377,10 @@ void DisplayApp::Refresh() { // Load timer app if not loaded if (currentApp != Apps::Timer) { LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); - } else { - // Set the timer to ringing mode if already loaded - auto* timerScreen = static_cast(currentScreen.get()); - timerScreen->SetTimerRinging(); } + // Set the timer to ringing mode + auto* timerScreen = static_cast(currentScreen.get()); + timerScreen->SetTimerRinging(); break; } case Messages::AlarmTriggered: diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index 3221c2f171..9c113f0fdb 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -28,7 +28,7 @@ "sources": [ { "file": "JetBrainsMono-Light.ttf", - "range": "0x25, 0x2D, 0x2F, 0x30-0x3a, 0x43, 0x46, 0xb0" + "range": "0x25, 0x2B, 0x2D, 0x2F, 0x30-0x3a, 0x43, 0x46, 0xb0" } ], "bpp": 1, diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp index 749d985933..1cee62ae52 100644 --- a/src/displayapp/screens/Timer.cpp +++ b/src/displayapp/screens/Timer.cpp @@ -6,9 +6,14 @@ using namespace Pinetime::Applications::Screens; +// Initialize static member with default timer durations (5min, 10min, 15min) +uint32_t Timer::timerDurations[Timer::numRecentTimers] = {300000, 600000, 900000}; + static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { auto* screen = static_cast(obj->user_data); - if (event == LV_EVENT_PRESSED) { + if (screen->launcherMode && event == LV_EVENT_CLICKED) { + screen->OnLauncherButtonClicked(obj); + } else if (event == LV_EVENT_PRESSED) { screen->ButtonPressed(); } else if (event == LV_EVENT_RELEASED || event == LV_EVENT_PRESS_LOST) { screen->MaskReset(); @@ -20,57 +25,17 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { Timer::Timer(Controllers::Timer& timerController, Controllers::MotorController& motorController, System::SystemTask& systemTask) : timer {timerController}, motorController {motorController}, wakeLock(systemTask) { - lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); - lv_obj_set_style_local_text_color(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_label_set_text_static(colonLabel, ":"); - lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29); - - minuteCounter.Create(); - secondCounter.Create(); - lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); - lv_obj_align(secondCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); - - highlightObjectMask = lv_objmask_create(lv_scr_act(), nullptr); - lv_obj_set_size(highlightObjectMask, 240, 50); - lv_obj_align(highlightObjectMask, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); - - lv_draw_mask_line_param_t tmpMaskLine; - - lv_draw_mask_line_points_init(&tmpMaskLine, 0, 0, 0, 240, LV_DRAW_MASK_LINE_SIDE_LEFT); - highlightMask = lv_objmask_add_mask(highlightObjectMask, &tmpMaskLine); - - lv_obj_t* btnHighlight = lv_obj_create(highlightObjectMask, nullptr); - lv_obj_set_style_local_radius(btnHighlight, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_obj_set_style_local_bg_color(btnHighlight, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); - lv_obj_set_size(btnHighlight, LV_HOR_RES, 50); - lv_obj_align(btnHighlight, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); - - btnObjectMask = lv_objmask_create(lv_scr_act(), nullptr); - lv_obj_set_size(btnObjectMask, 240, 50); - lv_obj_align(btnObjectMask, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); - - lv_draw_mask_line_points_init(&tmpMaskLine, 0, 0, 0, 240, LV_DRAW_MASK_LINE_SIDE_RIGHT); - btnMask = lv_objmask_add_mask(btnObjectMask, &tmpMaskLine); - - btnPlayPause = lv_btn_create(btnObjectMask, nullptr); - btnPlayPause->user_data = this; - lv_obj_set_style_local_radius(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_event_cb(btnPlayPause, btnEventHandler); - lv_obj_set_size(btnPlayPause, LV_HOR_RES, 50); - - // Create the label as a child of the button so it stays centered by default - txtPlayPause = lv_label_create(btnPlayPause, nullptr); - auto timerStatus = timer.GetTimerState(); if (timerStatus && timerStatus->expired) { - SetTimerRinging(); + // If timer has expired, go directly to timer UI with 0 duration + CreateTimerUI(0, false); } else if (timer.IsRunning()) { - SetTimerRunning(); + // If timer is already running, skip launcher and go directly to timer UI + uint32_t durationMs = GetTimerDuration(0); + CreateTimerUI(durationMs, false); } else { - SetTimerStopped(); + CreateLauncherUI(); } taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); @@ -86,6 +51,10 @@ Timer::~Timer() { timer.ResetExpiredTime(); } + if (launcherMode) { + lv_style_reset(&btnStyle); + } + lv_obj_clean(lv_scr_act()); } @@ -116,6 +85,18 @@ void Timer::UpdateMask() { } void Timer::Refresh() { + // Don't try to update timer display if we're in launcher mode + if (launcherMode) { + // If timer starts while in launcher, transition to timer UI + if (timer.IsRunning()) { + uint32_t durationMs = GetTimerDuration(0); + lv_style_reset(&btnStyle); + lv_obj_clean(lv_scr_act()); + CreateTimerUI(durationMs, false); + } + return; + } + auto timerStatus = timer.GetTimerState(); if (timerStatus && timerStatus->expired) { @@ -156,6 +137,9 @@ void Timer::DisplayTime() { } void Timer::SetTimerRunning() { + if (launcherMode) { + return; + } minuteCounter.HideControls(); secondCounter.HideControls(); lv_label_set_text_static(txtPlayPause, "Pause"); @@ -163,6 +147,9 @@ void Timer::SetTimerRunning() { } void Timer::SetTimerStopped() { + if (launcherMode) { + return; + } minuteCounter.ShowControls(); secondCounter.ShowControls(); lv_label_set_text_static(txtPlayPause, "Start"); @@ -170,6 +157,10 @@ void Timer::SetTimerStopped() { } void Timer::SetTimerRinging() { + if (launcherMode) { + // Timer expired while in launcher mode - transition will happen in Refresh() + return; + } motorController.StartRinging(); wakeLock.Lock(); minuteCounter.HideControls(); @@ -190,6 +181,11 @@ void Timer::ToggleRunning() { } else if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) { auto timerDuration = std::chrono::minutes(minuteCounter.GetValue()) + std::chrono::seconds(secondCounter.GetValue()); timer.StartTimer(timerDuration); + + // Add the timer duration to MRU list + uint32_t durationMs = (minuteCounter.GetValue() * 60 + secondCounter.GetValue()) * 1000; + AddTimerDuration(durationMs); + Refresh(); SetTimerRunning(); } @@ -200,3 +196,195 @@ void Timer::Reset() { DisplayTime(); SetTimerStopped(); } + +void Timer::AddTimerDuration(uint32_t duration) { + // If already at front, nothing to do + if (duration == timerDurations[0]) { + return; + } + + // Shift elements down, stopping after we find the duration + uint32_t prev = timerDurations[0]; + for (int i = 1; i < numRecentTimers; i++) { + uint32_t temp = timerDurations[i]; + timerDurations[i] = prev; + prev = temp; + if (temp == duration) { + // Found it - stop after this shift + break; + } + } + + // Insert duration at front + timerDurations[0] = duration; +} + +uint32_t Timer::GetTimerDuration(uint8_t index) const { + if (index >= numRecentTimers) { + return timerDurations[0]; + } + return timerDurations[index]; +} + +void Timer::CreateLauncherUI() { + static constexpr uint8_t innerDistance = 10; + static constexpr uint8_t buttonHeight = (LV_VER_RES_MAX - innerDistance) / 2; + static constexpr uint8_t buttonWidth = (LV_HOR_RES_MAX - innerDistance) / 2; + + lv_style_init(&btnStyle); + lv_style_set_radius(&btnStyle, LV_STATE_DEFAULT, buttonHeight / 4); + lv_style_set_bg_color(&btnStyle, LV_STATE_DEFAULT, Colors::bgAlt); + + // Layout positions for the 3 recent timer buttons + static constexpr lv_align_t buttonAlignments[numRecentTimers] = { + LV_ALIGN_IN_TOP_LEFT, // Button 0: Top-left + LV_ALIGN_IN_TOP_RIGHT, // Button 1: Top-right + LV_ALIGN_IN_BOTTOM_LEFT // Button 2: Bottom-left + }; + + // Create each of the recent timer buttons + for (int i = 0; i < numRecentTimers; i++) { + btnRecent[i] = lv_btn_create(lv_scr_act(), nullptr); + btnRecent[i]->user_data = this; + lv_obj_set_event_cb(btnRecent[i], btnEventHandler); + lv_obj_add_style(btnRecent[i], LV_BTN_PART_MAIN, &btnStyle); + lv_obj_set_size(btnRecent[i], buttonWidth, buttonHeight); + lv_obj_align(btnRecent[i], nullptr, buttonAlignments[i], 0, 0); + + uint32_t duration = GetTimerDuration(i); + uint32_t minutes = duration / 60000; + uint32_t seconds = (duration % 60000) / 1000; + + labelRecent[i] = lv_label_create(btnRecent[i], nullptr); + lv_obj_t* labelIcon = lv_label_create(btnRecent[i], nullptr); + + // Show the minutes + lv_obj_set_style_local_text_font(labelRecent[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + lv_label_set_text_fmt(labelRecent[i], "%lu", minutes); + lv_obj_align(labelRecent[i], btnRecent[i], LV_ALIGN_CENTER, 0, -20); + + // Show the seconds, or "min" below + lv_obj_set_style_local_text_font(labelIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + if (seconds == 0) { + lv_label_set_text_static(labelIcon, "min"); + } else { + lv_label_set_text_fmt(labelIcon, ":%02lu", seconds); + } + lv_obj_align(labelIcon, btnRecent[i], LV_ALIGN_CENTER, 0, 20); + } + + // Bottom-right: New timer + btnCustom = lv_btn_create(lv_scr_act(), nullptr); + btnCustom->user_data = this; + lv_obj_set_event_cb(btnCustom, btnEventHandler); + lv_obj_add_style(btnCustom, LV_BTN_PART_MAIN, &btnStyle); + lv_obj_set_size(btnCustom, buttonWidth, buttonHeight); + lv_obj_align(btnCustom, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + + labelCustom = lv_label_create(btnCustom, nullptr); + lv_obj_set_style_local_text_font(labelCustom, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + lv_label_set_text_static(labelCustom, "+"); +} + +void Timer::CreateTimerUI(uint32_t startDurationMs, bool autoStart) { + launcherMode = false; + + lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + lv_obj_set_style_local_text_color(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_label_set_text_static(colonLabel, ":"); + lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29); + + minuteCounter.Create(); + secondCounter.Create(); + lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); + lv_obj_align(secondCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); + + highlightObjectMask = lv_objmask_create(lv_scr_act(), nullptr); + lv_obj_set_size(highlightObjectMask, 240, 50); + lv_obj_align(highlightObjectMask, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); + + lv_draw_mask_line_param_t tmpMaskLine; + + lv_draw_mask_line_points_init(&tmpMaskLine, 0, 0, 0, 240, LV_DRAW_MASK_LINE_SIDE_LEFT); + highlightMask = lv_objmask_add_mask(highlightObjectMask, &tmpMaskLine); + + lv_obj_t* btnHighlight = lv_obj_create(highlightObjectMask, nullptr); + lv_obj_set_style_local_radius(btnHighlight, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_style_local_bg_color(btnHighlight, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_obj_set_size(btnHighlight, LV_HOR_RES, 50); + lv_obj_align(btnHighlight, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); + + btnObjectMask = lv_objmask_create(lv_scr_act(), nullptr); + lv_obj_set_size(btnObjectMask, 240, 50); + lv_obj_align(btnObjectMask, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); + + lv_draw_mask_line_points_init(&tmpMaskLine, 0, 0, 0, 240, LV_DRAW_MASK_LINE_SIDE_RIGHT); + btnMask = lv_objmask_add_mask(btnObjectMask, &tmpMaskLine); + + btnPlayPause = lv_btn_create(btnObjectMask, nullptr); + btnPlayPause->user_data = this; + lv_obj_set_style_local_radius(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_event_cb(btnPlayPause, btnEventHandler); + lv_obj_set_size(btnPlayPause, LV_HOR_RES, 50); + + // Create the label as a child of the button so it stays centered by default + txtPlayPause = lv_label_create(btnPlayPause, nullptr); + + // Reset button press state + buttonPressing = false; + pressTime = 0; + + if (timer.IsRunning()) { + SetTimerRunning(); + DisplayTime(); + } else if (autoStart) { + auto timerDuration = std::chrono::milliseconds(startDurationMs); + timer.StartTimer(timerDuration); + AddTimerDuration(startDurationMs); + SetTimerRunning(); + DisplayTime(); + } else { + // Set the initial duration only when timer is stopped + uint32_t minutes = startDurationMs / 60000; + uint32_t seconds = (startDurationMs % 60000) / 1000; + minuteCounter.SetValue(minutes); + secondCounter.SetValue(seconds); + SetTimerStopped(); + } +} + +void Timer::OnLauncherButtonClicked(lv_obj_t* obj) { + uint32_t durationMs; + bool autoStart; + + // Check if it's one of the recent timer buttons + bool found = false; + for (int i = 0; i < numRecentTimers; i++) { + if (obj == btnRecent[i]) { + durationMs = GetTimerDuration(i); + autoStart = true; + found = true; + break; + } + } + + // Check if it's the custom timer button + if (!found) { + if (obj == btnCustom) { + durationMs = 0; + autoStart = false; + } else { + return; + } + } + + lv_style_reset(&btnStyle); + lv_obj_clean(lv_scr_act()); + + CreateTimerUI(durationMs, autoStart); + + // Wait for button release to prevent the press state from carrying over to the new UI + lv_indev_wait_release(lv_indev_get_act()); +} diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h index 651c7f0d57..25199c5e2a 100644 --- a/src/displayapp/screens/Timer.h +++ b/src/displayapp/screens/Timer.h @@ -24,16 +24,32 @@ namespace Pinetime::Applications { void ButtonPressed(); void MaskReset(); void SetTimerRinging(); + void OnLauncherButtonClicked(lv_obj_t* obj); + + bool launcherMode = true; private: void SetTimerRunning(); void SetTimerStopped(); void UpdateMask(); void DisplayTime(); + void CreateLauncherUI(); + void CreateTimerUI(uint32_t startDurationMs, bool autoStart); + void AddTimerDuration(uint32_t duration); + uint32_t GetTimerDuration(uint8_t index) const; + Pinetime::Controllers::Timer& timer; Pinetime::Controllers::MotorController& motorController; Pinetime::System::WakeLock wakeLock; + // Launcher UI elements + static constexpr int numRecentTimers = 3; + static uint32_t timerDurations[numRecentTimers]; + lv_obj_t* btnRecent[numRecentTimers] = {nullptr}; + lv_obj_t* btnCustom = nullptr; + lv_obj_t* labelRecent[numRecentTimers] = {nullptr}; + lv_obj_t* labelCustom = nullptr; + lv_style_t btnStyle; lv_obj_t* btnPlayPause; lv_obj_t* txtPlayPause; From 36da9c9885373c8cb2a319cc3343e05bf1d52c77 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Thu, 9 Jan 2025 16:41:35 -0500 Subject: [PATCH 57/67] alarm: Long press to stop alarm This change prevents accidentally turning off alarm by ensuring that there is a deliberate long press, similar to resetting the Timer app. --- src/displayapp/screens/Alarm.cpp | 52 +++++++++++++++++++++++++++++--- src/displayapp/screens/Alarm.h | 11 +++++++ 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp index 4cf4392157..4fc1e142db 100644 --- a/src/displayapp/screens/Alarm.cpp +++ b/src/displayapp/screens/Alarm.cpp @@ -74,6 +74,14 @@ Alarm::Alarm(Controllers::AlarmController& alarmController, lv_label_set_text_static(colonLabel, ":"); lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29); + progressStop = lv_bar_create(lv_scr_act(), nullptr); + lv_bar_set_range(progressStop, 0, progressBarSize); + lv_bar_set_value(progressStop, 0, LV_ANIM_OFF); + lv_obj_set_size(progressStop, progressBarSize, 10); + lv_obj_align(progressStop, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0); + lv_obj_set_style_local_bg_color(progressStop, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_obj_set_hidden(progressStop, true); + btnStop = lv_btn_create(lv_scr_act(), nullptr); btnStop->user_data = this; lv_obj_set_event_cb(btnStop, btnEventHandler); @@ -122,12 +130,28 @@ Alarm::Alarm(Controllers::AlarmController& alarmController, } else { SetSwitchState(LV_ANIM_OFF); } + + taskRefresh = lv_task_create(RefreshTaskCallback, 50, LV_TASK_PRIO_MID, this); +} + +void Alarm::Refresh() { + if (stopBtnPressTime.has_value()) { + TickType_t elapsed = xTaskGetTickCount() - stopBtnPressTime.value(); + if (elapsed >= longPressTimeout) { + ResetStopProgress(); + StopAlerting(); + } else { + lv_coord_t stopPosition = (elapsed * progressBarSize) / longPressTimeout; + UpdateStopProgress(stopPosition); + } + } } Alarm::~Alarm() { if (alarmController.IsAlerting()) { StopAlerting(); } + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); alarmController.SaveAlarm(); } @@ -139,12 +163,32 @@ void Alarm::DisableAlarm() { } } +void Alarm::StopButtonPressed() { + stopBtnPressTime = xTaskGetTickCount(); + UpdateStopProgress(0); + lv_obj_set_hidden(progressStop, false); +} + +void Alarm::ResetStopProgress() { + stopBtnPressTime = std::nullopt; + lv_obj_set_hidden(progressStop, true); + UpdateStopProgress(0); +} + +void Alarm::UpdateStopProgress(lv_coord_t stopPosition) { + lv_bar_set_value(progressStop, progressBarSize - stopPosition, LV_ANIM_OFF); +} + void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { - if (event == LV_EVENT_CLICKED) { - if (obj == btnStop) { - StopAlerting(); - return; + if (obj == btnStop) { + if (event == LV_EVENT_PRESSED) { + StopButtonPressed(); + } else if (event == LV_EVENT_RELEASED || event == LV_EVENT_PRESS_LOST) { + ResetStopProgress(); } + return; + } + if (event == LV_EVENT_CLICKED) { if (obj == btnInfo) { ShowInfo(); return; diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h index 2dde6e8754..a0aabd1ebf 100644 --- a/src/displayapp/screens/Alarm.h +++ b/src/displayapp/screens/Alarm.h @@ -24,6 +24,7 @@ #include "displayapp/Controllers.h" #include "systemtask/WakeLock.h" #include "Symbols.h" +#include namespace Pinetime { namespace Applications { @@ -35,12 +36,15 @@ namespace Pinetime { System::SystemTask& systemTask, Controllers::MotorController& motorController); ~Alarm() override; + void Refresh() override; void SetAlerting(); void OnButtonEvent(lv_obj_t* obj, lv_event_t event); bool OnButtonPushed() override; bool OnTouchEvent(TouchEvents event) override; void OnValueChanged(); void StopAlerting(); + void StopButtonPressed(); + void ResetStopProgress(); private: Controllers::AlarmController& alarmController; @@ -51,6 +55,7 @@ namespace Pinetime { lv_obj_t* lblampm = nullptr; lv_obj_t* txtMessage = nullptr; lv_obj_t* btnMessage = nullptr; + lv_task_t* taskRefresh = nullptr; lv_task_t* taskStopAlarm = nullptr; enum class EnableButtonState { On, Off, Alerting }; @@ -62,8 +67,14 @@ namespace Pinetime { void HideInfo(); void ToggleRecurrence(); void UpdateAlarmTime(); + void UpdateStopProgress(lv_coord_t stopPosition); Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_76); Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76); + + lv_obj_t* progressStop; + std::optional stopBtnPressTime; + static constexpr TickType_t longPressTimeout = pdMS_TO_TICKS(1000); + static constexpr lv_coord_t progressBarSize = 240; }; } From 088ce955f0253007c66a288444aacbe40e056eb0 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Sat, 10 Jan 2026 17:33:56 +0000 Subject: [PATCH 58/67] Update GCC (in doc and docker) to GCC15 (Arm GNU Toolchain Version 15.2.Rel1 Released: December 17, 2025, https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) --- .vscode/c_cpp_properties.json | 2 +- .vscode/launch.json | 4 ++-- doc/buildAndProgram.md | 4 ++-- doc/buildWithVScode.md | 2 +- docker/build.sh | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index c5f88a827b..a90f78d8e4 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -2,7 +2,7 @@ "env": { // TODO: This is a duplication of the configuration set in /docker/build.sh! "TOOLS_DIR": "/opt", - "GCC_ARM_PATH": "gcc-arm-none-eabi-10.3-2021.10" + "GCC_ARM_PATH": "arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi" }, "configurations": [ { diff --git a/.vscode/launch.json b/.vscode/launch.json index 7d3f17a11c..afd37c9ead 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -53,7 +53,7 @@ "continue" ], // Only use armToolchainPath if your arm-none-eabi-gdb is not in your path (some GCC packages does not contain arm-none-eabi-gdb) - "armToolchainPath": "${workspaceRoot}/../gcc-arm-none-eabi-10.3-2021.10/bin", + "armToolchainPath": "${workspaceRoot}/../arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/bin", "svdFile": "${workspaceRoot}/nrf52.svd", "configFiles": [ "interface/stlink.cfg", @@ -68,7 +68,7 @@ "request": "launch", "servertype": "external", // FIXME: This is hardcoded. I have no idea how to use the values set in build.sh here - "gdbPath": "/opt/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gdb", + "gdbPath": "/opt/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gdb", // Connect to an already running OpenOCD instance "gdbTarget": "host.docker.internal:3333", "svdFile": "${workspaceRoot}/nrf52.svd", diff --git a/doc/buildAndProgram.md b/doc/buildAndProgram.md index 5d3af46ef0..8fb765a009 100644 --- a/doc/buildAndProgram.md +++ b/doc/buildAndProgram.md @@ -4,7 +4,7 @@ To build this project, you'll need: -- A cross-compiler : [ARM-GCC (10.3-2021.10)](https://developer.arm.com/downloads/-/gnu-rm) +- A cross-compiler : [ARM-GCC 15.2-Rel1 from December 17, 2025 (AArch32 bare-metal target (arm-none-eabi))](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) - The NRF52 SDK 15.3.0 : [nRF-SDK v15.3.0](https://nsscprodmedia.blob.core.windows.net/prod/software-and-other-downloads/sdks/nrf5/binaries/nrf5sdk153059ac345.zip) - The Python 3 modules `cbor`, `intelhex`, `click` and `cryptography` modules for the `mcuboot` tool (see [requirements.txt](../tools/mcuboot/requirements.txt)) - To keep the system clean, you can install python modules into a python virtual environment (`venv`) @@ -38,7 +38,7 @@ CMake configures the project according to variables you specify the command line Variable | Description | Example| ----------|-------------|--------| -**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-10.3-2021.10/`| +**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/`| **NRF5_SDK_PATH**|path to the NRF52 SDK|`-DNRF5_SDK_PATH=/home/jf/nrf52/Pinetime/sdk`| **CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug` **BUILD_DFU (\*\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-DBUILD_DFU=1` diff --git a/doc/buildWithVScode.md b/doc/buildWithVScode.md index 5f8724828a..9d9575356b 100644 --- a/doc/buildWithVScode.md +++ b/doc/buildWithVScode.md @@ -8,7 +8,7 @@ To support as many setups as possible the VS Code configuration files expect the Variable | Description | Example ----------|-------------|-------- -**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`export ARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-none-eabi-10.3-2021.10` +**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`export ARM_NONE_EABI_TOOLCHAIN_PATH=/opt/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi` **NRF5_SDK_PATH**|path to the NRF52 SDK|`export NRF5_SDK_PATH=/opt/nRF5_SDK_15.3.0_59ac345` ## VS Code Extensions diff --git a/docker/build.sh b/docker/build.sh index b7637f4990..31db89f142 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -16,7 +16,7 @@ export NPM_DIR="$BUILD_DIR/npm" export npm_config_cache="${NPM_DIR}" export BUILD_TYPE=${BUILD_TYPE:=Release} -export GCC_ARM_VER=${GCC_ARM_VER:="10.3-2021.10"} +export GCC_ARM_VER=${GCC_ARM_VER:="15.2.rel1"} export NRF_SDK_VER=${NRF_SDK_VER:="nRF5_SDK_15.3.0_59ac345"} # convert to lower case and remove _ and . character # the download URL uses the SLUG, but the extracted folder is named like the original value @@ -26,7 +26,7 @@ export NRF_SDK_VER_SLUG=${NRF_SDK_VER_SLUG//[_.]/} MACHINE="$(uname -m)" [ "$MACHINE" = "arm64" ] && MACHINE="aarch64" -export GCC_ARM_PATH="gcc-arm-none-eabi-$GCC_ARM_VER" +export GCC_ARM_PATH="arm-gnu-toolchain-$GCC_ARM_VER-$MACHINE-arm-none-eabi" main() { local target="$1" @@ -50,7 +50,7 @@ main() { } GetGcc() { - wget -q https://developer.arm.com/-/media/Files/downloads/gnu-rm/$GCC_ARM_VER/$GCC_ARM_PATH-$MACHINE-linux.tar.bz2 -O - | tar -xj -C $TOOLS_DIR/ + wget -q https://developer.arm.com/-/media/Files/downloads/gnu/$GCC_ARM_VER/binrel/$GCC_ARM_PATH.tar.xz -O - | tar -xJ -C $TOOLS_DIR/ if [ ! -d "$TOOLS_DIR/$GCC_ARM_PATH" ]; then echo "missing GCC path: $TOOLS_DIR/$GCC_ARM_PATH" return 1 From eafb127cdcd7867c15d161e5b8f29346498e3984 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Sat, 10 Jan 2026 13:04:54 +0000 Subject: [PATCH 59/67] Implement required stubs instead of linking nosys --- src/CMakeLists.txt | 12 +++++----- src/stdlib.c | 59 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e4a354df64..faef4160da 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -930,7 +930,7 @@ target_compile_options(${EXECUTABLE_NAME} PUBLIC set_target_properties(${EXECUTABLE_NAME} PROPERTIES SUFFIX ".out" - LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_FILE_NAME}.map" + LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_FILE_NAME}.map" ) add_custom_command(TARGET ${EXECUTABLE_NAME} @@ -965,7 +965,7 @@ target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES SUFFIX ".out" - LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_MCUBOOT_FILE_NAME}.map" + LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_MCUBOOT_FILE_NAME}.map" ) add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME} @@ -1008,7 +1008,7 @@ target_compile_options(${EXECUTABLE_RECOVERY_NAME} PUBLIC set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES SUFFIX ".out" - LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_RECOVERY_FILE_NAME}.map" + LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_RECOVERY_FILE_NAME}.map" ) add_custom_command(TARGET ${EXECUTABLE_RECOVERY_NAME} @@ -1040,7 +1040,7 @@ target_compile_options(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES SUFFIX ".out" - LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_GRAPHICS_FILE_NAME}.map" + LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_GRAPHICS_FILE_NAME}.map" ) add_custom_command(TARGET ${EXECUTABLE_RECOVERY_MCUBOOT_NAME} @@ -1083,7 +1083,7 @@ add_dependencies(${EXECUTABLE_RECOVERYLOADER_NAME} ${EXECUTABLE_RECOVERY_MCUBOOT set_target_properties(${EXECUTABLE_RECOVERYLOADER_NAME} PROPERTIES SUFFIX ".out" - LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_RECOVERYLOADER_FILE_NAME}.map" + LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_RECOVERYLOADER_FILE_NAME}.map" ) add_custom_command(TARGET ${EXECUTABLE_RECOVERYLOADER_NAME} @@ -1118,7 +1118,7 @@ add_dependencies(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} ${EXECUTABLE_RECOVERY set_target_properties(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PROPERTIES SUFFIX ".out" - LINK_FLAGS "-mthumb -mabi=aapcs -std=gnu++98 -std=c99 -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.map" + LINK_FLAGS "-mthumb -mabi=aapcs -std=gnu++98 -std=c99 -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -Wl,-Map=${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.map" ) add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} diff --git a/src/stdlib.c b/src/stdlib.c index 21b506a843..18884c4893 100644 --- a/src/stdlib.c +++ b/src/stdlib.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include // Override malloc() and free() to use the memory manager from FreeRTOS. // According to the documentation of libc, we also need to override @@ -29,7 +31,7 @@ void __wrap_free(void* ptr) { } void* calloc(size_t num, size_t size) { - void *ptr = malloc(num * size); + void* ptr = malloc(num * size); if (ptr) { memset(ptr, 0, num * size); } @@ -49,3 +51,58 @@ void* realloc(void* ptr, size_t newSize) { void* __wrap_realloc(void* ptr, size_t newSize) { return realloc(ptr, newSize); } + +// Implement functions required by libc as stubs +// These functions aren't linked into the final binary + +__attribute__((error("stub"))) void _close(int fp) { + __builtin_trap(); + (void) fp; +} + +__attribute__((error("stub"))) void _fstat(int fildes, struct stat* buf) { + __builtin_trap(); + (void) fildes; + (void) buf; +} + +__attribute__((error("stub"))) pid_t _getpid() { + __builtin_trap(); +} + +__attribute__((error("stub"))) int _isatty(int fd) { + __builtin_trap(); + (void) fd; +} + +__attribute__((error("stub"))) int _kill(pid_t pid, int sig) { + __builtin_trap(); + (void) pid; + (void) sig; +} + +__attribute__((error("stub"))) off_t _lseek(int fd, off_t offset, int whence) { + __builtin_trap(); + (void) fd; + (void) offset; + (void) whence; +} + +__attribute__((error("stub"))) ssize_t _read(int fd, void* buf, size_t count) { + __builtin_trap(); + (void) fd; + (void) buf; + (void) count; +} + +__attribute__((error("stub"))) ssize_t _write(int fd, void* buf, size_t count) { + __builtin_trap(); + (void) fd; + (void) buf; + (void) count; +} + +__attribute__((error("stub"))) void _exit(int status) { + __builtin_trap(); + (void) status; +} From ba96b547c5dc9d2832dda9a77e6530fe550631a5 Mon Sep 17 00:00:00 2001 From: ngarnsworthy Date: Sun, 10 May 2026 14:01:53 -0500 Subject: [PATCH 60/67] Add non-binary flag --- src/components/settings/Settings.h | 2 +- src/displayapp/screens/WatchFacePrideFlag.cpp | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 9133d3fea1..5ca3ac952e 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -39,7 +39,7 @@ namespace Pinetime { }; enum class PTSGaugeStyle : uint8_t { Full, Half, Numeric }; enum class PTSWeather : uint8_t { On, Off }; - enum class PrideFlag : uint8_t { Gay, Trans, Bi, Lesbian }; + enum class PrideFlag : uint8_t { Gay, Trans, Bi, Lesbian, Nonbinary }; enum class DfuAndFsMode : uint8_t { Disabled, Enabled, EnabledTillReboot }; struct PineTimeStyle { diff --git a/src/displayapp/screens/WatchFacePrideFlag.cpp b/src/displayapp/screens/WatchFacePrideFlag.cpp index e029c076f4..e1a43c7919 100644 --- a/src/displayapp/screens/WatchFacePrideFlag.cpp +++ b/src/displayapp/screens/WatchFacePrideFlag.cpp @@ -3,6 +3,8 @@ #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" #include "displayapp/screens/Symbols.h" +#include "drivers/Bma421_C/bma4_defs.h" +#include "lvgl/src/lv_misc/lv_color.h" using namespace Pinetime::Applications::Screens; @@ -15,7 +17,7 @@ namespace { Pinetime::Controllers::Settings::PrideFlag GetNext(Pinetime::Controllers::Settings::PrideFlag prideFlag) { const auto prideFlagAsInt = static_cast(prideFlag); Pinetime::Controllers::Settings::PrideFlag nextFlag; - if (prideFlagAsInt < 3) { + if (prideFlagAsInt < 4) { nextFlag = static_cast(prideFlagAsInt + 1); } else { nextFlag = static_cast(0); @@ -29,7 +31,7 @@ namespace { if (prideFlagAsInt > 0) { prevFlag = static_cast(prideFlagAsInt - 1); } else { - prevFlag = static_cast(3); + prevFlag = static_cast(4); } return prevFlag; } @@ -71,14 +73,17 @@ namespace { constexpr lv_color_t lightGreen = LV_COLOR_MAKE(0x98, 0xe8, 0xc1); constexpr lv_color_t indigo = LV_COLOR_MAKE(0x50, 0x49, 0xcc); constexpr lv_color_t steelBlue = LV_COLOR_MAKE(0x3d, 0x1a, 0x78); + constexpr lv_color_t skyBlue = LV_COLOR_MAKE(0x4a, 0x91, 0xe8); constexpr std::array gayColours {darkGreen, cyan, lightGreen, LV_COLOR_WHITE, lightBlue, indigo, steelBlue}; constexpr std::array transColours {lightBlue, lightPink, LV_COLOR_WHITE, lightPink, lightBlue}; constexpr std::array biColours {hotPink, hotPink, grayPurple, darkBlue, darkBlue}; constexpr std::array lesbianColours {LV_COLOR_RED, orange, lightOrange, LV_COLOR_WHITE, lightPurple, darkPurple, magenta}; + constexpr std::array nonbinaryColours {LV_COLOR_YELLOW, LV_COLOR_WHITE, LV_COLOR_PURPLE, LV_COLOR_BLACK}; constexpr PrideFlagData gayFlagData(gayColours, LV_COLOR_BLACK, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData transFlagData(transColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData biFlagData(biColours, LV_COLOR_BLACK, LV_COLOR_WHITE, LV_COLOR_BLACK); constexpr PrideFlagData lesbianFlagData(lesbianColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); + constexpr PrideFlagData nonbinaryFlagData(nonbinaryColours, skyBlue, LV_COLOR_BLACK, skyBlue); } WatchFacePrideFlag::WatchFacePrideFlag(Controllers::DateTime& dateTimeController, @@ -333,5 +338,8 @@ void WatchFacePrideFlag::UpdateScreen(const Pinetime::Controllers::Settings::Pri case Pinetime::Controllers::Settings::PrideFlag::Lesbian: UseFlagData(lesbianFlagData); break; + case Pinetime::Controllers::Settings::PrideFlag::Nonbinary: + UseFlagData(nonbinaryFlagData); + break; } } From f20c2c8e8e32f8b374c19724803512587b503594 Mon Sep 17 00:00:00 2001 From: Nicholas Garnsworthy Date: Sun, 10 May 2026 14:47:17 -0500 Subject: [PATCH 61/67] Add pride flag watchface documentation --- doc/gettingStarted/Watchfaces.md | 4 ++++ doc/gettingStarted/Watchfaces/Pride.png | Bin 0 -> 2413 bytes 2 files changed, 4 insertions(+) create mode 100644 doc/gettingStarted/Watchfaces/Pride.png diff --git a/doc/gettingStarted/Watchfaces.md b/doc/gettingStarted/Watchfaces.md index 9edff0bb51..2d888eae0f 100644 --- a/doc/gettingStarted/Watchfaces.md +++ b/doc/gettingStarted/Watchfaces.md @@ -29,3 +29,7 @@ InfiniTime has 6 apps on the `main` branch at the time of writing. ### Casio G7710 ![Casio G7710 face](/doc/gettingStarted/Watchfaces/CasioG7710.png) + +### Pride Flag +![Pride flag face](/doc/gettingStarted/Watchfaces/Pride.png) + - You can long-press on the display to change flags. (Gay, Lesbian, Bi, Trans, Non-binary) \ No newline at end of file diff --git a/doc/gettingStarted/Watchfaces/Pride.png b/doc/gettingStarted/Watchfaces/Pride.png new file mode 100644 index 0000000000000000000000000000000000000000..7e97295cea6c28e2eea095b92bb1d2b1b79069dc GIT binary patch literal 2413 zcmcImc~lbk76!KwCQCET9F-c=%F-;;v{6c}7`4Po9CDcqY*7Rk$}K=G*EDgQ!d90V z(cDmS0Ys74B9)mw8(h&;GIK%DR1`!Wo%jBD=bh>O*B`(8opbNG_uO;tz2EoC^znx2 zfQ`Wb06@p%=cA`pDEacVwNw_0n9KtJKnFaIy86aF6b4Q6uL>V2d0uNBMu zaakjNkZA^^Kjv0^d^(-*wxPPyVW%0;??XlDyVsN85)6B;(f6E_26D*pibkzdpgJQY zbl1sci&Mz~Bj5?X#b`CafT;y_eaJp;+1#xiIZc56>PFX&)Nym?!H)AsjG6W{>SqDZ zOH~vH>TTg~<4(1;pQp5Sj2a{VxoloUd!VeYq*JH7Bo|I4BVH`O%%IjgbNWnmk85hB z=mj4!0{#v3jZUuA35bANJp&`%<4M5t8s7$DUJfO1Bsg7L{PZ3kpLA-)qEdZ}Vj5)9-m}V{R@L%)|93n`R zcv-#;%P5+}jNG?$eKYMg9o0Vo+H%}FVPl!7&8U#NR3?vn zREsjJ%qz|B>S_BudQV#jz9EX3Xvgk!QJf94OKVsv>tuT)YYJBfLNY)StsZ@9Nv7lG z0*h^m4cNrh)d5hYrbeHShwDs}WGx&N;UQuq0kZtr7qk00FQD2HCLP16!(j$}fO8?yjb~YZxJSfD0ndbnUPlfgeodH_ ztzBHQce2FO=FS?Y8y*NqPB!*Q{x*|W*sfc>pmk)EYPl#PvAUEfCJ3TkZHLOH#>|(Z z-n4AqH}JM&%%yW*>_iAi(w$NsT4;zeONR&Wu$yj#&lTi5kn_G{-Uj+S%(V%~LAPHk zGWlTMe#g`1mDbC1{gy-JwXxVJjkeZOyJwc04 za<@EjQ<1-4Qe2gTt~Px!chlaFH9;ePfS8Z3tEoWp=vPs2#_sq)Yq_6)9NT8@WR*ZY zn65OrG${}=@603b9Qx>C6`6xc+vGLDs%sgCxlp}J>?_cS?nPQwd=lP-@XD)Mx4{Gk zHbf($Bgyxd5uT|BpTewpzq##3BZ87J<^Ery)?~z0V8Ih-{d58;tfA(vjH6uB55S@k zH^Y^7H&SyS7}0TYB}^yEm}9AEfe2Cbg>9+K^F5P{IeVNRZL-VO&puQE!EJz1O;*`Lti-{DSD^!l-cQxpK05yx_K+lTOg2jkg_Db)tq|JObq& zX;)EMRTE~!ABX!(RkGgM&-dTV@M>={niS;e{iV@tzWNGaqEyo20efcaJXIqW|HN1@ zJrjm>6X%WvSXNap@~7lX6yv>>n&573%}pwb(n$cBCZtubh!<{WdoG)&vfAwMgw-1N;MSS0MA?1z27m(!q@!)lO|n&6_f0_9 znPqJJ7XFZ&KQDdUrr1q|YrAVY?B6`xFp;FI(Z{WSVw(7|5!i?VJ@QdbR@yP~Uj0;y z*#)P+c69WgBh5=pY9^e|Y)`Amx|+l3?0!^9t4n6xDV+>oY! z^70@JTgGG6`)=s}ZuM01_tKTwA(XAOU?;&{Tz6~QzDE&ZYJhynL{%dW6ux$3bj;0l z#)=IqLq1`8WaLN<$3KK6C+G)!&ygymt(!EE8RMWIj~zP^e;uO<%z24IHQ_RL5!)(< zmEC&5K(E+ay|gooS@Y6OiU@<)V$E`R+~Qh(3fSZoGw*qG!5g|Dn+2z|H_9#@Zru_c z>(=j&L~Csgfq2z?Rygjc59-AP&S{{=oSR}%mL literal 0 HcmV?d00001 From e95f8a31238e5a23a0475d8a6a74204f508c2835 Mon Sep 17 00:00:00 2001 From: Nicholas Garnsworthy Date: Mon, 11 May 2026 03:34:03 +0000 Subject: [PATCH 62/67] Added aro, ace, aroace, and pan flags and updated the text color for nonbinary --- src/components/settings/Settings.h | 2 +- src/displayapp/screens/WatchFacePrideFlag.cpp | 28 +++++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 5ca3ac952e..93b484336d 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -39,7 +39,7 @@ namespace Pinetime { }; enum class PTSGaugeStyle : uint8_t { Full, Half, Numeric }; enum class PTSWeather : uint8_t { On, Off }; - enum class PrideFlag : uint8_t { Gay, Trans, Bi, Lesbian, Nonbinary }; + enum class PrideFlag : uint8_t { Gay, Trans, Bi, Lesbian, Nonbinary, Ace, Aro, AroAce, Pan }; enum class DfuAndFsMode : uint8_t { Disabled, Enabled, EnabledTillReboot }; struct PineTimeStyle { diff --git a/src/displayapp/screens/WatchFacePrideFlag.cpp b/src/displayapp/screens/WatchFacePrideFlag.cpp index e1a43c7919..510c78057c 100644 --- a/src/displayapp/screens/WatchFacePrideFlag.cpp +++ b/src/displayapp/screens/WatchFacePrideFlag.cpp @@ -17,7 +17,7 @@ namespace { Pinetime::Controllers::Settings::PrideFlag GetNext(Pinetime::Controllers::Settings::PrideFlag prideFlag) { const auto prideFlagAsInt = static_cast(prideFlag); Pinetime::Controllers::Settings::PrideFlag nextFlag; - if (prideFlagAsInt < 4) { + if (prideFlagAsInt < 8) { nextFlag = static_cast(prideFlagAsInt + 1); } else { nextFlag = static_cast(0); @@ -31,7 +31,7 @@ namespace { if (prideFlagAsInt > 0) { prevFlag = static_cast(prideFlagAsInt - 1); } else { - prevFlag = static_cast(4); + prevFlag = static_cast(8); } return prevFlag; } @@ -64,6 +64,8 @@ namespace { constexpr lv_color_t grayPurple = LV_COLOR_MAKE(0x9b, 0x4f, 0x96); constexpr lv_color_t darkBlue = LV_COLOR_MAKE(0x00, 0x38, 0xa8); constexpr lv_color_t orange = LV_COLOR_MAKE(0xef, 0x76, 0x27); + constexpr lv_color_t sunOrange = LV_COLOR_MAKE(0xe2, 0x8c, 0x00); + constexpr lv_color_t brightYellow = LV_COLOR_MAKE(0xec, 0xcd, 0x00); constexpr lv_color_t lightOrange = LV_COLOR_MAKE(0xff, 0x9b, 0x55); constexpr lv_color_t lightPurple = LV_COLOR_MAKE(0xd4, 0x61, 0xa6); constexpr lv_color_t darkPurple = LV_COLOR_MAKE(0xb5, 0x56, 0x90); @@ -79,11 +81,19 @@ namespace { constexpr std::array biColours {hotPink, hotPink, grayPurple, darkBlue, darkBlue}; constexpr std::array lesbianColours {LV_COLOR_RED, orange, lightOrange, LV_COLOR_WHITE, lightPurple, darkPurple, magenta}; constexpr std::array nonbinaryColours {LV_COLOR_YELLOW, LV_COLOR_WHITE, LV_COLOR_PURPLE, LV_COLOR_BLACK}; + constexpr std::array aceColours {LV_COLOR_BLACK, LV_COLOR_GRAY, LV_COLOR_WHITE, LV_COLOR_PURPLE}; + constexpr std::array aroColours {LV_COLOR_GREEN, lightGreen, LV_COLOR_WHITE, LV_COLOR_GRAY, LV_COLOR_BLACK}; + constexpr std::array aroaceColours {sunOrange, brightYellow, LV_COLOR_WHITE, LV_COLOR_MAKE(0x62, 0xae, 0xdc), LV_COLOR_MAKE(0x20, 0x38, 0x56)}; + constexpr std::array panColours {hotPink, LV_COLOR_YELLOW, skyBlue}; constexpr PrideFlagData gayFlagData(gayColours, LV_COLOR_BLACK, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData transFlagData(transColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData biFlagData(biColours, LV_COLOR_BLACK, LV_COLOR_WHITE, LV_COLOR_BLACK); constexpr PrideFlagData lesbianFlagData(lesbianColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); - constexpr PrideFlagData nonbinaryFlagData(nonbinaryColours, skyBlue, LV_COLOR_BLACK, skyBlue); + constexpr PrideFlagData nonbinaryFlagData(nonbinaryColours, skyBlue, lightPink, skyBlue); + constexpr PrideFlagData aceFlagData(aceColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_BLACK); + constexpr PrideFlagData aroFlagData(aroColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); + constexpr PrideFlagData aroaceFlagData(aroaceColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); + constexpr PrideFlagData panFlagData(panColours, LV_COLOR_BLACK, LV_COLOR_BLACK, LV_COLOR_BLACK); } WatchFacePrideFlag::WatchFacePrideFlag(Controllers::DateTime& dateTimeController, @@ -341,5 +351,17 @@ void WatchFacePrideFlag::UpdateScreen(const Pinetime::Controllers::Settings::Pri case Pinetime::Controllers::Settings::PrideFlag::Nonbinary: UseFlagData(nonbinaryFlagData); break; + case Pinetime::Controllers::Settings::PrideFlag::Ace: + UseFlagData(aceFlagData); + break; + case Pinetime::Controllers::Settings::PrideFlag::Aro: + UseFlagData(aroFlagData); + break; + case Pinetime::Controllers::Settings::PrideFlag::AroAce: + UseFlagData(aroaceFlagData); + break; + case Pinetime::Controllers::Settings::PrideFlag::Pan: + UseFlagData(panFlagData); + break; } } From f981f1ba712905e5c954a8bb58a82f44faf7ab76 Mon Sep 17 00:00:00 2001 From: Nicholas Garnsworthy Date: Mon, 11 May 2026 03:40:51 +0000 Subject: [PATCH 63/67] Fix formatting --- src/displayapp/screens/WatchFacePrideFlag.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/WatchFacePrideFlag.cpp b/src/displayapp/screens/WatchFacePrideFlag.cpp index 510c78057c..9231e4a99a 100644 --- a/src/displayapp/screens/WatchFacePrideFlag.cpp +++ b/src/displayapp/screens/WatchFacePrideFlag.cpp @@ -83,7 +83,11 @@ namespace { constexpr std::array nonbinaryColours {LV_COLOR_YELLOW, LV_COLOR_WHITE, LV_COLOR_PURPLE, LV_COLOR_BLACK}; constexpr std::array aceColours {LV_COLOR_BLACK, LV_COLOR_GRAY, LV_COLOR_WHITE, LV_COLOR_PURPLE}; constexpr std::array aroColours {LV_COLOR_GREEN, lightGreen, LV_COLOR_WHITE, LV_COLOR_GRAY, LV_COLOR_BLACK}; - constexpr std::array aroaceColours {sunOrange, brightYellow, LV_COLOR_WHITE, LV_COLOR_MAKE(0x62, 0xae, 0xdc), LV_COLOR_MAKE(0x20, 0x38, 0x56)}; + constexpr std::array aroaceColours {sunOrange, + brightYellow, + LV_COLOR_WHITE, + LV_COLOR_MAKE(0x62, 0xae, 0xdc), + LV_COLOR_MAKE(0x20, 0x38, 0x56)}; constexpr std::array panColours {hotPink, LV_COLOR_YELLOW, skyBlue}; constexpr PrideFlagData gayFlagData(gayColours, LV_COLOR_BLACK, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData transFlagData(transColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); From caf0a5a549143456e90db5d21a381d184e5f9022 Mon Sep 17 00:00:00 2001 From: Nicholas Garnsworthy Date: Mon, 11 May 2026 22:21:58 +0000 Subject: [PATCH 64/67] Updated watch colors for more contrast and cleaned up code and referances --- doc/gettingStarted/Watchfaces.md | 2 +- src/displayapp/screens/WatchFacePrideFlag.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/gettingStarted/Watchfaces.md b/doc/gettingStarted/Watchfaces.md index 2d888eae0f..a1e820f9ba 100644 --- a/doc/gettingStarted/Watchfaces.md +++ b/doc/gettingStarted/Watchfaces.md @@ -32,4 +32,4 @@ InfiniTime has 6 apps on the `main` branch at the time of writing. ### Pride Flag ![Pride flag face](/doc/gettingStarted/Watchfaces/Pride.png) - - You can long-press on the display to change flags. (Gay, Lesbian, Bi, Trans, Non-binary) \ No newline at end of file + - You can long-press on the display to change flags. (Gay, Lesbian, Bi, Trans, Non-binary, Aromantic, Asexual, AroAce, Pansexual) \ No newline at end of file diff --git a/src/displayapp/screens/WatchFacePrideFlag.cpp b/src/displayapp/screens/WatchFacePrideFlag.cpp index 9231e4a99a..b9fb6c09b1 100644 --- a/src/displayapp/screens/WatchFacePrideFlag.cpp +++ b/src/displayapp/screens/WatchFacePrideFlag.cpp @@ -3,7 +3,6 @@ #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" #include "displayapp/screens/Symbols.h" -#include "drivers/Bma421_C/bma4_defs.h" #include "lvgl/src/lv_misc/lv_color.h" using namespace Pinetime::Applications::Screens; @@ -93,7 +92,7 @@ namespace { constexpr PrideFlagData transFlagData(transColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData biFlagData(biColours, LV_COLOR_BLACK, LV_COLOR_WHITE, LV_COLOR_BLACK); constexpr PrideFlagData lesbianFlagData(lesbianColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); - constexpr PrideFlagData nonbinaryFlagData(nonbinaryColours, skyBlue, lightPink, skyBlue); + constexpr PrideFlagData nonbinaryFlagData(nonbinaryColours, skyBlue, LV_COLOR_MAKE(0x84, 0xAE, 0x09), skyBlue); constexpr PrideFlagData aceFlagData(aceColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_BLACK); constexpr PrideFlagData aroFlagData(aroColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData aroaceFlagData(aroaceColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); From dd5801f19e0dff7b39a48297fd6332aa49540e76 Mon Sep 17 00:00:00 2001 From: Nicholas Garnsworthy Date: Mon, 11 May 2026 23:10:18 +0000 Subject: [PATCH 65/67] New better contrast and fix includes --- src/displayapp/screens/WatchFacePrideFlag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/WatchFacePrideFlag.cpp b/src/displayapp/screens/WatchFacePrideFlag.cpp index b9fb6c09b1..27c7d009ca 100644 --- a/src/displayapp/screens/WatchFacePrideFlag.cpp +++ b/src/displayapp/screens/WatchFacePrideFlag.cpp @@ -92,7 +92,7 @@ namespace { constexpr PrideFlagData transFlagData(transColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData biFlagData(biColours, LV_COLOR_BLACK, LV_COLOR_WHITE, LV_COLOR_BLACK); constexpr PrideFlagData lesbianFlagData(lesbianColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); - constexpr PrideFlagData nonbinaryFlagData(nonbinaryColours, skyBlue, LV_COLOR_MAKE(0x84, 0xAE, 0x09), skyBlue); + constexpr PrideFlagData nonbinaryFlagData(nonbinaryColours, skyBlue, skyBlue, skyBlue); constexpr PrideFlagData aceFlagData(aceColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_BLACK); constexpr PrideFlagData aroFlagData(aroColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData aroaceFlagData(aroaceColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); From 65d2dd67f70d58181a4e7102005466ba6877b018 Mon Sep 17 00:00:00 2001 From: Nicholas Garnsworthy Date: Tue, 12 May 2026 14:06:30 +0000 Subject: [PATCH 66/67] Make all text colors black and white --- src/displayapp/screens/WatchFacePrideFlag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/WatchFacePrideFlag.cpp b/src/displayapp/screens/WatchFacePrideFlag.cpp index 27c7d009ca..d035337444 100644 --- a/src/displayapp/screens/WatchFacePrideFlag.cpp +++ b/src/displayapp/screens/WatchFacePrideFlag.cpp @@ -92,7 +92,7 @@ namespace { constexpr PrideFlagData transFlagData(transColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData biFlagData(biColours, LV_COLOR_BLACK, LV_COLOR_WHITE, LV_COLOR_BLACK); constexpr PrideFlagData lesbianFlagData(lesbianColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); - constexpr PrideFlagData nonbinaryFlagData(nonbinaryColours, skyBlue, skyBlue, skyBlue); + constexpr PrideFlagData nonbinaryFlagData(nonbinaryColours, LV_COLOR_BLACK, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData aceFlagData(aceColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_BLACK); constexpr PrideFlagData aroFlagData(aroColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); constexpr PrideFlagData aroaceFlagData(aroaceColours, LV_COLOR_WHITE, LV_COLOR_BLACK, LV_COLOR_WHITE); From 43cf5adb0d3b70a7741fcaaaae0abaf6c718aacc Mon Sep 17 00:00:00 2001 From: BurninTurtles Date: Mon, 25 May 2026 08:02:02 -0400 Subject: [PATCH 67/67] Disable logging to enable building my rig --- src/libs/lfs_config.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/libs/lfs_config.h b/src/libs/lfs_config.h index eaeede0e63..8e283579fd 100644 --- a/src/libs/lfs_config.h +++ b/src/libs/lfs_config.h @@ -2,25 +2,25 @@ #include -#ifndef LFS_TRACE -#ifdef LFS_YES_TRACE -#define LFS_TRACE_(fmt, ...) \ - NRF_LOG_DEBUG("[LFS] %s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) -#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") -#else -#define LFS_TRACE(...) -#endif -#endif +//#ifndef LFS_TRACE +//#ifdef LFS_YES_TRACE +//#define LFS_TRACE_(fmt, ...) \ +// NRF_LOG_DEBUG("[LFS] %s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +//#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") +//#else +//#define LFS_TRACE(...) +//#endif +//#endif -#ifndef LFS_DEBUG -#ifndef LFS_NO_DEBUG -#define LFS_DEBUG_(fmt, ...) \ - NRF_LOG_DEBUG("[LFS] %s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) -#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") -#else -#define LFS_DEBUG(...) -#endif -#endif +//#ifndef LFS_DEBUG +//#ifndef LFS_NO_DEBUG +//#define LFS_DEBUG_(fmt, ...) \ +// NRF_LOG_DEBUG("[LFS] %s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +//#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") +//#else +//#define LFS_DEBUG(...) +//#endif +//#endif #ifndef LFS_WARN #ifndef LFS_NO_WARN