diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bcf40920..28359735 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -404,6 +404,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Motion.cpp displayapp/screens/FlashLight.cpp displayapp/screens/List.cpp + displayapp/screens/CheckboxList.cpp displayapp/screens/BatteryInfo.cpp displayapp/screens/Steps.cpp displayapp/screens/Timer.cpp @@ -433,6 +434,7 @@ list(APPEND SOURCE_FILES displayapp/screens/WatchFaceDigital.cpp displayapp/screens/WatchFaceTerminal.cpp displayapp/screens/WatchFacePineTimeStyle.cpp + displayapp/screens/WatchFaceSimpleAnalog.cpp ## @@ -609,6 +611,7 @@ set(INCLUDE_FILES displayapp/screens/FirmwareUpdate.h displayapp/screens/FirmwareValidation.h displayapp/screens/ApplicationList.h + displayapp/screens/CheckboxList.h displayapp/Apps.h displayapp/screens/Notifications.h displayapp/screens/HeartRate.h diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 44a1a85c..fd25822e 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -128,6 +128,13 @@ namespace Pinetime { Notification GetNotificationStatus() const { return settings.notificationStatus; }; + void SetWatchfacesMenu(uint8_t menu) { + watchFacesMenu = menu; + }; + + uint8_t GetWatchfacesMenu() const { + return watchFacesMenu; + }; void SetScreenTimeOut(uint32_t timeout) { if (timeout != settings.screenTimeOut) { @@ -140,15 +147,14 @@ namespace Pinetime { return settings.screenTimeOut; }; - void SetShakeThreshold(uint16_t thresh){ - if(settings.shakeWakeThreshold != thresh){ - settings.shakeWakeThreshold = thresh; - settingsChanged = true; + void SetShakeThreshold(uint16_t thresh) { + if (settings.shakeWakeThreshold != thresh) { + settings.shakeWakeThreshold = thresh; + settingsChanged = true; } - } - int16_t GetShakeThreshold() const{ + int16_t GetShakeThreshold() const { return settings.shakeWakeThreshold; } @@ -195,20 +201,20 @@ namespace Pinetime { if (goal != settings.stepsGoal) { settingsChanged = true; } - settings.stepsGoal = goal; + settings.stepsGoal = goal; }; - + uint32_t GetStepsGoal() const { return settings.stepsGoal; }; - void SetBleRadioEnabled(bool enabled) { - bleRadioEnabled = enabled; - }; + void SetBleRadioEnabled(bool enabled) { + bleRadioEnabled = enabled; + }; - bool GetBleRadioEnabled() const { - return bleRadioEnabled; - }; + bool GetBleRadioEnabled() const { + return bleRadioEnabled; + }; private: Pinetime::Controllers::FS& fs; @@ -237,6 +243,7 @@ namespace Pinetime { uint8_t appMenu = 0; uint8_t settingsMenu = 0; + uint8_t watchFacesMenu = 0; /* ble state is intentionally not saved with the other watch settings and initialized * to off (false) on every boot because we always want ble to be enabled on startup */ diff --git a/src/displayapp/screens/CheckboxList.cpp b/src/displayapp/screens/CheckboxList.cpp new file mode 100644 index 00000000..ee64167d --- /dev/null +++ b/src/displayapp/screens/CheckboxList.cpp @@ -0,0 +1,118 @@ +#include "displayapp/screens/CheckboxList.h" +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Styles.h" +#include "displayapp/screens/Symbols.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + static void event_handler(lv_obj_t* obj, lv_event_t event) { + CheckboxList* screen = static_cast(obj->user_data); + screen->UpdateSelected(obj, event); + } + +} + +CheckboxList::CheckboxList(const uint8_t screenID, + const uint8_t numScreens, + DisplayApp* app, + Controllers::Settings& settingsController, + const char* optionsTitle, + const char* optionsSymbol, + void (Controllers::Settings::*SetOptionIndex)(uint8_t), + uint8_t (Controllers::Settings::*GetOptionIndex)() const, + std::array options) + : Screen(app), + screenID {screenID}, + settingsController {settingsController}, + SetOptionIndex {SetOptionIndex}, + GetOptionIndex {GetOptionIndex}, + options {options} { + + settingsController.SetWatchfacesMenu(screenID); + + // Set the background to Black + lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + + if (numScreens > 1) { + pageIndicatorBasePoints[0].x = LV_HOR_RES - 1; + pageIndicatorBasePoints[0].y = 0; + pageIndicatorBasePoints[1].x = LV_HOR_RES - 1; + pageIndicatorBasePoints[1].y = LV_VER_RES; + + pageIndicatorBase = lv_line_create(lv_scr_act(), NULL); + lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3); + lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111)); + lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2); + + const uint16_t indicatorSize = LV_VER_RES / numScreens; + const uint16_t indicatorPos = indicatorSize * screenID; + + pageIndicatorPoints[0].x = LV_HOR_RES - 1; + pageIndicatorPoints[0].y = indicatorPos; + pageIndicatorPoints[1].x = LV_HOR_RES - 1; + pageIndicatorPoints[1].y = indicatorPos + indicatorSize; + + pageIndicator = lv_line_create(lv_scr_act(), NULL); + lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3); + lv_obj_set_style_local_line_color(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + lv_line_set_points(pageIndicator, pageIndicatorPoints, 2); + } + + lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); + + lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); + lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); + lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); + + lv_obj_set_pos(container1, 10, 60); + lv_obj_set_width(container1, LV_HOR_RES - 20); + lv_obj_set_height(container1, LV_VER_RES - 50); + lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); + + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(title, optionsTitle); + lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); + lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 15); + + lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_label_set_text_static(icon, optionsSymbol); + lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); + lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); + + for (unsigned int i = 0; i < options.size(); i++) { + if (strcmp(options[i], "")) { + cbOption[i] = lv_checkbox_create(container1, nullptr); + lv_checkbox_set_text(cbOption[i], options[i]); + cbOption[i]->user_data = this; + lv_obj_set_event_cb(cbOption[i], event_handler); + SetRadioButtonStyle(cbOption[i]); + + if (static_cast((settingsController.*GetOptionIndex)() - MAXLISTITEMS * screenID) == i) { + lv_checkbox_set_checked(cbOption[i], true); + } + } + } +} + +CheckboxList::~CheckboxList() { + lv_obj_clean(lv_scr_act()); + settingsController.SaveSettings(); +} + +void CheckboxList::UpdateSelected(lv_obj_t* object, lv_event_t event) { + if (event == LV_EVENT_VALUE_CHANGED) { + for (unsigned int i = 0; i < options.size(); i++) { + if (strcmp(options[i], "")) { + if (object == cbOption[i]) { + lv_checkbox_set_checked(cbOption[i], true); + (settingsController.*SetOptionIndex)(MAXLISTITEMS * screenID + i); + } else { + lv_checkbox_set_checked(cbOption[i], false); + } + } + } + } +} diff --git a/src/displayapp/screens/CheckboxList.h b/src/displayapp/screens/CheckboxList.h new file mode 100644 index 00000000..6660acde --- /dev/null +++ b/src/displayapp/screens/CheckboxList.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include "displayapp/screens/Screen.h" +#include "displayapp/Apps.h" +#include "components/settings/Settings.h" + +#define MAXLISTITEMS 4 + +namespace Pinetime { + namespace Applications { + namespace Screens { + class CheckboxList : public Screen { + public: + CheckboxList(const uint8_t screenID, + const uint8_t numScreens, + DisplayApp* app, + Controllers::Settings& settingsController, + const char* optionsTitle, + const char* optionsSymbol, + void (Controllers::Settings::*SetOptionIndex)(uint8_t), + uint8_t (Controllers::Settings::*GetOptionIndex)() const, + std::array options); + + ~CheckboxList() override; + + void UpdateSelected(lv_obj_t* object, lv_event_t event); + + private: + const uint8_t screenID; + Controllers::Settings& settingsController; + const char* optionsTitle; + const char* optionsSymbol; + void (Controllers::Settings::*SetOptionIndex)(uint8_t); + uint8_t (Controllers::Settings::*GetOptionIndex)() const; + std::array options; + + lv_obj_t* cbOption[MAXLISTITEMS]; + + lv_point_t pageIndicatorBasePoints[2]; + lv_point_t pageIndicatorPoints[2]; + lv_obj_t* pageIndicatorBase; + lv_obj_t* pageIndicator; + }; + } + } +} diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp index de5ae712..adb741ce 100644 --- a/src/displayapp/screens/Clock.cpp +++ b/src/displayapp/screens/Clock.cpp @@ -11,6 +11,7 @@ #include "displayapp/screens/WatchFaceDigital.h" #include "displayapp/screens/WatchFaceTerminal.h" #include "displayapp/screens/WatchFaceAnalog.h" +#include "displayapp/screens/WatchFaceSimpleAnalog.h" #include "displayapp/screens/WatchFacePineTimeStyle.h" using namespace Pinetime::Applications::Screens; @@ -45,6 +46,9 @@ Clock::Clock(DisplayApp* app, case 3: return WatchFaceTerminalScreen(); break; + case 4: + return WatchFaceSimpleAnalogScreen(); + break; } return WatchFaceDigitalScreen(); }()} { @@ -74,15 +78,20 @@ std::unique_ptr Clock::WatchFaceDigitalScreen() { motionController); } +std::unique_ptr Clock::WatchFaceSimpleAnalogScreen() { + return std::make_unique(app, + dateTimeController, + batteryController, + bleController, + notificatioManager, + settingsController, + heartRateController, + motionController); +} + std::unique_ptr Clock::WatchFaceAnalogScreen() { - return std::make_unique(app, - dateTimeController, - batteryController, - bleController, - notificatioManager, - settingsController, - heartRateController, - motionController); + return std::make_unique( + app, dateTimeController, batteryController, bleController, notificatioManager, settingsController); } std::unique_ptr Clock::WatchFacePineTimeStyleScreen() { diff --git a/src/displayapp/screens/Clock.h b/src/displayapp/screens/Clock.h index 1ba752c7..582e12f8 100644 --- a/src/displayapp/screens/Clock.h +++ b/src/displayapp/screens/Clock.h @@ -48,6 +48,7 @@ namespace Pinetime { std::unique_ptr WatchFaceAnalogScreen(); std::unique_ptr WatchFacePineTimeStyleScreen(); std::unique_ptr WatchFaceTerminalScreen(); + std::unique_ptr WatchFaceSimpleAnalogScreen(); }; } } diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index 7e86e98d..251a560f 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -5,16 +5,16 @@ #include "displayapp/screens/BleIcon.h" #include "displayapp/screens/Symbols.h" #include "displayapp/screens/NotificationIcon.h" -#include "components/heartrate/HeartRateController.h" -#include "components/motion/MotionController.h" #include "components/settings/Settings.h" +LV_IMG_DECLARE(bg_clock); + using namespace Pinetime::Applications::Screens; namespace { - constexpr int16_t HourLength = 60; - constexpr int16_t MinuteLength = 95; - constexpr int16_t SecondLength = 97; + 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); @@ -47,30 +47,22 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, Controllers::Battery& batteryController, Controllers::Ble& bleController, Controllers::NotificationManager& notificationManager, - Controllers::Settings& settingsController, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController) + Controllers::Settings& settingsController) : Screen(app), currentDateTime {{}}, dateTimeController {dateTimeController}, batteryController {batteryController}, bleController {bleController}, notificationManager {notificationManager}, - settingsController {settingsController}, - heartRateController {heartRateController}, - motionController {motionController} { + settingsController {settingsController} { sHour = 99; sMinute = 99; sSecond = 99; - stepsMeter = lv_linemeter_create(lv_scr_act(), nullptr); - lv_linemeter_set_range(stepsMeter, 0, 12); - lv_linemeter_set_scale(stepsMeter, 360, 13); - lv_linemeter_set_angle_offset(stepsMeter, 180); - lv_obj_set_size(stepsMeter, LV_HOR_RES, LV_VER_RES); - lv_obj_align(stepsMeter, nullptr, LV_ALIGN_CENTER, 0, 0); - lv_obj_set_style_local_pad_all(stepsMeter, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_t* bg_clock_img = lv_img_create(lv_scr_act(), NULL); + lv_img_set_src(bg_clock_img, &bg_clock); + lv_obj_align(bg_clock_img, NULL, LV_ALIGN_CENTER, 0, 0); batteryIcon.Create(lv_scr_act()); lv_obj_align(batteryIcon.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); @@ -80,63 +72,24 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, lv_obj_set_style_local_text_color(plugIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); lv_obj_align(plugIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); - bleIcon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0082FC)); - lv_label_set_text_static(bleIcon, Symbols::bluetooth); - lv_obj_align(bleIcon, plugIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0); - - notificationIcon = lv_label_create(lv_scr_act(), nullptr); + notificationIcon = lv_label_create(lv_scr_act(), NULL); lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00)); lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); - lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); - - 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); + lv_obj_align(notificationIcon, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); // Date - Day / Week day - label_date_day = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x90, 0x90, 0x90)); - lv_label_set_text_fmt(label_date_day, "%s %02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day()); + label_date_day = lv_label_create(lv_scr_act(), NULL); + lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0)); + lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day()); lv_label_set_align(label_date_day, LV_LABEL_ALIGN_CENTER); - lv_obj_align(label_date_day, nullptr, LV_ALIGN_CENTER, 60, -2); + lv_obj_align(label_date_day, NULL, LV_ALIGN_CENTER, 50, 0); - minute_body_trace = lv_line_create(lv_scr_act(), nullptr); - hour_body_trace = lv_line_create(lv_scr_act(), nullptr); - minute_body = lv_line_create(lv_scr_act(), nullptr); - hour_body = lv_line_create(lv_scr_act(), nullptr); - second_body = lv_line_create(lv_scr_act(), nullptr); - - lv_style_init(&minute_line_style); - lv_style_set_line_width(&minute_line_style, LV_STATE_DEFAULT, 9); - lv_style_set_line_color(&minute_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); - 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_trace_line_style); - lv_style_set_line_width(&minute_trace_line_style, LV_STATE_DEFAULT, 5); - lv_style_set_line_color(&minute_trace_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_line_rounded(&minute_trace_line_style, LV_STATE_DEFAULT, true); - lv_obj_add_style(minute_body_trace, LV_LINE_PART_MAIN, &minute_trace_line_style); - - lv_style_init(&hour_line_style); - lv_style_set_line_width(&hour_line_style, LV_STATE_DEFAULT, 9); - lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); - 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_trace_line_style); - lv_style_set_line_width(&hour_trace_line_style, LV_STATE_DEFAULT, 5); - lv_style_set_line_color(&hour_trace_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_line_rounded(&hour_trace_line_style, LV_STATE_DEFAULT, true); - lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_trace_line_style); + minute_body = lv_line_create(lv_scr_act(), NULL); + minute_body_trace = lv_line_create(lv_scr_act(), NULL); + hour_body = lv_line_create(lv_scr_act(), NULL); + hour_body_trace = lv_line_create(lv_scr_act(), NULL); + second_body = lv_line_create(lv_scr_act(), NULL); lv_style_init(&second_line_style); lv_style_set_line_width(&second_line_style, LV_STATE_DEFAULT, 3); @@ -144,11 +97,29 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, 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); - dot = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_size(dot, 10, 10); - lv_obj_align(dot, nullptr, LV_ALIGN_CENTER, 0, 0); - lv_obj_set_style_local_radius(dot, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_obj_set_style_local_bg_color(dot, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + 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_WHITE); + 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_WHITE); + 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_WHITE); + 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_WHITE); + 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); taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); @@ -159,7 +130,9 @@ WatchFaceAnalog::~WatchFaceAnalog() { 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()); @@ -172,15 +145,14 @@ void WatchFaceAnalog::UpdateClock() { if (sMinute != minute) { auto const angle = minute * 6; - - minute_point[0] = CoordinateRelocate(16, angle); + minute_point[0] = CoordinateRelocate(30, angle); minute_point[1] = CoordinateRelocate(MinuteLength, angle); - minute_trace_point[0] = CoordinateRelocate(0, angle); - minute_trace_point[1] = minute_point[0]; + 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_trace_point, 2); + lv_line_set_points(minute_body_trace, minute_point_trace, 2); } if (sHour != hour || sMinute != minute) { @@ -188,14 +160,14 @@ void WatchFaceAnalog::UpdateClock() { sMinute = minute; auto const angle = (hour * 30 + minute / 2); - hour_point[0] = CoordinateRelocate(16, angle); + hour_point[0] = CoordinateRelocate(30, angle); hour_point[1] = CoordinateRelocate(HourLength, angle); - hour_trace_point[0] = CoordinateRelocate(0, angle); - hour_trace_point[1] = hour_point[1]; + 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_trace_point, 2); + lv_line_set_points(hour_body_trace, hour_point_trace, 2); } if (sSecond != second) { @@ -204,7 +176,6 @@ void WatchFaceAnalog::UpdateClock() { second_point[0] = CoordinateRelocate(-20, angle); second_point[1] = CoordinateRelocate(SecondLength, angle); - lv_line_set_points(second_body, second_point, 2); } } @@ -233,14 +204,6 @@ void WatchFaceAnalog::Refresh() { } } - bleState = bleController.IsConnected(); - bleRadioEnabled = bleController.IsRadioEnabled(); - if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { - lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get())); - } - lv_obj_realign(plugIcon); - lv_obj_realign(bleIcon); - notificationState = notificationManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { @@ -257,40 +220,11 @@ void WatchFaceAnalog::Refresh() { UpdateClock(); if ((month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) { - lv_label_set_text_fmt(label_date_day, "%s %02i", dateTimeController.DayOfWeekShortToString(), day); + lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), day); currentMonth = month; currentDayOfWeek = dayOfWeek; currentDay = day; } } - - heartbeat = heartRateController.HeartRate(); - heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; - if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) { - 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); - } - - stepCount = motionController.NbSteps(); - motionSensorOk = motionController.IsSensorOk(); - if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) { - uint32_t goal = settingsController.GetStepsGoal(); - uint32_t steps = stepCount.Get(); - int32_t steps_value; - if (steps > goal) - steps_value = 12; - else - steps_value = ((float) steps / goal) * 12; - - lv_linemeter_set_value(stepsMeter, steps_value); - } } diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h index f634ea37..04d9e711 100644 --- a/src/displayapp/screens/WatchFaceAnalog.h +++ b/src/displayapp/screens/WatchFaceAnalog.h @@ -17,8 +17,6 @@ namespace Pinetime { class Battery; class Ble; class NotificationManager; - class HeartRateController; - class MotionController; } namespace Applications { namespace Screens { @@ -30,9 +28,7 @@ namespace Pinetime { Controllers::Battery& batteryController, Controllers::Ble& bleController, Controllers::NotificationManager& notificationManager, - Controllers::Settings& settingsController, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController); + Controllers::Settings& settingsController); ~WatchFaceAnalog() override; @@ -49,14 +45,7 @@ namespace Pinetime { DirtyValue isCharging {}; DirtyValue> currentDateTime; DirtyValue notificationState {false}; - DirtyValue bleState {}; - DirtyValue bleRadioEnabled {}; - DirtyValue motionSensorOk {}; - DirtyValue stepCount {}; - DirtyValue heartbeat {}; - DirtyValue heartbeatRunning {}; - lv_obj_t* dot; lv_obj_t* hour_body; lv_obj_t* hour_body_trace; lv_obj_t* minute_body; @@ -64,24 +53,20 @@ namespace Pinetime { lv_obj_t* second_body; lv_point_t hour_point[2]; - lv_point_t hour_trace_point[2]; + lv_point_t hour_point_trace[2]; lv_point_t minute_point[2]; - lv_point_t minute_trace_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_trace_line_style; + lv_style_t hour_line_style_trace; lv_style_t minute_line_style; - lv_style_t minute_trace_line_style; + lv_style_t minute_line_style_trace; lv_style_t second_line_style; lv_obj_t* label_date_day; lv_obj_t* plugIcon; - lv_obj_t* bleIcon; lv_obj_t* notificationIcon; - lv_obj_t* heartbeatIcon; - lv_obj_t* heartbeatValue; - lv_obj_t* stepsMeter; BatteryIcon batteryIcon; @@ -90,8 +75,6 @@ namespace Pinetime { Controllers::Ble& bleController; Controllers::NotificationManager& notificationManager; Controllers::Settings& settingsController; - Controllers::HeartRateController& heartRateController; - Controllers::MotionController& motionController; void UpdateClock(); void SetBatteryIcon(); diff --git a/src/displayapp/screens/WatchFaceSimpleAnalog.cpp b/src/displayapp/screens/WatchFaceSimpleAnalog.cpp new file mode 100644 index 00000000..0d63147b --- /dev/null +++ b/src/displayapp/screens/WatchFaceSimpleAnalog.cpp @@ -0,0 +1,298 @@ +#include "displayapp/screens/WatchFaceSimpleAnalog.h" +#include +#include +#include "displayapp/screens/BatteryIcon.h" +#include "displayapp/screens/BleIcon.h" +#include "displayapp/screens/Symbols.h" +#include "displayapp/screens/NotificationIcon.h" +#include "components/heartrate/HeartRateController.h" +#include "components/motion/MotionController.h" +#include "components/settings/Settings.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + constexpr int16_t HourLength = 60; + constexpr int16_t MinuteLength = 95; + constexpr int16_t SecondLength = 97; + + // 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)}; + } + +} + +WatchFaceSimpleAnalog::WatchFaceSimpleAnalog(Pinetime::Applications::DisplayApp* app, + Controllers::DateTime& dateTimeController, + Controllers::Battery& batteryController, + Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController) + : Screen(app), + currentDateTime {{}}, + dateTimeController {dateTimeController}, + batteryController {batteryController}, + bleController {bleController}, + notificationManager {notificationManager}, + settingsController {settingsController}, + heartRateController {heartRateController}, + motionController {motionController} { + + sHour = 99; + sMinute = 99; + sSecond = 99; + + stepsMeter = lv_linemeter_create(lv_scr_act(), nullptr); + lv_linemeter_set_range(stepsMeter, 0, 12); + lv_linemeter_set_scale(stepsMeter, 360, 13); + lv_linemeter_set_angle_offset(stepsMeter, 180); + lv_obj_set_size(stepsMeter, LV_HOR_RES, LV_VER_RES); + lv_obj_align(stepsMeter, nullptr, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_local_pad_all(stepsMeter, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 0); + + batteryIcon.Create(lv_scr_act()); + lv_obj_align(batteryIcon.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); + + plugIcon = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(plugIcon, Symbols::plug); + lv_obj_set_style_local_text_color(plugIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_obj_align(plugIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); + + bleIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0082FC)); + lv_label_set_text_static(bleIcon, Symbols::bluetooth); + lv_obj_align(bleIcon, plugIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0); + + 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_hex(0x00FF00)); + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); + lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); + + 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); + + // Date - Day / Week day + + label_date_day = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x90, 0x90, 0x90)); + lv_label_set_text_fmt(label_date_day, "%s %02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day()); + lv_label_set_align(label_date_day, LV_LABEL_ALIGN_CENTER); + lv_obj_align(label_date_day, nullptr, LV_ALIGN_CENTER, 60, -2); + + minute_body_trace = lv_line_create(lv_scr_act(), nullptr); + hour_body_trace = lv_line_create(lv_scr_act(), nullptr); + minute_body = lv_line_create(lv_scr_act(), nullptr); + hour_body = lv_line_create(lv_scr_act(), nullptr); + second_body = lv_line_create(lv_scr_act(), nullptr); + + lv_style_init(&minute_line_style); + lv_style_set_line_width(&minute_line_style, LV_STATE_DEFAULT, 9); + lv_style_set_line_color(&minute_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + 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_trace_line_style); + lv_style_set_line_width(&minute_trace_line_style, LV_STATE_DEFAULT, 5); + lv_style_set_line_color(&minute_trace_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_line_rounded(&minute_trace_line_style, LV_STATE_DEFAULT, true); + lv_obj_add_style(minute_body_trace, LV_LINE_PART_MAIN, &minute_trace_line_style); + + lv_style_init(&hour_line_style); + lv_style_set_line_width(&hour_line_style, LV_STATE_DEFAULT, 9); + lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + 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_trace_line_style); + lv_style_set_line_width(&hour_trace_line_style, LV_STATE_DEFAULT, 5); + lv_style_set_line_color(&hour_trace_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_line_rounded(&hour_trace_line_style, LV_STATE_DEFAULT, true); + lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_trace_line_style); + + 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_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); + + dot = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_size(dot, 10, 10); + lv_obj_align(dot, nullptr, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_local_radius(dot, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_style_local_bg_color(dot, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + + Refresh(); +} + +WatchFaceSimpleAnalog::~WatchFaceSimpleAnalog() { + lv_task_del(taskRefresh); + + lv_style_reset(&hour_line_style); + lv_style_reset(&hour_trace_line_style); + lv_style_reset(&minute_line_style); + lv_style_reset(&minute_trace_line_style); + lv_style_reset(&second_line_style); + + lv_obj_clean(lv_scr_act()); +} + +void WatchFaceSimpleAnalog::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(16, angle); + minute_point[1] = CoordinateRelocate(MinuteLength, angle); + + minute_trace_point[0] = CoordinateRelocate(0, angle); + minute_trace_point[1] = minute_point[0]; + + lv_line_set_points(minute_body, minute_point, 2); + lv_line_set_points(minute_body_trace, minute_trace_point, 2); + } + + if (sHour != hour || sMinute != minute) { + sHour = hour; + sMinute = minute; + auto const angle = (hour * 30 + minute / 2); + + hour_point[0] = CoordinateRelocate(16, angle); + hour_point[1] = CoordinateRelocate(HourLength, angle); + + hour_trace_point[0] = CoordinateRelocate(0, angle); + hour_trace_point[1] = hour_point[1]; + + lv_line_set_points(hour_body, hour_point, 2); + lv_line_set_points(hour_body_trace, hour_trace_point, 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); + } +} + +void WatchFaceSimpleAnalog::SetBatteryIcon() { + auto batteryPercent = batteryPercentRemaining.Get(); + batteryIcon.SetBatteryPercentage(batteryPercent); +} + +void WatchFaceSimpleAnalog::Refresh() { + isCharging = batteryController.IsCharging(); + if (isCharging.IsUpdated()) { + if (isCharging.Get()) { + lv_obj_set_hidden(batteryIcon.GetObject(), true); + lv_obj_set_hidden(plugIcon, false); + } else { + lv_obj_set_hidden(batteryIcon.GetObject(), false); + lv_obj_set_hidden(plugIcon, true); + SetBatteryIcon(); + } + } + if (!isCharging.Get()) { + batteryPercentRemaining = batteryController.PercentRemaining(); + if (batteryPercentRemaining.IsUpdated()) { + SetBatteryIcon(); + } + } + + bleState = bleController.IsConnected(); + bleRadioEnabled = bleController.IsRadioEnabled(); + if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { + lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get())); + } + lv_obj_realign(plugIcon); + lv_obj_realign(bleIcon); + + notificationState = notificationManager.AreNewNotificationsAvailable(); + + if (notificationState.IsUpdated()) { + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); + } + + currentDateTime = dateTimeController.CurrentDateTime(); + + if (currentDateTime.IsUpdated()) { + Pinetime::Controllers::DateTime::Months month = dateTimeController.Month(); + uint8_t day = dateTimeController.Day(); + Pinetime::Controllers::DateTime::Days dayOfWeek = dateTimeController.DayOfWeek(); + + UpdateClock(); + + if ((month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) { + lv_label_set_text_fmt(label_date_day, "%s %02i", dateTimeController.DayOfWeekShortToString(), day); + + currentMonth = month; + currentDayOfWeek = dayOfWeek; + currentDay = day; + } + } + + heartbeat = heartRateController.HeartRate(); + heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; + if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) { + 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); + } + + stepCount = motionController.NbSteps(); + motionSensorOk = motionController.IsSensorOk(); + if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) { + uint32_t goal = settingsController.GetStepsGoal(); + uint32_t steps = stepCount.Get(); + int32_t steps_value; + if (steps > goal) + steps_value = 12; + else + steps_value = ((float) steps / goal) * 12; + + lv_linemeter_set_value(stepsMeter, steps_value); + } +} diff --git a/src/displayapp/screens/WatchFaceSimpleAnalog.h b/src/displayapp/screens/WatchFaceSimpleAnalog.h new file mode 100644 index 00000000..1c893156 --- /dev/null +++ b/src/displayapp/screens/WatchFaceSimpleAnalog.h @@ -0,0 +1,103 @@ +#pragma once + +#include +#include +#include +#include +#include "displayapp/screens/Screen.h" +#include "components/datetime/DateTimeController.h" +#include "components/battery/BatteryController.h" +#include "components/ble/BleController.h" +#include "components/ble/NotificationManager.h" +#include + +namespace Pinetime { + namespace Controllers { + class Settings; + class Battery; + class Ble; + class NotificationManager; + class HeartRateController; + class MotionController; + } + namespace Applications { + namespace Screens { + + class WatchFaceSimpleAnalog : public Screen { + public: + WatchFaceSimpleAnalog(DisplayApp* app, + Controllers::DateTime& dateTimeController, + Controllers::Battery& batteryController, + Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController); + + ~WatchFaceSimpleAnalog() override; + + void Refresh() override; + + private: + uint8_t sHour, sMinute, sSecond; + + Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; + Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; + uint8_t currentDay = 0; + + DirtyValue batteryPercentRemaining {0}; + DirtyValue isCharging {}; + DirtyValue> currentDateTime; + DirtyValue notificationState {false}; + DirtyValue bleState {}; + DirtyValue bleRadioEnabled {}; + DirtyValue motionSensorOk {}; + DirtyValue stepCount {}; + DirtyValue heartbeat {}; + DirtyValue heartbeatRunning {}; + + lv_obj_t* dot; + 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_trace_point[2]; + lv_point_t minute_point[2]; + lv_point_t minute_trace_point[2]; + lv_point_t second_point[2]; + + lv_style_t hour_line_style; + lv_style_t hour_trace_line_style; + lv_style_t minute_line_style; + lv_style_t minute_trace_line_style; + lv_style_t second_line_style; + + lv_obj_t* label_date_day; + lv_obj_t* plugIcon; + lv_obj_t* bleIcon; + lv_obj_t* notificationIcon; + lv_obj_t* heartbeatIcon; + lv_obj_t* heartbeatValue; + lv_obj_t* stepsMeter; + + BatteryIcon batteryIcon; + + const Controllers::DateTime& dateTimeController; + Controllers::Battery& batteryController; + Controllers::Ble& bleController; + Controllers::NotificationManager& notificationManager; + Controllers::Settings& settingsController; + Controllers::HeartRateController& heartRateController; + Controllers::MotionController& motionController; + + void UpdateClock(); + void SetBatteryIcon(); + + lv_task_t* taskRefresh; + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index 3cb2a364..39cbe86f 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -1,59 +1,29 @@ #include "displayapp/screens/settings/SettingWatchFace.h" #include #include "displayapp/DisplayApp.h" +#include "displayapp/screens/CheckboxList.h" #include "displayapp/screens/Screen.h" #include "displayapp/screens/Styles.h" #include "displayapp/screens/Symbols.h" +#include "components/settings/Settings.h" using namespace Pinetime::Applications::Screens; -namespace { - void event_handler(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast(obj->user_data); - screen->UpdateSelected(obj, event); - } -} - -constexpr std::array SettingWatchFace::options; +constexpr const char* SettingWatchFace::title; +constexpr const char* SettingWatchFace::symbol; SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) - : Screen(app), settingsController {settingsController} { - - lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); - - // lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111)); - lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); - lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); - lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); - - lv_obj_set_pos(container1, 10, 60); - lv_obj_set_width(container1, LV_HOR_RES - 20); - lv_obj_set_height(container1, LV_VER_RES - 50); - lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); - - lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(title, "Watch face"); - lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); - lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 15); - - lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); - lv_label_set_text_static(icon, Symbols::home); - lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); - lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); - - for (unsigned int i = 0; i < options.size(); i++) { - cbOption[i] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text(cbOption[i], options[i]); - cbOption[i]->user_data = this; - lv_obj_set_event_cb(cbOption[i], event_handler); - SetRadioButtonStyle(cbOption[i]); - - if (settingsController.GetClockFace() == i) { - lv_checkbox_set_checked(cbOption[i], true); - } - } + : Screen(app), + settingsController {settingsController}, + screens {app, + settingsController.GetWatchfacesMenu(), + {[this]() -> std::unique_ptr { + return CreateScreen1(); + }, + [this]() -> std::unique_ptr { + return CreateScreen2(); + }}, + Screens::ScreenListModes::UpDown} { } SettingWatchFace::~SettingWatchFace() { @@ -61,15 +31,18 @@ SettingWatchFace::~SettingWatchFace() { settingsController.SaveSettings(); } -void SettingWatchFace::UpdateSelected(lv_obj_t* object, lv_event_t event) { - if (event == LV_EVENT_VALUE_CHANGED) { - for (unsigned int i = 0; i < options.size(); i++) { - if (object == cbOption[i]) { - lv_checkbox_set_checked(cbOption[i], true); - settingsController.SetClockFace(i); - } else { - lv_checkbox_set_checked(cbOption[i], false); - } - } - } +bool SettingWatchFace::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + return screens.OnTouchEvent(event); +} + +std::unique_ptr SettingWatchFace::CreateScreen1() { + std::array watchfaces {" Digital face", " Analog face", " PineTimeStyle", " Terminal"}; + return std::make_unique( + 0, 2, app, settingsController, title, symbol, &Controllers::Settings::SetClockFace, &Controllers::Settings::GetClockFace, watchfaces); +} + +std::unique_ptr SettingWatchFace::CreateScreen2() { + std::array watchfaces {" Simple Analog", "", "", ""}; + return std::make_unique( + 1, 2, app, settingsController, title, symbol, &Controllers::Settings::SetClockFace, &Controllers::Settings::GetClockFace, watchfaces); } diff --git a/src/displayapp/screens/settings/SettingWatchFace.h b/src/displayapp/screens/settings/SettingWatchFace.h index 62427b4f..7d14554e 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.h +++ b/src/displayapp/screens/settings/SettingWatchFace.h @@ -4,8 +4,10 @@ #include #include +#include "displayapp/screens/ScreenList.h" #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" namespace Pinetime { @@ -17,13 +19,16 @@ namespace Pinetime { SettingWatchFace(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingWatchFace() override; - void UpdateSelected(lv_obj_t* object, lv_event_t event); + bool OnTouchEvent(TouchEvents event) override; private: - static constexpr std::array options = {" Digital face", " Analog face", " PineTimeStyle", " Terminal"}; Controllers::Settings& settingsController; + ScreenList<2> screens; - lv_obj_t* cbOption[options.size()]; + static constexpr const char* title = "Watch face"; + static constexpr const char* symbol = Symbols::home; + std::unique_ptr CreateScreen1(); + std::unique_ptr CreateScreen2(); }; } }