From 43e07540d78dda31c47a9acd35ef7060d70011cd Mon Sep 17 00:00:00 2001 From: Olivier ROMAN Date: Wed, 5 Feb 2025 16:43:40 +0100 Subject: [PATCH 1/9] add date format setting --- src/CMakeLists.txt | 2 + src/components/settings/Settings.h | 13 ++++ src/displayapp/DisplayApp.cpp | 2 +- .../screens/settings/SettingClockFormat.cpp | 61 +++++++++++++++ .../screens/settings/SettingClockFormat.h | 24 ++++++ .../screens/settings/SettingDateFormat.cpp | 63 +++++++++++++++ .../screens/settings/SettingDateFormat.h | 24 ++++++ .../screens/settings/SettingTimeFormat.cpp | 77 ++++++++----------- .../screens/settings/SettingTimeFormat.h | 18 +++-- 9 files changed, 228 insertions(+), 56 deletions(-) create mode 100644 src/displayapp/screens/settings/SettingClockFormat.cpp create mode 100644 src/displayapp/screens/settings/SettingClockFormat.h create mode 100644 src/displayapp/screens/settings/SettingDateFormat.cpp create mode 100644 src/displayapp/screens/settings/SettingDateFormat.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e2b69b8b02..0f44e827fb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -408,6 +408,8 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/Settings.cpp displayapp/screens/settings/SettingWatchFace.cpp displayapp/screens/settings/SettingTimeFormat.cpp + displayapp/screens/settings/SettingClockFormat.cpp + displayapp/screens/settings/SettingDateFormat.cpp displayapp/screens/settings/SettingWeatherFormat.cpp displayapp/screens/settings/SettingWakeUp.cpp displayapp/screens/settings/SettingDisplay.cpp diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 602de3a585..a7b7dfe775 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -10,6 +10,7 @@ namespace Pinetime { class Settings { public: enum class ClockType : uint8_t { H24, H12 }; + enum class DateFormat : uint8_t { YYYYMMDD, DDMMYYYY, MMDDYYYY, DayDDMonthYYYY }; enum class WeatherFormat : uint8_t { Metric, Imperial }; enum class Notification : uint8_t { On, Off, Sleep }; enum class ChimesOption : uint8_t { None, Hours, HalfHours }; @@ -181,6 +182,17 @@ namespace Pinetime { return settings.clockType; }; + void SetDateFormat(DateFormat dateFormat) { + if (dateFormat != settings.dateFormat) { + settingsChanged = true; + } + settings.dateFormat = dateFormat; + }; + + DateFormat GetDateFormat() const { + return settings.dateFormat; + }; + void SetWeatherFormat(WeatherFormat weatherFormat) { if (weatherFormat != settings.weatherFormat) { settingsChanged = true; @@ -311,6 +323,7 @@ namespace Pinetime { bool alwaysOnDisplay = false; ClockType clockType = ClockType::H24; + DateFormat dateFormat = DateFormat::DayDDMonthYYYY; WeatherFormat weatherFormat = WeatherFormat::Metric; Notification notificationStatus = Notification::On; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 6671ac9e51..060658c33e 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -597,7 +597,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio currentScreen = std::make_unique(this, std::move(items), settingsController, filesystem); } break; case Apps::SettingTimeFormat: - currentScreen = std::make_unique(settingsController); + currentScreen = std::make_unique(this, settingsController); break; case Apps::SettingWeatherFormat: currentScreen = std::make_unique(settingsController); diff --git a/src/displayapp/screens/settings/SettingClockFormat.cpp b/src/displayapp/screens/settings/SettingClockFormat.cpp new file mode 100644 index 0000000000..fb41271c0e --- /dev/null +++ b/src/displayapp/screens/settings/SettingClockFormat.cpp @@ -0,0 +1,61 @@ +#include "displayapp/screens/settings/SettingClockFormat.h" +#include +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Styles.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + struct ClockOption { + Pinetime::Controllers::Settings::ClockType clockType; + const char* name; + }; + + constexpr std::array clockOptions = {{ + {Pinetime::Controllers::Settings::ClockType::H12, "12-hour"}, + {Pinetime::Controllers::Settings::ClockType::H24, "24-hour"}, + }}; + + std::array CreateClockOptionArray() { + std::array clockOptionArray; + for (size_t i = 0; i < CheckboxList::MaxItems; i++) { + if (i >= clockOptions.size()) { + clockOptionArray[i].name = ""; + clockOptionArray[i].enabled = false; + } else { + clockOptionArray[i].name = clockOptions[i].name; + clockOptionArray[i].enabled = true; + } + } + return clockOptionArray; + } + + uint32_t GetDefaultClockOption(Pinetime::Controllers::Settings::ClockType currentOption) { + for (size_t i = 0; i < clockOptions.size(); i++) { + if (clockOptions[i].clockType == currentOption) { + return i; + } + } + return 0; + } +} + +SettingClockFormat::SettingClockFormat(Pinetime::Controllers::Settings& settingsController) + : clockCheckboxList( + 0, + 1, + "Time format", + Symbols::clock, + GetDefaultClockOption(settingsController.GetClockType()), + [&settings = settingsController](uint32_t index) { + settings.SetClockType(clockOptions[index].clockType); + settings.SaveSettings(); + }, + CreateClockOptionArray()) { +} + +SettingClockFormat::~SettingClockFormat() { + lv_obj_clean(lv_scr_act()); +} diff --git a/src/displayapp/screens/settings/SettingClockFormat.h b/src/displayapp/screens/settings/SettingClockFormat.h new file mode 100644 index 0000000000..99123a4163 --- /dev/null +++ b/src/displayapp/screens/settings/SettingClockFormat.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +#include "components/settings/Settings.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/CheckboxList.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class SettingClockFormat : public Screen { + public: + SettingClockFormat(Pinetime::Controllers::Settings& settingsController); + ~SettingClockFormat() override; + + private: + CheckboxList clockCheckboxList; + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingDateFormat.cpp b/src/displayapp/screens/settings/SettingDateFormat.cpp new file mode 100644 index 0000000000..7019ee3b7d --- /dev/null +++ b/src/displayapp/screens/settings/SettingDateFormat.cpp @@ -0,0 +1,63 @@ +#include "displayapp/screens/settings/SettingDateFormat.h" +#include +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Styles.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + struct DateOption { + Pinetime::Controllers::Settings::DateFormat dateFormat; + const char* name; + }; + + constexpr std::array dateOptions = {{ + {Pinetime::Controllers::Settings::DateFormat::YYYYMMDD, "yyyy-mm-dd"}, + {Pinetime::Controllers::Settings::DateFormat::DDMMYYYY, "dd/mm/yyyy"}, + {Pinetime::Controllers::Settings::DateFormat::MMDDYYYY, "mm/dd/yyyy"}, + {Pinetime::Controllers::Settings::DateFormat::DayDDMonthYYYY, "Day DD Month YYYY"}, + }}; + + std::array CreateDateOptionArray() { + std::array dateOptionArray; + for (size_t i = 0; i < CheckboxList::MaxItems; i++) { + if (i >= dateOptions.size()) { + dateOptionArray[i].name = ""; + dateOptionArray[i].enabled = false; + } else { + dateOptionArray[i].name = dateOptions[i].name; + dateOptionArray[i].enabled = true; + } + } + return dateOptionArray; + } + + uint32_t GetDefaultDateOption(Pinetime::Controllers::Settings::DateFormat currentOption) { + for (size_t i = 0; i < dateOptions.size(); i++) { + if (dateOptions[i].dateFormat == currentOption) { + return i; + } + } + return 0; + } +} + +SettingDateFormat::SettingDateFormat(Pinetime::Controllers::Settings& settingsController) + : dateCheckboxList( + 0, + 1, + "Date format", + Symbols::clock, + GetDefaultDateOption(settingsController.GetDateFormat()), + [&settings = settingsController](uint32_t index) { + settings.SetDateFormat(dateOptions[index].dateFormat); + settings.SaveSettings(); + }, + CreateDateOptionArray()) { +} + +SettingDateFormat::~SettingDateFormat() { + lv_obj_clean(lv_scr_act()); +} diff --git a/src/displayapp/screens/settings/SettingDateFormat.h b/src/displayapp/screens/settings/SettingDateFormat.h new file mode 100644 index 0000000000..94e64a3068 --- /dev/null +++ b/src/displayapp/screens/settings/SettingDateFormat.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +#include "components/settings/Settings.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/CheckboxList.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class SettingDateFormat : public Screen { + public: + SettingDateFormat(Pinetime::Controllers::Settings& settingsController); + ~SettingDateFormat() override; + + private: + CheckboxList dateCheckboxList; + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingTimeFormat.cpp b/src/displayapp/screens/settings/SettingTimeFormat.cpp index df46d8a829..94bcc7f241 100644 --- a/src/displayapp/screens/settings/SettingTimeFormat.cpp +++ b/src/displayapp/screens/settings/SettingTimeFormat.cpp @@ -1,61 +1,44 @@ #include "displayapp/screens/settings/SettingTimeFormat.h" -#include +#include "displayapp/screens/settings/SettingClockFormat.h" +#include "displayapp/screens/settings/SettingDateFormat.h" #include "displayapp/DisplayApp.h" -#include "displayapp/screens/Styles.h" -#include "displayapp/screens/Screen.h" -#include "displayapp/screens/Symbols.h" +#include "displayapp/screens/ScreenList.h" +#include "components/settings/Settings.h" +#include "displayapp/widgets/DotIndicator.h" using namespace Pinetime::Applications::Screens; -namespace { - struct Option { - Pinetime::Controllers::Settings::ClockType clockType; - const char* name; - }; - - constexpr std::array options = {{ - {Pinetime::Controllers::Settings::ClockType::H12, "12-hour"}, - {Pinetime::Controllers::Settings::ClockType::H24, "24-hour"}, - }}; +bool SettingTimeFormat::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + return screens.OnTouchEvent(event); +} - std::array CreateOptionArray() { - std::array optionArray; - for (size_t i = 0; i < CheckboxList::MaxItems; i++) { - if (i >= options.size()) { - optionArray[i].name = ""; - optionArray[i].enabled = false; - } else { - optionArray[i].name = options[i].name; - optionArray[i].enabled = true; - } - } - return optionArray; - } +SettingTimeFormat::SettingTimeFormat(Pinetime::Applications::DisplayApp* app, + Pinetime::Controllers::Settings& settingsController) + : settingsController {settingsController}, + screens {app, + 0, + {[this]() -> std::unique_ptr { + return screenClockFormat(); + }, + [this]() -> std::unique_ptr { + return screenDateFormat(); + }}, + Screens::ScreenListModes::UpDown} { +} - uint32_t GetDefaultOption(Pinetime::Controllers::Settings::ClockType currentOption) { - for (size_t i = 0; i < options.size(); i++) { - if (options[i].clockType == currentOption) { - return i; - } - } - return 0; - } +std::unique_ptr SettingTimeFormat::screenDateFormat() { + Widgets::DotIndicator dotIndicator(1, 2); + dotIndicator.Create(); + return std::make_unique(settingsController); } -SettingTimeFormat::SettingTimeFormat(Pinetime::Controllers::Settings& settingsController) - : checkboxList( - 0, - 1, - "Time format", - Symbols::clock, - GetDefaultOption(settingsController.GetClockType()), - [&settings = settingsController](uint32_t index) { - settings.SetClockType(options[index].clockType); - settings.SaveSettings(); - }, - CreateOptionArray()) { +std::unique_ptr SettingTimeFormat::screenClockFormat() { + Widgets::DotIndicator dotIndicator(0, 2); + dotIndicator.Create(); + return std::make_unique(settingsController); } SettingTimeFormat::~SettingTimeFormat() { lv_obj_clean(lv_scr_act()); } + diff --git a/src/displayapp/screens/settings/SettingTimeFormat.h b/src/displayapp/screens/settings/SettingTimeFormat.h index c33f75c0e9..75230150e6 100644 --- a/src/displayapp/screens/settings/SettingTimeFormat.h +++ b/src/displayapp/screens/settings/SettingTimeFormat.h @@ -1,25 +1,27 @@ #pragma once -#include #include #include - -#include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" -#include "displayapp/screens/CheckboxList.h" +#include "displayapp/screens/ScreenList.h" namespace Pinetime { - namespace Applications { namespace Screens { - class SettingTimeFormat : public Screen { public: - SettingTimeFormat(Pinetime::Controllers::Settings& settingsController); + SettingTimeFormat(DisplayApp* app, + Pinetime::Controllers::Settings& settingsController); ~SettingTimeFormat() override; + bool OnTouchEvent(TouchEvents event) override; + private: - CheckboxList checkboxList; + Controllers::Settings& settingsController; + + ScreenList<2> screens; + std::unique_ptr screenDateFormat(); + std::unique_ptr screenClockFormat(); }; } } From a6a718d9d419c93b4167fe1599679e98f6bc4205 Mon Sep 17 00:00:00 2001 From: Olivier ROMAN Date: Wed, 5 Feb 2025 17:53:04 +0100 Subject: [PATCH 2/9] clang-format --- src/displayapp/screens/settings/SettingTimeFormat.cpp | 4 +--- src/displayapp/screens/settings/SettingTimeFormat.h | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/displayapp/screens/settings/SettingTimeFormat.cpp b/src/displayapp/screens/settings/SettingTimeFormat.cpp index 94bcc7f241..c803eff0ce 100644 --- a/src/displayapp/screens/settings/SettingTimeFormat.cpp +++ b/src/displayapp/screens/settings/SettingTimeFormat.cpp @@ -12,8 +12,7 @@ bool SettingTimeFormat::OnTouchEvent(Pinetime::Applications::TouchEvents event) return screens.OnTouchEvent(event); } -SettingTimeFormat::SettingTimeFormat(Pinetime::Applications::DisplayApp* app, - Pinetime::Controllers::Settings& settingsController) +SettingTimeFormat::SettingTimeFormat(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) : settingsController {settingsController}, screens {app, 0, @@ -41,4 +40,3 @@ std::unique_ptr SettingTimeFormat::screenClockFormat() { SettingTimeFormat::~SettingTimeFormat() { lv_obj_clean(lv_scr_act()); } - diff --git a/src/displayapp/screens/settings/SettingTimeFormat.h b/src/displayapp/screens/settings/SettingTimeFormat.h index 75230150e6..8f91e7eae5 100644 --- a/src/displayapp/screens/settings/SettingTimeFormat.h +++ b/src/displayapp/screens/settings/SettingTimeFormat.h @@ -10,8 +10,7 @@ namespace Pinetime { namespace Screens { class SettingTimeFormat : public Screen { public: - SettingTimeFormat(DisplayApp* app, - Pinetime::Controllers::Settings& settingsController); + SettingTimeFormat(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingTimeFormat() override; bool OnTouchEvent(TouchEvents event) override; From 5a2427cf58bb4991e5a7757e10484ad5f8df0a53 Mon Sep 17 00:00:00 2001 From: Olivier ROMAN Date: Mon, 27 Jan 2025 00:12:57 +0100 Subject: [PATCH 3/9] add mixed screen --- src/CMakeLists.txt | 1 + src/displayapp/UserApps.h | 1 + src/displayapp/apps/Apps.h.in | 1 + src/displayapp/apps/CMakeLists.txt | 1 + src/displayapp/screens/WatchFaceMixed.cpp | 365 ++++++++++++++++++++++ src/displayapp/screens/WatchFaceMixed.h | 127 ++++++++ 6 files changed, 496 insertions(+) create mode 100644 src/displayapp/screens/WatchFaceMixed.cpp create mode 100644 src/displayapp/screens/WatchFaceMixed.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0f44e827fb..5d6fffb765 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -424,6 +424,7 @@ list(APPEND SOURCE_FILES ## Watch faces displayapp/screens/WatchFaceAnalog.cpp displayapp/screens/WatchFaceDigital.cpp + displayapp/screens/WatchFaceMixed.cpp displayapp/screens/WatchFaceInfineat.cpp displayapp/screens/WatchFaceTerminal.cpp displayapp/screens/WatchFacePineTimeStyle.cpp diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h index 67bbfa7d41..cf9d5c534c 100644 --- a/src/displayapp/UserApps.h +++ b/src/displayapp/UserApps.h @@ -10,6 +10,7 @@ #include "displayapp/screens/ApplicationList.h" #include "displayapp/screens/WatchFaceDigital.h" #include "displayapp/screens/WatchFaceAnalog.h" +#include "displayapp/screens/WatchFaceMixed.h" #include "displayapp/screens/WatchFaceCasioStyleG7710.h" #include "displayapp/screens/WatchFaceInfineat.h" #include "displayapp/screens/WatchFacePineTimeStyle.h" diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 2104a267c0..ad07b5284c 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -48,6 +48,7 @@ namespace Pinetime { enum class WatchFace : uint8_t { Digital, Analog, + Mixed, PineTimeStyle, Terminal, Infineat, diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index d78587609e..c4db4ef1e9 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -23,6 +23,7 @@ if(DEFINED ENABLE_WATCHFACES) else() set(DEFAULT_WATCHFACE_TYPES "WatchFace::Digital") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Analog") + set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Mixed") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::PineTimeStyle") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Infineat") diff --git a/src/displayapp/screens/WatchFaceMixed.cpp b/src/displayapp/screens/WatchFaceMixed.cpp new file mode 100644 index 0000000000..6db61ea622 --- /dev/null +++ b/src/displayapp/screens/WatchFaceMixed.cpp @@ -0,0 +1,365 @@ +#include "displayapp/screens/WatchFaceMixed.h" +#include +#include +#include "displayapp/screens/Symbols.h" +#include "displayapp/screens/WeatherSymbols.h" +#include "displayapp/screens/NotificationIcon.h" +#include "components/heartrate/HeartRateController.h" +#include "components/motion/MotionController.h" +#include "components/ble/SimpleWeatherService.h" +#include "components/settings/Settings.h" +#include "displayapp/InfiniTimeTheme.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + constexpr int16_t HourLength = 70; + constexpr int16_t MinuteLength = 90; + constexpr int16_t SecondLength = 110; + + // sin(90) = 1 so the value of _lv_trigo_sin(90) is the scaling factor + const auto LV_TRIG_SCALE = _lv_trigo_sin(90); + + int16_t Cosine(int16_t angle) { + return _lv_trigo_sin(angle + 90); + } + + int16_t Sine(int16_t angle) { + return _lv_trigo_sin(angle); + } + + int16_t CoordinateXRelocate(int16_t x) { + return (x + LV_HOR_RES / 2); + } + + int16_t CoordinateYRelocate(int16_t y) { + return std::abs(y - LV_HOR_RES / 2); + } + + lv_point_t CoordinateRelocate(int16_t radius, int16_t angle) { + return lv_point_t {.x = CoordinateXRelocate(radius * static_cast(Sine(angle)) / LV_TRIG_SCALE), + .y = CoordinateYRelocate(radius * static_cast(Cosine(angle)) / LV_TRIG_SCALE)}; + } + +} + +WatchFaceMixed::WatchFaceMixed(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + const Controllers::AlarmController& alarmController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weather) + : currentDateTime {{}}, + dateTimeController {dateTimeController}, + notificationManager {notificationManager}, + settingsController {settingsController}, + heartRateController {heartRateController}, + motionController {motionController}, + weatherService {weather}, + statusIcons {batteryController, bleController, alarmController} { + + sHour = 0; + sMinute = 0; + sSecond = 0; + + statusIcons.Create(); + + // Clock + + minor_scales = lv_linemeter_create(lv_scr_act(), nullptr); + lv_linemeter_set_scale(minor_scales, 300, 51); + lv_linemeter_set_angle_offset(minor_scales, 180); + lv_obj_set_size(minor_scales, 240, 240); + lv_obj_align(minor_scales, nullptr, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_local_bg_opa(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + lv_obj_set_style_local_scale_width(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); + lv_obj_set_style_local_scale_end_line_width(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 1); + lv_obj_set_style_local_scale_end_color(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + + major_scales = lv_linemeter_create(lv_scr_act(), nullptr); + lv_linemeter_set_scale(major_scales, 300, 11); + lv_linemeter_set_angle_offset(major_scales, 180); + lv_obj_set_size(major_scales, 240, 240); + lv_obj_align(major_scales, nullptr, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_local_bg_opa(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + lv_obj_set_style_local_scale_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 6); + lv_obj_set_style_local_scale_end_line_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); + lv_obj_set_style_local_scale_end_color(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER); + + large_scales = lv_linemeter_create(lv_scr_act(), nullptr); + lv_linemeter_set_scale(large_scales, 180, 3); + lv_linemeter_set_angle_offset(large_scales, 180); + lv_obj_set_size(large_scales, 240, 240); + lv_obj_align(large_scales, nullptr, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_local_bg_opa(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + lv_obj_set_style_local_scale_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 20); + lv_obj_set_style_local_scale_end_line_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); + lv_obj_set_style_local_scale_end_color(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0000A0)); + + twelve = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_align(twelve, LV_LABEL_ALIGN_CENTER); + lv_label_set_text_static(twelve, "12"); + lv_obj_set_pos(twelve, 110, 10); + lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + + // Hands + + minute_body = lv_line_create(lv_scr_act(), nullptr); + minute_body_trace = lv_line_create(lv_scr_act(), nullptr); + hour_body = lv_line_create(lv_scr_act(), nullptr); + hour_body_trace = lv_line_create(lv_scr_act(), nullptr); + second_body = lv_line_create(lv_scr_act(), nullptr); + + lv_style_init(&second_line_style); + lv_style_set_line_width(&second_line_style, LV_STATE_DEFAULT, 3); + lv_style_set_line_color(&second_line_style, LV_STATE_DEFAULT, lv_color_hex(0xC00000)); + lv_style_set_line_rounded(&second_line_style, LV_STATE_DEFAULT, true); + lv_obj_add_style(second_body, LV_LINE_PART_MAIN, &second_line_style); + + lv_style_init(&minute_line_style); + lv_style_set_line_width(&minute_line_style, LV_STATE_DEFAULT, 7); + lv_style_set_line_color(&minute_line_style, LV_STATE_DEFAULT, LV_COLOR_NAVY); + lv_style_set_line_rounded(&minute_line_style, LV_STATE_DEFAULT, true); + lv_obj_add_style(minute_body, LV_LINE_PART_MAIN, &minute_line_style); + + lv_style_init(&minute_line_style_trace); + lv_style_set_line_width(&minute_line_style_trace, LV_STATE_DEFAULT, 3); + lv_style_set_line_color(&minute_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_NAVY); + lv_style_set_line_rounded(&minute_line_style_trace, LV_STATE_DEFAULT, false); + lv_obj_add_style(minute_body_trace, LV_LINE_PART_MAIN, &minute_line_style_trace); + + lv_style_init(&hour_line_style); + lv_style_set_line_width(&hour_line_style, LV_STATE_DEFAULT, 7); + lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, LV_COLOR_NAVY); + lv_style_set_line_rounded(&hour_line_style, LV_STATE_DEFAULT, true); + lv_obj_add_style(hour_body, LV_LINE_PART_MAIN, &hour_line_style); + + lv_style_init(&hour_line_style_trace); + lv_style_set_line_width(&hour_line_style_trace, LV_STATE_DEFAULT, 3); + lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_NAVY); + lv_style_set_line_rounded(&hour_line_style_trace, LV_STATE_DEFAULT, false); + lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_line_style_trace); + + // Time + + label_time = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, -31); + lv_label_set_align(label_time, LV_LABEL_ALIGN_CENTER); + + label_time_ampm = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(label_time_ampm, ""); + lv_obj_set_style_local_text_color(label_time_ampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -30, 30); + lv_label_set_align(label_time_ampm, LV_LABEL_ALIGN_RIGHT); + + label_date = lv_label_create(lv_scr_act(), nullptr); + lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 30); + lv_label_set_align(label_date, LV_LABEL_ALIGN_CENTER); + + // Notification + + notificationIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME); + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); + lv_obj_align(notificationIcon, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0); + + // Weather + + weatherIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons); + lv_label_set_text(weatherIcon, ""); + lv_obj_align(weatherIcon, lv_scr_act(), LV_ALIGN_IN_TOP_MID, -20, 50); + lv_obj_set_auto_realign(weatherIcon, true); + + 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_hex(0x999999)); + lv_label_set_text(temperature, ""); + lv_obj_align(temperature, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 20, 50); + + // HeartBeat + + heartbeatIcon = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat); + lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); + lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + + heartbeatValue = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); + lv_label_set_text_static(heartbeatValue, ""); + lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0); + + // Steps + + stepValue = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); + lv_label_set_text_static(stepValue, "0"); + lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + + stepIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); + lv_label_set_text_static(stepIcon, Symbols::shoe); + lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + + Refresh(); +} + +WatchFaceMixed::~WatchFaceMixed() { + lv_task_del(taskRefresh); + + lv_style_reset(&hour_line_style); + lv_style_reset(&hour_line_style_trace); + lv_style_reset(&minute_line_style); + lv_style_reset(&minute_line_style_trace); + lv_style_reset(&second_line_style); + + lv_obj_clean(lv_scr_act()); +} + +void WatchFaceMixed::UpdateClock() { + uint8_t hour = dateTimeController.Hours(); + uint8_t minute = dateTimeController.Minutes(); + uint8_t second = dateTimeController.Seconds(); + + if (sMinute != minute) { + auto const angle = minute * 6; + minute_point[0] = CoordinateRelocate(30, angle); + minute_point[1] = CoordinateRelocate(MinuteLength, angle); + + minute_point_trace[0] = CoordinateRelocate(5, angle); + minute_point_trace[1] = CoordinateRelocate(31, angle); + + lv_line_set_points(minute_body, minute_point, 2); + lv_line_set_points(minute_body_trace, minute_point_trace, 2); + } + + if (sHour != hour || sMinute != minute) { + sHour = hour; + sMinute = minute; + auto const angle = (hour * 30 + minute / 2); + + hour_point[0] = CoordinateRelocate(30, angle); + hour_point[1] = CoordinateRelocate(HourLength, angle); + + hour_point_trace[0] = CoordinateRelocate(5, angle); + hour_point_trace[1] = CoordinateRelocate(31, angle); + + lv_line_set_points(hour_body, hour_point, 2); + lv_line_set_points(hour_body_trace, hour_point_trace, 2); + } + + if (sSecond != second) { + sSecond = second; + auto const angle = second * 6; + + second_point[0] = CoordinateRelocate(-20, angle); + second_point[1] = CoordinateRelocate(SecondLength, angle); + lv_line_set_points(second_body, second_point, 2); + } + + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + char ampmChar[3] = "AM"; + if (hour == 0) { + hour = 12; + } else if (hour == 12) { + ampmChar[0] = 'P'; + } else if (hour > 12) { + hour = hour - 12; + ampmChar[0] = 'P'; + } + lv_label_set_text(label_time_ampm, ampmChar); + lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute); + lv_obj_realign(label_time); + } else { + lv_label_set_text_fmt(label_time, "%02d:%02d:%02d", hour, minute, second); + lv_obj_realign(label_time); + } +} + +void WatchFaceMixed::UpdateDate() { + lv_label_set_text_fmt(label_date, + "%02d/%02d/%04d", + dateTimeController.Day(), + dateTimeController.Month(), + dateTimeController.Year()); + lv_obj_realign(label_date); +} + +void WatchFaceMixed::UpdateHeartbeat() { + if (heartbeatRunning.Get()) { + lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); + lv_label_set_text_fmt(heartbeatValue, "%d", heartbeat.Get()); + } else { + lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B)); + lv_label_set_text_static(heartbeatValue, ""); + } + + lv_obj_realign(heartbeatIcon); + lv_obj_realign(heartbeatValue); +} + +void WatchFaceMixed::UpdateSteps() { + lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get()); + lv_obj_realign(stepValue); + lv_obj_realign(stepIcon); +} + +void WatchFaceMixed::UpdateWeather() { + auto optCurrentWeather = currentWeather.Get(); + if (optCurrentWeather) { + int16_t temp = optCurrentWeather->temperature.Celsius(); + char tempUnit = 'C'; + if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + temp = optCurrentWeather->temperature.Fahrenheit(); + tempUnit = 'F'; + } + lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); + lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); + } else { + lv_label_set_text_static(temperature, ""); + lv_label_set_text(weatherIcon, ""); + } + lv_obj_realign(temperature); + lv_obj_realign(weatherIcon); +} + +void WatchFaceMixed::Refresh() { + statusIcons.Update(); + + notificationState = notificationManager.AreNewNotificationsAvailable(); + if (notificationState.IsUpdated()) { + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); + } + + currentDateTime = dateTimeController.CurrentDateTime(); + if (currentDateTime.IsUpdated()) { + UpdateClock(); + + currentDate = std::chrono::time_point_cast(currentDateTime.Get()); + if (currentDate.IsUpdated()) { + UpdateDate(); + } + } + + heartbeat = heartRateController.HeartRate(); + heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; + if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) { + UpdateHeartbeat(); + } + + stepCount = motionController.NbSteps(); + if (stepCount.IsUpdated()) { + UpdateSteps(); + } + + currentWeather = weatherService.Current(); + if (currentWeather.IsUpdated()) { + UpdateWeather(); + } +} diff --git a/src/displayapp/screens/WatchFaceMixed.h b/src/displayapp/screens/WatchFaceMixed.h new file mode 100644 index 0000000000..21d6b1cd2d --- /dev/null +++ b/src/displayapp/screens/WatchFaceMixed.h @@ -0,0 +1,127 @@ +#pragma once + +#include +#include +#include +#include +#include "displayapp/screens/Screen.h" +#include "displayapp/widgets/StatusIcons.h" +#include "utility/DirtyValue.h" + +namespace Pinetime { + namespace Controllers { + class Settings; + class Battery; + class Ble; + class NotificationManager; + class AlarmController; + class HeartRateController; + class MotionController; + class SimpleWeatherService; + } + + namespace Applications { + namespace Screens { + + class WatchFaceMixed : public Screen { + public: + WatchFaceMixed(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + const Controllers::AlarmController& alarmController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weather); + + ~WatchFaceMixed() override; + + void Refresh() override; + + private: + uint8_t sHour, sMinute, sSecond; + + Utility::DirtyValue> currentDateTime; + Utility::DirtyValue stepCount {}; + Utility::DirtyValue heartbeat {}; + Utility::DirtyValue heartbeatRunning {}; + Utility::DirtyValue notificationState {false}; + Utility::DirtyValue> currentDate; + Utility::DirtyValue> currentWeather {}; + + lv_obj_t* minor_scales; + lv_obj_t* major_scales; + lv_obj_t* large_scales; + lv_obj_t* twelve; + + lv_obj_t* hour_body; + lv_obj_t* hour_body_trace; + lv_obj_t* minute_body; + lv_obj_t* minute_body_trace; + lv_obj_t* second_body; + + lv_point_t hour_point[2]; + lv_point_t hour_point_trace[2]; + lv_point_t minute_point[2]; + lv_point_t minute_point_trace[2]; + lv_point_t second_point[2]; + + lv_style_t hour_line_style; + lv_style_t hour_line_style_trace; + lv_style_t minute_line_style; + lv_style_t minute_line_style_trace; + lv_style_t second_line_style; + + lv_obj_t* label_time; + lv_obj_t* label_time_ampm; + lv_obj_t* heartbeatIcon; + lv_obj_t* heartbeatValue; + lv_obj_t* stepIcon; + lv_obj_t* stepValue; + lv_obj_t* label_date; + lv_obj_t* notificationIcon; + lv_obj_t* weatherIcon; + lv_obj_t* temperature; + + Controllers::DateTime& dateTimeController; + Controllers::NotificationManager& notificationManager; + Controllers::Settings& settingsController; + Controllers::HeartRateController& heartRateController; + Controllers::MotionController& motionController; + Controllers::SimpleWeatherService& weatherService; + Widgets::StatusIcons statusIcons; + + void UpdateClock(); + void UpdateDate(); + void UpdateHeartbeat(); + void UpdateSteps(); + void UpdateWeather(); + + lv_task_t* taskRefresh; + }; + } + + template <> + struct WatchFaceTraits { + static constexpr WatchFace watchFace = WatchFace::Mixed; + static constexpr const char* name = "Mixed face"; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::WatchFaceMixed(controllers.dateTimeController, + controllers.batteryController, + controllers.bleController, + controllers.alarmController, + controllers.notificationManager, + controllers.settingsController, + controllers.heartRateController, + controllers.motionController, + *controllers.weatherController); + } + + static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { + return true; + } + }; + } +} From 80d4a835734ea480ddfd8588b46e80867d994eb6 Mon Sep 17 00:00:00 2001 From: Olivier ROMAN Date: Mon, 27 Jan 2025 03:04:49 +0100 Subject: [PATCH 4/9] use metallic colors --- src/displayapp/screens/WatchFaceMixed.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/displayapp/screens/WatchFaceMixed.cpp b/src/displayapp/screens/WatchFaceMixed.cpp index 6db61ea622..7dbaea90b8 100644 --- a/src/displayapp/screens/WatchFaceMixed.cpp +++ b/src/displayapp/screens/WatchFaceMixed.cpp @@ -97,13 +97,13 @@ WatchFaceMixed::WatchFaceMixed(Controllers::DateTime& dateTimeController, lv_obj_set_style_local_bg_opa(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_obj_set_style_local_scale_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 20); lv_obj_set_style_local_scale_end_line_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); - lv_obj_set_style_local_scale_end_color(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0000A0)); + lv_obj_set_style_local_scale_end_color(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xE5E5E2)); twelve = lv_label_create(lv_scr_act(), nullptr); lv_label_set_align(twelve, LV_LABEL_ALIGN_CENTER); lv_label_set_text_static(twelve, "12"); lv_obj_set_pos(twelve, 110, 10); - lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFD700)); // Hands @@ -115,31 +115,31 @@ WatchFaceMixed::WatchFaceMixed(Controllers::DateTime& dateTimeController, lv_style_init(&second_line_style); lv_style_set_line_width(&second_line_style, LV_STATE_DEFAULT, 3); - lv_style_set_line_color(&second_line_style, LV_STATE_DEFAULT, lv_color_hex(0xC00000)); + lv_style_set_line_color(&second_line_style, LV_STATE_DEFAULT, LV_COLOR_RED); lv_style_set_line_rounded(&second_line_style, LV_STATE_DEFAULT, true); lv_obj_add_style(second_body, LV_LINE_PART_MAIN, &second_line_style); lv_style_init(&minute_line_style); lv_style_set_line_width(&minute_line_style, LV_STATE_DEFAULT, 7); - lv_style_set_line_color(&minute_line_style, LV_STATE_DEFAULT, LV_COLOR_NAVY); + lv_style_set_line_color(&minute_line_style, LV_STATE_DEFAULT, lv_color_hex(0xB87333)); lv_style_set_line_rounded(&minute_line_style, LV_STATE_DEFAULT, true); lv_obj_add_style(minute_body, LV_LINE_PART_MAIN, &minute_line_style); lv_style_init(&minute_line_style_trace); lv_style_set_line_width(&minute_line_style_trace, LV_STATE_DEFAULT, 3); - lv_style_set_line_color(&minute_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_NAVY); + lv_style_set_line_color(&minute_line_style_trace, LV_STATE_DEFAULT, lv_color_hex(0xB87333)); lv_style_set_line_rounded(&minute_line_style_trace, LV_STATE_DEFAULT, false); lv_obj_add_style(minute_body_trace, LV_LINE_PART_MAIN, &minute_line_style_trace); lv_style_init(&hour_line_style); lv_style_set_line_width(&hour_line_style, LV_STATE_DEFAULT, 7); - lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, LV_COLOR_NAVY); + lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, lv_color_hex(0xB87333)); lv_style_set_line_rounded(&hour_line_style, LV_STATE_DEFAULT, true); lv_obj_add_style(hour_body, LV_LINE_PART_MAIN, &hour_line_style); lv_style_init(&hour_line_style_trace); lv_style_set_line_width(&hour_line_style_trace, LV_STATE_DEFAULT, 3); - lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_NAVY); + lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, lv_color_hex(0xB87333)); lv_style_set_line_rounded(&hour_line_style_trace, LV_STATE_DEFAULT, false); lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_line_style_trace); From 9e2719748f3b1f8eedd0febca0f964b85147dab7 Mon Sep 17 00:00:00 2001 From: Olivier ROMAN Date: Wed, 5 Feb 2025 16:44:19 +0100 Subject: [PATCH 5/9] use the date format setting --- src/displayapp/screens/WatchFaceMixed.cpp | 36 +++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/displayapp/screens/WatchFaceMixed.cpp b/src/displayapp/screens/WatchFaceMixed.cpp index 7dbaea90b8..60b6de2769 100644 --- a/src/displayapp/screens/WatchFaceMixed.cpp +++ b/src/displayapp/screens/WatchFaceMixed.cpp @@ -283,11 +283,37 @@ void WatchFaceMixed::UpdateClock() { } void WatchFaceMixed::UpdateDate() { - lv_label_set_text_fmt(label_date, - "%02d/%02d/%04d", - dateTimeController.Day(), - dateTimeController.Month(), - dateTimeController.Year()); + switch(settingsController.GetDateFormat()){ + case Controllers::Settings::DateFormat::DDMMYYYY: + lv_label_set_text_fmt(label_date, + "%02d/%02d/%04d", + dateTimeController.Day(), + dateTimeController.Month(), + dateTimeController.Year()); + break; + case Controllers::Settings::DateFormat::MMDDYYYY: + lv_label_set_text_fmt(label_date, + "%02d/%02d/%04d", + dateTimeController.Month(), + dateTimeController.Day(), + dateTimeController.Year()); + break; + case Controllers::Settings::DateFormat::YYYYMMDD: + lv_label_set_text_fmt(label_date, + "%04d-%02d-%02d", + dateTimeController.Year(), + dateTimeController.Month(), + dateTimeController.Day()); + break; + case Controllers::Settings::DateFormat::DayDDMonthYYYY: + lv_label_set_text_fmt(label_date, + "%s %02d %s %04d", + Controllers::DateTime::DayOfWeekShortToStringLow(dateTimeController.DayOfWeek()), + dateTimeController.Day(), + Controllers::DateTime::MonthShortToStringLow(dateTimeController.Month()), + dateTimeController.Year()); + break; + } lv_obj_realign(label_date); } From 4f6f0ba18279eb44921f64ca5293eeee1d66528c Mon Sep 17 00:00:00 2001 From: Olivier ROMAN Date: Mon, 27 Jan 2025 16:42:40 +0100 Subject: [PATCH 6/9] Notification icon last while notification still there --- src/displayapp/screens/WatchFaceMixed.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/WatchFaceMixed.cpp b/src/displayapp/screens/WatchFaceMixed.cpp index 60b6de2769..1d4faad57a 100644 --- a/src/displayapp/screens/WatchFaceMixed.cpp +++ b/src/displayapp/screens/WatchFaceMixed.cpp @@ -358,7 +358,7 @@ void WatchFaceMixed::UpdateWeather() { void WatchFaceMixed::Refresh() { statusIcons.Update(); - notificationState = notificationManager.AreNewNotificationsAvailable(); + notificationState = notificationManager.NbNotifications() > 0; if (notificationState.IsUpdated()) { lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); } From a07fbeb518c9bcc6e5565c0b0f8171ae9a20f5e4 Mon Sep 17 00:00:00 2001 From: Olivier ROMAN Date: Mon, 27 Jan 2025 17:05:46 +0100 Subject: [PATCH 7/9] fix hand disappearance bug --- src/displayapp/screens/WatchFaceMixed.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/WatchFaceMixed.cpp b/src/displayapp/screens/WatchFaceMixed.cpp index 1d4faad57a..5647683a6d 100644 --- a/src/displayapp/screens/WatchFaceMixed.cpp +++ b/src/displayapp/screens/WatchFaceMixed.cpp @@ -61,9 +61,9 @@ WatchFaceMixed::WatchFaceMixed(Controllers::DateTime& dateTimeController, weatherService {weather}, statusIcons {batteryController, bleController, alarmController} { - sHour = 0; - sMinute = 0; - sSecond = 0; + sHour = 99; + sMinute = 99; + sSecond = 99; statusIcons.Create(); From 15f62933cf29dd7ff853c445d4cc5f3a06420dd7 Mon Sep 17 00:00:00 2001 From: Olivier ROMAN Date: Wed, 5 Feb 2025 17:54:10 +0100 Subject: [PATCH 8/9] clang-format --- src/displayapp/screens/WatchFaceMixed.cpp | 30 +++++++---------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/displayapp/screens/WatchFaceMixed.cpp b/src/displayapp/screens/WatchFaceMixed.cpp index 5647683a6d..c974769860 100644 --- a/src/displayapp/screens/WatchFaceMixed.cpp +++ b/src/displayapp/screens/WatchFaceMixed.cpp @@ -283,35 +283,23 @@ void WatchFaceMixed::UpdateClock() { } void WatchFaceMixed::UpdateDate() { - switch(settingsController.GetDateFormat()){ + switch (settingsController.GetDateFormat()) { case Controllers::Settings::DateFormat::DDMMYYYY: - lv_label_set_text_fmt(label_date, - "%02d/%02d/%04d", - dateTimeController.Day(), - dateTimeController.Month(), - dateTimeController.Year()); + lv_label_set_text_fmt(label_date, "%02d/%02d/%04d", dateTimeController.Day(), dateTimeController.Month(), dateTimeController.Year()); break; case Controllers::Settings::DateFormat::MMDDYYYY: - lv_label_set_text_fmt(label_date, - "%02d/%02d/%04d", - dateTimeController.Month(), - dateTimeController.Day(), - dateTimeController.Year()); + lv_label_set_text_fmt(label_date, "%02d/%02d/%04d", dateTimeController.Month(), dateTimeController.Day(), dateTimeController.Year()); break; case Controllers::Settings::DateFormat::YYYYMMDD: - lv_label_set_text_fmt(label_date, - "%04d-%02d-%02d", - dateTimeController.Year(), - dateTimeController.Month(), - dateTimeController.Day()); + lv_label_set_text_fmt(label_date, "%04d-%02d-%02d", dateTimeController.Year(), dateTimeController.Month(), dateTimeController.Day()); break; case Controllers::Settings::DateFormat::DayDDMonthYYYY: lv_label_set_text_fmt(label_date, - "%s %02d %s %04d", - Controllers::DateTime::DayOfWeekShortToStringLow(dateTimeController.DayOfWeek()), - dateTimeController.Day(), - Controllers::DateTime::MonthShortToStringLow(dateTimeController.Month()), - dateTimeController.Year()); + "%s %02d %s %04d", + Controllers::DateTime::DayOfWeekShortToStringLow(dateTimeController.DayOfWeek()), + dateTimeController.Day(), + Controllers::DateTime::MonthShortToStringLow(dateTimeController.Month()), + dateTimeController.Year()); break; } lv_obj_realign(label_date); From f21c39428cc28e6c4c3d85531879681923fb09a6 Mon Sep 17 00:00:00 2001 From: Olivier ROMAN Date: Wed, 12 Feb 2025 22:56:15 +0100 Subject: [PATCH 9/9] color weather --- src/displayapp/screens/WatchFaceMixed.cpp | 77 ++++++++++++++++++++++- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/WatchFaceMixed.cpp b/src/displayapp/screens/WatchFaceMixed.cpp index c974769860..bd997a4d3a 100644 --- a/src/displayapp/screens/WatchFaceMixed.cpp +++ b/src/displayapp/screens/WatchFaceMixed.cpp @@ -1,5 +1,7 @@ #include "displayapp/screens/WatchFaceMixed.h" #include +#include +#include #include #include "displayapp/screens/Symbols.h" #include "displayapp/screens/WeatherSymbols.h" @@ -157,7 +159,7 @@ WatchFaceMixed::WatchFaceMixed(Controllers::DateTime& dateTimeController, lv_label_set_align(label_time_ampm, LV_LABEL_ALIGN_RIGHT); label_date = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 30); + lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 20); lv_label_set_align(label_date, LV_LABEL_ALIGN_CENTER); // Notification @@ -173,13 +175,13 @@ WatchFaceMixed::WatchFaceMixed(Controllers::DateTime& dateTimeController, lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons); lv_label_set_text(weatherIcon, ""); - lv_obj_align(weatherIcon, lv_scr_act(), LV_ALIGN_IN_TOP_MID, -20, 50); + lv_obj_align(weatherIcon, lv_scr_act(), LV_ALIGN_CENTER, -23, 50); lv_obj_set_auto_realign(weatherIcon, true); 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_hex(0x999999)); lv_label_set_text(temperature, ""); - lv_obj_align(temperature, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 20, 50); + lv_obj_align(temperature, lv_scr_act(), LV_ALIGN_CENTER, 22, 50); // HeartBeat @@ -324,20 +326,89 @@ void WatchFaceMixed::UpdateSteps() { lv_obj_realign(stepIcon); } +uint32_t linear_color_gradient(uint32_t startingColor, uint32_t endingColor, uint8_t progress){ + constexpr decltype(progress) maxProgress = std::numeric_limits::max(); + uint32_t res = 0; + res += ((maxProgress-progress)*((startingColor&0xff0000) >> 16) + progress*((endingColor&0xff0000) >> 16)) / maxProgress; + res <<= 8; + res += ((maxProgress - progress) * ((startingColor&0x00ff00) >> 8) + progress * ((endingColor&0x00ff00) >> 8)) / maxProgress; + res <<= 8; + res += ((maxProgress - progress) * (startingColor&0x0000ff) + progress * (endingColor&0x0000ff)) / maxProgress; + + return res; +} + void WatchFaceMixed::UpdateWeather() { auto optCurrentWeather = currentWeather.Get(); if (optCurrentWeather) { int16_t temp = optCurrentWeather->temperature.Celsius(); char tempUnit = 'C'; + + enum TempColor : uint32_t { + VeryCold = 0x6495ed, + Freezing = 0x00ffff, + Cold = 0x808080, + Hot = 0xfafd0f, + VeryHot = 0xff0000 + }; + if(temp < -30) { + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(TempColor::VeryCold)); + } else if(-30 <= temp && temp < 0) { + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(linear_color_gradient(TempColor::VeryCold, TempColor::Freezing, 255*(temp+30)/30))); + } else if(0 <= temp && temp < 10) { + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(linear_color_gradient(TempColor::Freezing, TempColor::Cold, 255*temp/10))); + } else if(10 <= temp && temp < 18) { + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(linear_color_gradient(TempColor::Cold, TempColor::Hot, 255*(temp-10)/8))); + } else if(18 <= temp && temp < 50) { + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(linear_color_gradient(TempColor::Hot, TempColor::VeryHot, 255*(temp-18)/32))); + } else if(temp >= 50) { + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(TempColor::VeryHot)); + } if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { temp = optCurrentWeather->temperature.Fahrenheit(); tempUnit = 'F'; } lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); + lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); + using Icons = Pinetime::Controllers::SimpleWeatherService::Icons; + switch(optCurrentWeather->iconId){ + case Icons::Sun: + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xfafd0f)); + break; + case Icons::CloudsSun: + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xc4c745)); + break; + case Icons::Clouds: + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xcbd0d2)); + break; + case Icons::BrokenClouds: + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x7e8796)); + break; + case Icons::CloudShowerHeavy: + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000080)); + break; + case Icons::CloudSunRain: + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xbfddea)); + break; + case Icons::Thunderstorm: + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xC4893D)); + break; + case Icons::Snow: + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xffffff)); + break; + case Icons::Smog: + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x697379)); + break; + default: + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + break; + } } else { lv_label_set_text_static(temperature, ""); + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); lv_label_set_text(weatherIcon, ""); + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); } lv_obj_realign(temperature); lv_obj_realign(weatherIcon);