diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index faef4160da..aae4297e3d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -429,6 +429,7 @@ list(APPEND SOURCE_FILES displayapp/screens/WatchFaceTerminal.cpp displayapp/screens/WatchFacePineTimeStyle.cpp displayapp/screens/WatchFaceCasioStyleG7710.cpp + displayapp/screens/WatchFaceNumerals.cpp displayapp/screens/WatchFacePrideFlag.cpp ## diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h index 25926edc40..731a4e0369 100644 --- a/src/displayapp/UserApps.h +++ b/src/displayapp/UserApps.h @@ -14,6 +14,7 @@ #include "displayapp/screens/WatchFaceInfineat.h" #include "displayapp/screens/WatchFacePineTimeStyle.h" #include "displayapp/screens/WatchFaceTerminal.h" +#include "displayapp/screens/WatchFaceNumerals.h" #include "displayapp/screens/WatchFacePrideFlag.h" namespace Pinetime { diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index d440b598d1..b8f90b2753 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -55,6 +55,7 @@ namespace Pinetime { Terminal, Infineat, CasioStyleG7710, + Numerals, PrideFlag, }; diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 93196ed6a0..c00203128b 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -28,6 +28,7 @@ else() set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Infineat") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::CasioStyleG7710") + set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Numerals") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::PrideFlag") set(WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}" CACHE STRING "List of watch faces to build into the firmware") endif() diff --git a/src/displayapp/screens/WatchFaceNumerals.cpp b/src/displayapp/screens/WatchFaceNumerals.cpp new file mode 100644 index 0000000000..dd94a630c3 --- /dev/null +++ b/src/displayapp/screens/WatchFaceNumerals.cpp @@ -0,0 +1,138 @@ +#include "displayapp/screens/WatchFaceNumerals.h" + +#include +#include +#include "displayapp/screens/Symbols.h" +#include "components/ble/NotificationManager.h" +#include "components/settings/Settings.h" + +using namespace Pinetime::Applications::Screens; + +WatchFaceNumerals::WatchFaceNumerals(Controllers::DateTime& dateTimeController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::FS& filesystem) + : currentDateTime {{}}, + dateTimeController {dateTimeController}, + notificationManager {notificationManager}, + settingsController {settingsController} { + + lfs_file f = {}; + if (filesystem.FileOpen(&f, "/fonts/rounded_large.bin", LFS_O_RDONLY) >= 0) { + filesystem.FileClose(&f); + fontLarge = lv_font_load("F:/fonts/rounded_large.bin"); + } + + if (filesystem.FileOpen(&f, "/fonts/rounded_small.bin", LFS_O_RDONLY) >= 0) { + filesystem.FileClose(&f); + fontSmall = lv_font_load("F:/fonts/rounded_small.bin"); + } + + notificationIcon = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_bg_color(notificationIcon, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); + lv_obj_set_style_local_radius(notificationIcon, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); + lv_obj_set_size(notificationIcon, 16, 16); + lv_obj_align(notificationIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 4, -76); + lv_obj_set_hidden(notificationIcon, true); + + labelTimeHour = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(labelTimeHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fontLarge); + lv_obj_set_style_local_text_color(labelTimeHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + lv_obj_align(labelTimeHour, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -160, -125); + + labelTimeMinute = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(labelTimeMinute, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fontLarge); + lv_obj_set_style_local_text_color(labelTimeMinute, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); + lv_obj_align(labelTimeMinute, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -160, 0); + + labelTimeAMPM1 = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(labelTimeAMPM1, ""); + lv_obj_set_style_local_text_font(labelTimeAMPM1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fontSmall); + lv_obj_set_style_local_text_color(labelTimeAMPM1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, ampmColor); + lv_obj_align(labelTimeAMPM1, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 2, -34); + // We use two labels for more flexibility with alignment + labelTimeAMPM2 = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(labelTimeAMPM2, "M"); + lv_obj_set_style_local_text_font(labelTimeAMPM2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fontSmall); + lv_obj_set_style_local_text_color(labelTimeAMPM2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, ampmColor); + lv_obj_align(labelTimeAMPM2, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + + dateDayOfWeek = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_font(dateDayOfWeek, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fontSmall); + lv_obj_align(dateDayOfWeek, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0); + + dateDay = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(dateDay, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_font(dateDay, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fontSmall); + lv_obj_align(dateDay, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 36); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + Refresh(); +} + +WatchFaceNumerals::~WatchFaceNumerals() { + lv_task_del(taskRefresh); + + if (fontLarge != nullptr) { + lv_font_free(fontLarge); + } + if (fontSmall != nullptr) { + lv_font_free(fontSmall); + } + + lv_obj_clean(lv_scr_act()); +} + +void WatchFaceNumerals::Refresh() { + notificationState = notificationManager.AreNewNotificationsAvailable(); + if (notificationState.IsUpdated()) { + lv_obj_set_hidden(notificationIcon, !notificationState.Get()); + } + + currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + if (currentDateTime.IsUpdated()) { + uint8_t hour = dateTimeController.Hours(); + uint8_t minute = dateTimeController.Minutes(); + + if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + char ampmChar[2] = "A"; + 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(labelTimeAMPM1, ampmChar); + } else { + lv_obj_set_hidden(labelTimeAMPM2, true); + } + lv_label_set_text_fmt(labelTimeHour, "%02d", hour); + lv_label_set_text_fmt(labelTimeMinute, "%02d", minute); + + currentDate = std::chrono::time_point_cast(currentDateTime.Get()); + if (currentDate.IsUpdated()) { + lv_label_set_text_static(dateDayOfWeek, dateTimeController.DayOfWeekShortToString()); + lv_label_set_text_fmt(dateDay, "%d", dateTimeController.Day()); + lv_obj_realign(dateDay); + } + } +} + +bool WatchFaceNumerals::IsAvailable(Pinetime::Controllers::FS& filesystem) { + lfs_file file = {}; + + if (filesystem.FileOpen(&file, "/fonts/rounded_small.bin", LFS_O_RDONLY) < 0) { + return false; + } + + filesystem.FileClose(&file); + if (filesystem.FileOpen(&file, "/fonts/rounded_large.bin", LFS_O_RDONLY) < 0) { + return false; + } + + filesystem.FileClose(&file); + return true; +} diff --git a/src/displayapp/screens/WatchFaceNumerals.h b/src/displayapp/screens/WatchFaceNumerals.h new file mode 100644 index 0000000000..cdcdaa0b42 --- /dev/null +++ b/src/displayapp/screens/WatchFaceNumerals.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "displayapp/screens/Screen.h" +#include "components/datetime/DateTimeController.h" +#include "utility/DirtyValue.h" +#include "displayapp/apps/Apps.h" + +namespace Pinetime { + namespace Controllers { + class Settings; + class NotificationManager; + } + + namespace Applications { + namespace Screens { + + class WatchFaceNumerals : public Screen { + public: + WatchFaceNumerals(Controllers::DateTime& dateTimeController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::FS& fs); + ~WatchFaceNumerals() override; + + void Refresh() override; + + static bool IsAvailable(Pinetime::Controllers::FS& filesystem); + + private: + static constexpr lv_color_t ampmColor = LV_COLOR_MAKE(0x99, 0x99, 0x99); + + Utility::DirtyValue notificationState {}; + Utility::DirtyValue> currentDateTime {}; + Utility::DirtyValue> currentDate; + + lv_obj_t* labelTimeHour; + lv_obj_t* labelTimeMinute; + lv_obj_t* labelTimeAMPM1; + lv_obj_t* labelTimeAMPM2; + lv_obj_t* label_date; + lv_obj_t* notificationIcon; + lv_obj_t* dateDay; + lv_obj_t* dateDayOfWeek; + + Controllers::DateTime& dateTimeController; + Controllers::NotificationManager& notificationManager; + Controllers::Settings& settingsController; + + lv_font_t* fontLarge = nullptr; + lv_font_t* fontSmall = nullptr; + + lv_task_t* taskRefresh; + }; + } + + template <> + struct WatchFaceTraits { + static constexpr WatchFace watchFace = WatchFace::Numerals; + static constexpr const char* name = "Numerals"; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::WatchFaceNumerals(controllers.dateTimeController, + controllers.notificationManager, + controllers.settingsController, + controllers.filesystem); + }; + + static bool IsAvailable(Pinetime::Controllers::FS& filesystem) { + return Screens::WatchFaceNumerals::IsAvailable(filesystem); + } + }; + } +} diff --git a/src/resources/fonts.json b/src/resources/fonts.json index c4a63349a1..2f8a9f6807 100644 --- a/src/resources/fonts.json +++ b/src/resources/fonts.json @@ -58,5 +58,29 @@ "size": 115, "format": "bin", "target_path": "/fonts/" + }, + "rounded_large": { + "sources": [ + { + "file": "fonts/BloggerSans-Bold.ttf", + "symbols": "0123456789" + } + ], + "bpp": 1, + "size": 150, + "format": "bin", + "target_path": "/fonts/" + }, + "rounded_small": { + "sources": [ + { + "file": "fonts/BloggerSans-Bold.ttf", + "symbols": "0123456789APMONTUEWDHRFIS" + } + ], + "bpp": 1, + "size": 30, + "format": "bin", + "target_path": "/fonts/" } } diff --git a/src/resources/fonts/BloggerSans-Bold.ttf b/src/resources/fonts/BloggerSans-Bold.ttf new file mode 100644 index 0000000000..d287255d91 Binary files /dev/null and b/src/resources/fonts/BloggerSans-Bold.ttf differ