From 1f9e381dcec596643e7f3bcdb8e15fc894b6b66a Mon Sep 17 00:00:00 2001 From: faxe1008 Date: Sun, 13 Nov 2022 19:21:16 +0100 Subject: [PATCH 1/2] [new watchface] watchface inspired by the Pebble Watch This patch adds a new watchface which is inspired by a Pebble watchface with the step count being displayed as a rectangular progressbar at the edge of the screen. --- src/CMakeLists.txt | 1 + src/displayapp/screens/Clock.cpp | 13 + src/displayapp/screens/Clock.h | 1 + src/displayapp/screens/WatchFaceGravel.cpp | 334 ++++++++++++++++++ src/displayapp/screens/WatchFaceGravel.h | 84 +++++ .../screens/settings/SettingWatchFace.cpp | 3 +- src/resources/fonts.json | 24 ++ src/resources/fonts/public_pixel.ttf | Bin 0 -> 97456 bytes 8 files changed, 459 insertions(+), 1 deletion(-) create mode 100644 src/displayapp/screens/WatchFaceGravel.cpp create mode 100644 src/displayapp/screens/WatchFaceGravel.h create mode 100644 src/resources/fonts/public_pixel.ttf diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e59c0d81..b9bdcee0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -431,6 +431,7 @@ list(APPEND SOURCE_FILES displayapp/screens/WatchFaceTerminal.cpp displayapp/screens/WatchFacePineTimeStyle.cpp displayapp/screens/WatchFaceCasioStyleG7710.cpp + displayapp/screens/WatchFaceGravel.cpp ## diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp index 07d307e0..c5a437b7 100644 --- a/src/displayapp/screens/Clock.cpp +++ b/src/displayapp/screens/Clock.cpp @@ -14,6 +14,7 @@ #include "displayapp/screens/WatchFaceAnalog.h" #include "displayapp/screens/WatchFacePineTimeStyle.h" #include "displayapp/screens/WatchFaceCasioStyleG7710.h" +#include "displayapp/screens/WatchFaceGravel.h" using namespace Pinetime::Applications::Screens; @@ -55,6 +56,9 @@ Clock::Clock(DisplayApp* app, case 5: return WatchFaceCasioStyleG7710(); break; + case 6: + return WatchFaceGravel(); + break; } return WatchFaceDigitalScreen(); }()} { @@ -136,3 +140,12 @@ std::unique_ptr Clock::WatchFaceCasioStyleG7710() { motionController, filesystem); } + +std::unique_ptr Clock::WatchFaceGravel() { + return std::make_unique(app, + dateTimeController, + batteryController, + settingsController, + motionController, + filesystem); +} diff --git a/src/displayapp/screens/Clock.h b/src/displayapp/screens/Clock.h index 613fef57..1486bc65 100644 --- a/src/displayapp/screens/Clock.h +++ b/src/displayapp/screens/Clock.h @@ -52,6 +52,7 @@ namespace Pinetime { std::unique_ptr WatchFaceTerminalScreen(); std::unique_ptr WatchFaceInfineatScreen(); std::unique_ptr WatchFaceCasioStyleG7710(); + std::unique_ptr WatchFaceGravel(); }; } } diff --git a/src/displayapp/screens/WatchFaceGravel.cpp b/src/displayapp/screens/WatchFaceGravel.cpp new file mode 100644 index 00000000..05a1c07f --- /dev/null +++ b/src/displayapp/screens/WatchFaceGravel.cpp @@ -0,0 +1,334 @@ +#include "displayapp/screens/WatchFaceGravel.h" + +#include +#include +#include "components/battery/BatteryController.h" +#include "components/ble/BleController.h" +#include "components/ble/NotificationManager.h" +#include "components/heartrate/HeartRateController.h" +#include "components/motion/MotionController.h" +#include "components/settings/Settings.h" + +using namespace Pinetime::Applications::Screens; + +namespace Style { + static constexpr lv_style_int_t STEP_LINE_THICKNESS = 8; + static constexpr lv_style_int_t STEP_LINE_PADDING = 4; + + static constexpr lv_style_int_t BATTERY_INDICATOR_THICKNESS = 8; + static constexpr lv_style_int_t BATTERY_INDICATOR_LENGTH = 60; + static constexpr uint32_t BATTERY_CHARGING_ANIMATION_DURATION = 5000; + + static constexpr lv_color_t red = LV_COLOR_MAKE(0xCE, 0x27, 0x2A); + static constexpr lv_color_t green = LV_COLOR_MAKE(0x20, 0xA8, 0x20); + static constexpr lv_color_t yellow = LV_COLOR_MAKE(0xCE, 0xCE, 0x27); + static constexpr lv_color_t blue = LV_COLOR_MAKE(0x27, 0xA2, 0xCE); + static constexpr lv_color_t barBackground = LV_COLOR_MAKE(0x38, 0x38, 0x38); +} + +WatchFaceGravel::WatchFaceGravel(DisplayApp* app, + Controllers::DateTime& dateTimeController, + Controllers::Battery& batteryController, + Controllers::Settings& settingsController, + Controllers::MotionController& motionController, + Controllers::FS& filesystem) + : Screen(app), + currentDateTime {{}}, + dateTimeController {dateTimeController}, + batteryController {batteryController}, + settingsController {settingsController}, + motionController(motionController) { + + lfs_file f = {}; + if (filesystem.FileOpen(&f, "/fonts/SquareRegular_72.bin", LFS_O_RDONLY) >= 0) { + filesystem.FileClose(&f); + font_SquareRegular72 = lv_font_load("F:/fonts/SquareRegular_72.bin"); + } + + if (filesystem.FileOpen(&f, "/fonts/SquareRegular_20.bin", LFS_O_RDONLY) >= 0) { + filesystem.FileClose(&f); + font_SquareRegular20 = lv_font_load("F:/fonts/SquareRegular_20.bin"); + } + + labelTime = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(labelTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_SquareRegular72); + + labelTimeAMPM = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(labelTimeAMPM, ""); + lv_obj_set_style_local_text_font(labelTimeAMPM, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_SquareRegular20); + lv_obj_align(labelTimeAMPM, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -50, -45); + + stepLineBackground = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_opa(stepLineBackground, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0); + lv_obj_set_style_local_border_width(stepLineBackground, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, Style::STEP_LINE_THICKNESS); + lv_obj_set_style_local_border_color(stepLineBackground, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, Style::barBackground); + lv_obj_set_style_local_border_opa(stepLineBackground, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50); + lv_obj_set_width(stepLineBackground, LV_HOR_RES - (Style::STEP_LINE_THICKNESS / 2) - Style::STEP_LINE_PADDING * 2); + lv_obj_set_height(stepLineBackground, LV_VER_RES - (Style::STEP_LINE_THICKNESS / 2) - Style::STEP_LINE_PADDING * 2); + lv_obj_align(stepLineBackground, NULL, LV_ALIGN_IN_TOP_LEFT, Style::STEP_LINE_PADDING, Style::STEP_LINE_PADDING); + + stepLine = lv_line_create(lv_scr_act(), nullptr); + lv_style_init(&styleStepLine); + lv_style_set_line_width(&styleStepLine, LV_STATE_DEFAULT, Style::STEP_LINE_THICKNESS); + lv_style_set_line_color(&styleStepLine, LV_STATE_DEFAULT, Style::blue); + lv_style_set_line_rounded(&styleStepLine, LV_STATE_DEFAULT, true); + lv_obj_add_style(stepLine, LV_LINE_PART_MAIN, &styleStepLine); + lv_obj_align(stepLine, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + + batteryBar = lv_bar_create(lv_scr_act(), nullptr); + lv_obj_set_size(batteryBar, Style::BATTERY_INDICATOR_LENGTH, Style::BATTERY_INDICATOR_THICKNESS); + lv_bar_set_range(batteryBar, 0, 100); + lv_bar_set_value(batteryBar, 0, LV_ANIM_OFF); + lv_obj_set_style_local_radius(batteryBar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_style_local_bg_color(batteryBar, LV_BAR_PART_BG, LV_STATE_DEFAULT, Style::barBackground); + lv_obj_set_style_local_bg_opa(batteryBar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_50); + lv_obj_set_style_local_bg_color(batteryBar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_obj_align(batteryBar, lv_scr_act(), LV_ALIGN_CENTER, 40, 40); + + lv_anim_init(&animationBatteryCharging); + lv_anim_set_var(&animationBatteryCharging, batteryBar); + lv_anim_set_repeat_count(&animationBatteryCharging, LV_ANIM_REPEAT_INFINITE); + + labelDate = lv_label_create(lv_scr_act(), nullptr); + lv_obj_align(labelDate, batteryBar, LV_ALIGN_OUT_LEFT_MID, -15, 0); + lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_SquareRegular20); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + Refresh(); +} + +WatchFaceGravel::~WatchFaceGravel() { + lv_task_del(taskRefresh); + lv_style_reset(&styleStepLine); + + if (font_SquareRegular20 != nullptr) { + lv_font_free(font_SquareRegular20); + } + + if (font_SquareRegular72 != nullptr) { + lv_font_free(font_SquareRegular72); + } + + lv_obj_clean(lv_scr_act()); +} + +void WatchFaceGravel::Refresh() { + currentDateTime = dateTimeController.CurrentDateTime(); + + if (currentDateTime.IsUpdated()) { + auto newDateTime = currentDateTime.Get(); + + auto dp = date::floor(newDateTime); + auto time = date::make_time(newDateTime - dp); + + uint8_t hour = time.hours().count(); + uint8_t minute = time.minutes().count(); + + if (displayedHour != hour || displayedMinute != minute) { + displayedHour = hour; + displayedMinute = minute; + + 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(labelTimeAMPM, ampmChar); + } + + lv_label_set_text_fmt(labelTime, "%02d:%02d", hour, minute); + lv_obj_align_origo(labelTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + } + + auto yearMonthDay = date::year_month_day(dp); + auto month = static_cast(static_cast(yearMonthDay.month())); + auto day = static_cast(yearMonthDay.day()); + if ((day != currentDay) || (month != currentMonth)) { + lv_label_set_text_fmt(labelDate, "%d %s", day, Pinetime::Controllers::DateTime::MonthShortToStringLow(month)); + } + lv_obj_realign(labelDate); + } + + stepCount = motionController.NbSteps(); + motionSensorOk = motionController.IsSensorOk(); + if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) { + uint16_t pointCount = refreshStepLinePoints(std::min(stepCount.Get(), settingsController.GetStepsGoal())); + lv_line_set_points(stepLine, stepLinePoints.data(), pointCount); + } + lv_obj_realign(stepLine); + + isCharging = batteryController.IsCharging(); + if (isCharging.IsUpdated()) { + toggleBatteryChargingAnimation(isCharging.Get(), batteryPercentRemaining.Get()); + } + + batteryPercentRemaining = batteryController.PercentRemaining(); + if (batteryPercentRemaining.IsUpdated()) { + if (isCharging.Get()) { + toggleBatteryChargingAnimation(true, batteryPercentRemaining.Get()); + } else { + updateBatteryBar(batteryPercentRemaining.Get()); + } + } +} + +void WatchFaceGravel::updateBatteryBar(uint8_t percent) { + lv_bar_set_value(batteryBar, percent, LV_ANIM_ON); + if (percent >= 70) { + lv_obj_set_style_local_bg_color(batteryBar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Style::green); + } else if (percent >= 40) { + lv_obj_set_style_local_bg_color(batteryBar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Style::yellow); + } else { + lv_obj_set_style_local_bg_color(batteryBar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Style::red); + } +} + +void WatchFaceGravel::toggleBatteryChargingAnimation(bool enabled, uint8_t percent) { + if (enabled) { + lv_obj_set_style_local_bg_color(batteryBar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Style::green); + lv_anim_del(batteryBar, (lv_anim_exec_xcb_t) lv_bar_set_value); + lv_anim_set_exec_cb(&animationBatteryCharging, (lv_anim_exec_xcb_t) lv_bar_set_value); + lv_anim_set_values(&animationBatteryCharging, percent, 100); + uint32_t duration = (Style::BATTERY_CHARGING_ANIMATION_DURATION / 100) * (100 - percent); + lv_anim_set_time(&animationBatteryCharging, duration); + lv_anim_start(&animationBatteryCharging); + } else { + lv_anim_del(batteryBar, (lv_anim_exec_xcb_t) lv_bar_set_value); + updateBatteryBar(batteryPercentRemaining.Get()); + } +} + +WatchFaceGravel::DrawStop WatchFaceGravel::getDrawEnd(float percent, uint16_t width, uint16_t height) { + DrawStop drawStop = {.place = Place::TOP, .location = 0.0f}; + float halfBarWidth = width / 2; + + if (percent > halfBarWidth) { + float second = percent - (halfBarWidth); + // right + if (second > (height - Style::STEP_LINE_THICKNESS)) { + float third = second - (height - Style::STEP_LINE_THICKNESS); + + // bottom + if (third > (width - Style::STEP_LINE_THICKNESS)) { + float forth = third - (width - Style::STEP_LINE_THICKNESS); + + // left + if (forth > (height - Style::STEP_LINE_THICKNESS)) { + float fifth = forth - (height - Style::STEP_LINE_THICKNESS); + + // top left + if (fifth == halfBarWidth) { + drawStop.place = Place::TOP; + drawStop.location = halfBarWidth; + } else { + drawStop.place = Place::TOP; + drawStop.location = Style::STEP_LINE_THICKNESS + fifth; + } + } else { + drawStop.place = Place::LEFT; + drawStop.location = height - Style::STEP_LINE_THICKNESS - forth; + } + + } else { + drawStop.place = Place::BOTTOM; + drawStop.location = width - Style::STEP_LINE_THICKNESS - third; + } + } else { + drawStop.place = Place::RIGHT; + drawStop.location = Style::STEP_LINE_THICKNESS + second; + } + + } else { + drawStop.place = Place::TOP; + drawStop.location = halfBarWidth + percent; + } + + return drawStop; +} + +// Credit to https://github.com/mrwonderman/android-square-progressbar for original source +uint16_t WatchFaceGravel::refreshStepLinePoints(uint32_t stepCount) { + uint16_t currentPointIndex = 0; + + if (stepCount == 0) + return currentPointIndex; + + int barWidth = LV_HOR_RES - Style::STEP_LINE_PADDING; + int barHeight = LV_VER_RES - Style::STEP_LINE_PADDING; + + float scope = (2 * barWidth) + (2 * barHeight) - (4 * Style::STEP_LINE_THICKNESS); + float halfStrokeWidth = Style::STEP_LINE_THICKNESS / 2 + Style::STEP_LINE_PADDING; + + const auto addPoint = [&](lv_coord_t x, lv_coord_t y) { + stepLinePoints[currentPointIndex++] = {.x = x, .y = y}; + }; + + float progress = static_cast(stepCount * 100) / static_cast(settingsController.GetStepsGoal()); + float percent = (scope / 100.0F) * progress; + + auto drawEnd = getDrawEnd(percent, barWidth, barHeight); + + if (drawEnd.place == Place::TOP) { + if (drawEnd.location > (barWidth / 2) && progress < 100.0F) { + addPoint(barWidth / 2, halfStrokeWidth); + addPoint(drawEnd.location, halfStrokeWidth); + } else { + addPoint(barWidth / 2, halfStrokeWidth); + addPoint(barWidth - halfStrokeWidth, halfStrokeWidth); + addPoint(barWidth - halfStrokeWidth, barHeight - halfStrokeWidth); + addPoint(halfStrokeWidth, barHeight - halfStrokeWidth); + addPoint(halfStrokeWidth, halfStrokeWidth); + addPoint(Style::STEP_LINE_THICKNESS, halfStrokeWidth); + addPoint(drawEnd.location, halfStrokeWidth); + } + return currentPointIndex; + } + + if (drawEnd.place == Place::RIGHT) { + addPoint(barWidth / 2, halfStrokeWidth); + addPoint(barWidth - halfStrokeWidth, halfStrokeWidth); + addPoint(barWidth - halfStrokeWidth, 0 + drawEnd.location); + return currentPointIndex; + } + + if (drawEnd.place == Place::BOTTOM) { + addPoint(barWidth / 2, halfStrokeWidth); + addPoint(barWidth - halfStrokeWidth, halfStrokeWidth); + addPoint(barWidth - halfStrokeWidth, barHeight - halfStrokeWidth); + addPoint(barWidth - Style::STEP_LINE_THICKNESS, barHeight - halfStrokeWidth); + addPoint(drawEnd.location, barHeight - halfStrokeWidth); + return currentPointIndex; + } + + if (drawEnd.place == Place::LEFT) { + addPoint(barWidth / 2, halfStrokeWidth); + addPoint(barWidth - halfStrokeWidth, halfStrokeWidth); + addPoint(barWidth - halfStrokeWidth, barHeight - halfStrokeWidth); + addPoint(halfStrokeWidth, barHeight - halfStrokeWidth); + addPoint(halfStrokeWidth, barHeight - Style::STEP_LINE_THICKNESS); + addPoint(halfStrokeWidth, drawEnd.location); + return currentPointIndex; + } + + return currentPointIndex; +} + +bool WatchFaceGravel::IsAvailable(Pinetime::Controllers::FS& filesystem) { + lfs_file file = {}; + + if (filesystem.FileOpen(&file, "/fonts/SquareRegular_72.bin", LFS_O_RDONLY) < 0) { + return false; + } + filesystem.FileClose(&file); + + if (filesystem.FileOpen(&file, "/fonts/SquareRegular_20.bin", LFS_O_RDONLY) < 0) { + return false; + } + filesystem.FileClose(&file); + return true; +} diff --git a/src/displayapp/screens/WatchFaceGravel.h b/src/displayapp/screens/WatchFaceGravel.h new file mode 100644 index 00000000..7faf7fae --- /dev/null +++ b/src/displayapp/screens/WatchFaceGravel.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "components/ble/BleController.h" +#include "components/datetime/DateTimeController.h" +#include "displayapp/screens/Screen.h" + +namespace Pinetime { + namespace Controllers { + class Settings; + class Battery; + class Ble; + class NotificationManager; + class HeartRateController; + class MotionController; + } + + namespace Applications { + namespace Screens { + + class WatchFaceGravel : public Screen { + public: + WatchFaceGravel(DisplayApp* app, + Controllers::DateTime& dateTimeController, + Controllers::Battery& batteryController, + Controllers::Settings& settingsController, + Controllers::MotionController& motionController, + Controllers::FS& filesystem); + ~WatchFaceGravel() override; + + void Refresh() override; + + static bool IsAvailable(Pinetime::Controllers::FS& filesystem); + + private: + uint8_t displayedHour = -1; + uint8_t displayedMinute = -1; + Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; + uint8_t currentDay = 0; + std::array stepLinePoints = {0}; + + DirtyValue> currentDateTime {}; + DirtyValue motionSensorOk {}; + DirtyValue stepCount {}; + DirtyValue batteryPercentRemaining {}; + DirtyValue isCharging {}; + + lv_obj_t* labelTime; + lv_obj_t* labelTimeAMPM; + lv_style_t styleStepLine; + lv_obj_t* stepLine; + lv_obj_t* stepLineBackground; + lv_obj_t* labelDate; + lv_obj_t* batteryBar; + lv_anim_t animationBatteryCharging; + + lv_font_t* font_SquareRegular72 = nullptr; + lv_font_t* font_SquareRegular20 = nullptr; + + Controllers::DateTime& dateTimeController; + Controllers::Settings& settingsController; + Controllers::MotionController& motionController; + Controllers::Battery& batteryController; + + lv_task_t* taskRefresh; + + enum class Place { TOP, RIGHT, BOTTOM, LEFT }; + typedef struct { + Place place; + float location; + } DrawStop; + + DrawStop getDrawEnd(float percent, uint16_t width, uint16_t height); + uint16_t refreshStepLinePoints(uint32_t stepCount); + void updateBatteryBar(uint8_t percent); + void toggleBatteryChargingAnimation(bool enabled, uint8_t percent); + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index 217f97b8..14ce5754 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -6,6 +6,7 @@ #include "components/settings/Settings.h" #include "displayapp/screens/WatchFaceInfineat.h" #include "displayapp/screens/WatchFaceCasioStyleG7710.h" +#include "displayapp/screens/WatchFaceGravel.h" using namespace Pinetime::Applications::Screens; @@ -58,7 +59,7 @@ std::unique_ptr SettingWatchFace::CreateScreen2() { std::array watchfaces { {{"Infineat face", Applications::Screens::WatchFaceInfineat::IsAvailable(filesystem)}, {"Casio G7710", Applications::Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem)}, - {"", false}, + {"Gravel", Applications::Screens::WatchFaceGravel::IsAvailable(filesystem)}, {"", false}}}; return std::make_unique( 1, diff --git a/src/resources/fonts.json b/src/resources/fonts.json index a270e6a2..91c94926 100644 --- a/src/resources/fonts.json +++ b/src/resources/fonts.json @@ -58,5 +58,29 @@ "size": 115, "format": "bin", "target_path": "/fonts/" + }, + "SquareRegular_72": { + "sources": [ + { + "file": "fonts/SquareRegular.ttf", + "symbols": "0123456789:/amp " + } + ], + "bpp": 1, + "size": 72, + "format": "bin", + "target_path": "/fonts/" + }, + "SquareRegular_20": { + "sources": [ + { + "file": "fonts/SquareRegular.ttf", + "symbols": "0123456789:--ADFJMNOPSabceglnoprtuvy " + } + ], + "bpp": 2, + "size": 20, + "format": "bin", + "target_path": "/fonts/" } } diff --git a/src/resources/fonts/public_pixel.ttf b/src/resources/fonts/public_pixel.ttf new file mode 100644 index 0000000000000000000000000000000000000000..618e5bb88efc72572877cd6a99cb2cdf06741de5 GIT binary patch literal 97456 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 P*T49z0v0{r8p3}AhSeWV literal 0 HcmV?d00001 From bf66e640216c68d03657f183d4dec62afd3c9892 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 9 May 2024 15:52:57 -0400 Subject: [PATCH 2/2] Gravel watchface compiles --- src/displayapp/UserApps.h | 1 + src/displayapp/apps/Apps.h.in | 1 + src/displayapp/apps/CMakeLists.txt | 1 + src/displayapp/screens/WatchFaceGravel.cpp | 100 +++++++++------------ src/displayapp/screens/WatchFaceGravel.h | 39 +++++--- src/resources/fonts/SquareRegular.ttf | Bin 0 -> 17180 bytes 6 files changed, 76 insertions(+), 66 deletions(-) create mode 100644 src/resources/fonts/SquareRegular.ttf diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h index 3f05ebdd..c7a719d8 100644 --- a/src/displayapp/UserApps.h +++ b/src/displayapp/UserApps.h @@ -17,6 +17,7 @@ #include "displayapp/screens/WatchFaceTerminal.h" #include "displayapp/screens/WatchFaceHorizon.h" #include "displayapp/screens/WatchFaceAccurateWords.h" +#include "displayapp/screens/WatchFaceGravel.h" namespace Pinetime { namespace Applications { diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index c05fb834..8cc34943 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -59,6 +59,7 @@ namespace Pinetime { CasioStyleG7710, Horizon, AccurateWords, + Gravel }; template diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 379605bd..85281926 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -32,6 +32,7 @@ else() set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::CasioStyleG7710") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Horizon") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::AccurateWords") + set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Gravel") set(WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}" CACHE STRING "List of watch faces to build into the firmware") endif() diff --git a/src/displayapp/screens/WatchFaceGravel.cpp b/src/displayapp/screens/WatchFaceGravel.cpp index 05a1c07f..2bb4c47b 100644 --- a/src/displayapp/screens/WatchFaceGravel.cpp +++ b/src/displayapp/screens/WatchFaceGravel.cpp @@ -1,6 +1,5 @@ #include "displayapp/screens/WatchFaceGravel.h" -#include #include #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" @@ -26,18 +25,16 @@ namespace Style { static constexpr lv_color_t barBackground = LV_COLOR_MAKE(0x38, 0x38, 0x38); } -WatchFaceGravel::WatchFaceGravel(DisplayApp* app, - Controllers::DateTime& dateTimeController, - Controllers::Battery& batteryController, +WatchFaceGravel::WatchFaceGravel(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, Controllers::Settings& settingsController, Controllers::MotionController& motionController, Controllers::FS& filesystem) - : Screen(app), - currentDateTime {{}}, + : currentDateTime {{}}, dateTimeController {dateTimeController}, batteryController {batteryController}, settingsController {settingsController}, - motionController(motionController) { + motionController {motionController} { lfs_file f = {}; if (filesystem.FileOpen(&f, "/fonts/SquareRegular_72.bin", LFS_O_RDONLY) >= 0) { @@ -116,47 +113,36 @@ void WatchFaceGravel::Refresh() { currentDateTime = dateTimeController.CurrentDateTime(); if (currentDateTime.IsUpdated()) { - auto newDateTime = currentDateTime.Get(); + uint8_t hour = dateTimeController.Hours(); + uint8_t minute = dateTimeController.Minutes(); - auto dp = date::floor(newDateTime); - auto time = date::make_time(newDateTime - dp); - uint8_t hour = time.hours().count(); - uint8_t minute = time.minutes().count(); - - if (displayedHour != hour || displayedMinute != minute) { - displayedHour = hour; - displayedMinute = minute; - - 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(labelTimeAMPM, ampmChar); + 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_fmt(labelTime, "%02d:%02d", hour, minute); - lv_obj_align_origo(labelTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + lv_label_set_text(labelTimeAMPM, ampmChar); } - auto yearMonthDay = date::year_month_day(dp); - auto month = static_cast(static_cast(yearMonthDay.month())); - auto day = static_cast(yearMonthDay.day()); - if ((day != currentDay) || (month != currentMonth)) { - lv_label_set_text_fmt(labelDate, "%d %s", day, Pinetime::Controllers::DateTime::MonthShortToStringLow(month)); + lv_label_set_text_fmt(labelTime, "%02d:%02d", hour, minute); + lv_obj_align_origo(labelTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + + + currentDate = std::chrono::time_point_cast(currentDateTime.Get()); + if (currentDate.IsUpdated()) { + lv_label_set_text_fmt(labelDate, "%d %s", dateTimeController.DayOfWeekShortToString(), dateTimeController.MonthShortToString()); } lv_obj_realign(labelDate); } stepCount = motionController.NbSteps(); - motionSensorOk = motionController.IsSensorOk(); - if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) { + if (stepCount.IsUpdated()) { uint16_t pointCount = refreshStepLinePoints(std::min(stepCount.Get(), settingsController.GetStepsGoal())); lv_line_set_points(stepLine, stepLinePoints.data(), pointCount); } @@ -177,6 +163,21 @@ void WatchFaceGravel::Refresh() { } } +bool WatchFaceGravel::IsAvailable(Pinetime::Controllers::FS& filesystem) { + lfs_file file = {}; + + if (filesystem.FileOpen(&file, "/fonts/SquareRegular_72.bin", LFS_O_RDONLY) < 0) { + return false; + } + filesystem.FileClose(&file); + + if (filesystem.FileOpen(&file, "/fonts/SquareRegular_20.bin", LFS_O_RDONLY) < 0) { + return false; + } + filesystem.FileClose(&file); + return true; +} + void WatchFaceGravel::updateBatteryBar(uint8_t percent) { lv_bar_set_value(batteryBar, percent, LV_ANIM_ON); if (percent >= 70) { @@ -188,8 +189,9 @@ void WatchFaceGravel::updateBatteryBar(uint8_t percent) { } } -void WatchFaceGravel::toggleBatteryChargingAnimation(bool enabled, uint8_t percent) { - if (enabled) { +void WatchFaceGravel::toggleBatteryChargingAnimation(bool, uint8_t) { +//void WatchFaceGravel::toggleBatteryChargingAnimation(bool enabled, uint8_t percent) { + /*if (enabled) { lv_obj_set_style_local_bg_color(batteryBar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Style::green); lv_anim_del(batteryBar, (lv_anim_exec_xcb_t) lv_bar_set_value); lv_anim_set_exec_cb(&animationBatteryCharging, (lv_anim_exec_xcb_t) lv_bar_set_value); @@ -200,7 +202,8 @@ void WatchFaceGravel::toggleBatteryChargingAnimation(bool enabled, uint8_t perce } else { lv_anim_del(batteryBar, (lv_anim_exec_xcb_t) lv_bar_set_value); updateBatteryBar(batteryPercentRemaining.Get()); - } + }*/ + } WatchFaceGravel::DrawStop WatchFaceGravel::getDrawEnd(float percent, uint16_t width, uint16_t height) { @@ -317,18 +320,3 @@ uint16_t WatchFaceGravel::refreshStepLinePoints(uint32_t stepCount) { return currentPointIndex; } - -bool WatchFaceGravel::IsAvailable(Pinetime::Controllers::FS& filesystem) { - lfs_file file = {}; - - if (filesystem.FileOpen(&file, "/fonts/SquareRegular_72.bin", LFS_O_RDONLY) < 0) { - return false; - } - filesystem.FileClose(&file); - - if (filesystem.FileOpen(&file, "/fonts/SquareRegular_20.bin", LFS_O_RDONLY) < 0) { - return false; - } - filesystem.FileClose(&file); - return true; -} diff --git a/src/displayapp/screens/WatchFaceGravel.h b/src/displayapp/screens/WatchFaceGravel.h index 7faf7fae..480985e4 100644 --- a/src/displayapp/screens/WatchFaceGravel.h +++ b/src/displayapp/screens/WatchFaceGravel.h @@ -5,9 +5,11 @@ #include #include #include +#include "displayapp/Controllers.h" #include "components/ble/BleController.h" #include "components/datetime/DateTimeController.h" #include "displayapp/screens/Screen.h" +#include "utility/DirtyValue.h" namespace Pinetime { namespace Controllers { @@ -21,12 +23,10 @@ namespace Pinetime { namespace Applications { namespace Screens { - class WatchFaceGravel : public Screen { public: - WatchFaceGravel(DisplayApp* app, - Controllers::DateTime& dateTimeController, - Controllers::Battery& batteryController, + WatchFaceGravel(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, Controllers::Settings& settingsController, Controllers::MotionController& motionController, Controllers::FS& filesystem); @@ -43,11 +43,12 @@ namespace Pinetime { uint8_t currentDay = 0; std::array stepLinePoints = {0}; - DirtyValue> currentDateTime {}; - DirtyValue motionSensorOk {}; - DirtyValue stepCount {}; - DirtyValue batteryPercentRemaining {}; - DirtyValue isCharging {}; + Utility::DirtyValue> currentDateTime {}; + Utility::DirtyValue motionSensorOk {}; + Utility::DirtyValue stepCount {}; + Utility::DirtyValue batteryPercentRemaining {}; + Utility::DirtyValue isCharging {}; + Utility::DirtyValue> currentDate; lv_obj_t* labelTime; lv_obj_t* labelTimeAMPM; @@ -62,9 +63,9 @@ namespace Pinetime { lv_font_t* font_SquareRegular20 = nullptr; Controllers::DateTime& dateTimeController; + const Controllers::Battery& batteryController; Controllers::Settings& settingsController; Controllers::MotionController& motionController; - Controllers::Battery& batteryController; lv_task_t* taskRefresh; @@ -80,5 +81,23 @@ namespace Pinetime { void toggleBatteryChargingAnimation(bool enabled, uint8_t percent); }; } + + template <> + struct WatchFaceTraits { + static constexpr WatchFace watchFace = WatchFace::Gravel; + static constexpr const char* name = "Pebble face"; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::WatchFaceGravel(controllers.dateTimeController, + controllers.batteryController, + controllers.settingsController, + controllers.motionController, + controllers.filesystem); + }; + + static bool IsAvailable(Pinetime::Controllers::FS& filesystem) { + return Screens::WatchFaceGravel::IsAvailable(filesystem); + } + }; } } diff --git a/src/resources/fonts/SquareRegular.ttf b/src/resources/fonts/SquareRegular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9243923e229dce2989f863e1810b26705c06327f GIT binary patch literal 17180 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 literal 0 HcmV?d00001