diff --git a/.gitmodules b/.gitmodules index 7a4e307b..e629301e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "src/libs/arduinoFFT"] path = src/libs/arduinoFFT url = https://github.com/kosme/arduinoFFT.git +[submodule "src/libs/sunset"] + path = src/libs/sunset + url = https://github.com/buelowp/sunset.git diff --git a/shell.nix b/shell.nix index 45b92c8c..2cd26898 100644 --- a/shell.nix +++ b/shell.nix @@ -13,18 +13,14 @@ with pkgs; let nodejs node_modules/lv_img_conv/lv_img_conv.js ''; buildInfinitime = pkgs.writeScriptBin "build-infinitime" '' - mkdir build - cd build + mkdir -p build/ cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=$ARM_NONE_EABI_TOOLCHAIN_PATH \ -DNRF5_SDK_PATH=$NRF5_SDK_PATH \ -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE \ -DBUILD_DFU=$BUILD_DFU \ -DBUILD_RESOURCES=$BUILD_RESOURCES \ -DTARGET_DEVICE=$TARGET_DEVICE \ - -DENABLE_WATCHFACES="WatchFace::Analog,WatchFace::Digital,WatchFace::Fuzzy" \ - .. - - cd .. + -S . -B build cmake --build build -j6 ''; in mkShell { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd489879..5922bca7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -174,6 +174,11 @@ set(LITTLEFS_SRC libs/littlefs/lfs.c ) +set(SUNSET_SRC + libs/sunset/src/sunset.h + libs/sunset/src/sunset.cpp + ) + set(LVGL_SRC libs/lv_conf.h libs/lvgl/lvgl.h @@ -366,8 +371,6 @@ list(APPEND SOURCE_FILES displayapp/DisplayApp.cpp displayapp/screens/Screen.cpp displayapp/screens/Tile.cpp - displayapp/screens/InfiniPaint.cpp - displayapp/screens/Paddle.cpp displayapp/screens/StopWatch.cpp displayapp/screens/BatteryIcon.cpp displayapp/screens/BleIcon.cpp @@ -376,14 +379,9 @@ list(APPEND SOURCE_FILES displayapp/screens/Label.cpp displayapp/screens/FirmwareUpdate.cpp displayapp/screens/Music.cpp - displayapp/screens/Navigation.cpp - displayapp/screens/Metronome.cpp - displayapp/screens/Motion.cpp - displayapp/screens/Weather.cpp displayapp/screens/FirmwareValidation.cpp displayapp/screens/ApplicationList.cpp displayapp/screens/Notifications.cpp - displayapp/screens/Twos.cpp displayapp/screens/HeartRate.cpp displayapp/screens/FlashLight.cpp displayapp/screens/List.cpp @@ -420,13 +418,9 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingBluetooth.cpp ## Watch faces - displayapp/screens/WatchFaceAnalog.cpp displayapp/screens/WatchFaceDigital.cpp - displayapp/screens/WatchFaceInfineat.cpp - displayapp/screens/WatchFaceTerminal.cpp - displayapp/screens/WatchFacePineTimeStyle.cpp - displayapp/screens/WatchFaceCasioStyleG7710.cpp displayapp/screens/WatchFaceFuzzy.cpp + displayapp/screens/WatchFaceSundial.cpp ## @@ -591,9 +585,7 @@ set(INCLUDE_FILES displayapp/TouchEvents.h displayapp/screens/Screen.h displayapp/screens/Tile.h - displayapp/screens/InfiniPaint.h displayapp/screens/StopWatch.h - displayapp/screens/Paddle.h displayapp/screens/BatteryIcon.h displayapp/screens/BleIcon.h displayapp/screens/NotificationIcon.h @@ -607,11 +599,7 @@ set(INCLUDE_FILES displayapp/Apps.h displayapp/screens/Notifications.h displayapp/screens/HeartRate.h - displayapp/screens/Metronome.h - displayapp/screens/Motion.h displayapp/screens/Timer.h - displayapp/screens/Dice.h - displayapp/screens/Alarm.h displayapp/Colors.h displayapp/widgets/Counter.h displayapp/widgets/PageIndicator.h @@ -900,13 +888,25 @@ target_compile_options(littlefs PRIVATE $<$: ${ASM_FLAGS}> ) +# SUNSET_SRC +add_library(sunset STATIC ${SUNSET_SRC}) +target_include_directories(sunset SYSTEM PUBLIC . ../) +target_include_directories(sunset SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) +target_compile_options(sunset PRIVATE + ${COMMON_FLAGS} + $<$: ${DEBUG_FLAGS}> + $<$: ${RELEASE_FLAGS}> + $<$: ${CXX_FLAGS}> + $<$: ${ASM_FLAGS}> + ) + # Build autonomous binary (without support for bootloader) set(EXECUTABLE_NAME "pinetime-app") set(EXECUTABLE_FILE_NAME ${EXECUTABLE_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}) set(NRF5_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/gcc_nrf52.ld") add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES}) set_target_properties(${EXECUTABLE_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_FILE_NAME}) -target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl littlefs infinitime_fonts infinitime_apps) +target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl littlefs sunset infinitime_fonts infinitime_apps) target_compile_options(${EXECUTABLE_NAME} PUBLIC ${COMMON_FLAGS} ${WARNING_FLAGS} @@ -940,7 +940,7 @@ set(IMAGE_MCUBOOT_FILE_NAME_BIN ${EXECUTABLE_MCUBOOT_NAME}-image-${pinetime_VERS set(DFU_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip) set(NRF5_LINKER_SCRIPT_MCUBOOT "${CMAKE_SOURCE_DIR}/gcc_nrf52-mcuboot.ld") add_executable(${EXECUTABLE_MCUBOOT_NAME} ${SOURCE_FILES}) -target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl littlefs infinitime_fonts infinitime_apps) +target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl littlefs sunset infinitime_fonts infinitime_apps) set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_MCUBOOT_FILE_NAME}) target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC ${COMMON_FLAGS} @@ -982,7 +982,7 @@ endif() set(EXECUTABLE_RECOVERY_NAME "pinetime-recovery") set(EXECUTABLE_RECOVERY_FILE_NAME ${EXECUTABLE_RECOVERY_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}) add_executable(${EXECUTABLE_RECOVERY_NAME} ${RECOVERY_SOURCE_FILES}) -target_link_libraries(${EXECUTABLE_RECOVERY_NAME} nimble nrf-sdk littlefs infinitime_fonts infinitime_apps) +target_link_libraries(${EXECUTABLE_RECOVERY_NAME} nimble nrf-sdk littlefs sunset infinitime_fonts infinitime_apps) set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERY_FILE_NAME}) target_compile_definitions(${EXECUTABLE_RECOVERY_NAME} PUBLIC "PINETIME_IS_RECOVERY") target_compile_options(${EXECUTABLE_RECOVERY_NAME} PUBLIC @@ -1014,7 +1014,7 @@ set(IMAGE_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-image-$ set(IMAGE_RECOVERY_MCUBOOT_FILE_NAME_HEX ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}.hex) set(DFU_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip) add_executable(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} ${RECOVERY_SOURCE_FILES}) -target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk littlefs infinitime_fonts infinitime_apps) +target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk littlefs sunset infinitime_fonts infinitime_apps) set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}) target_compile_definitions(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC "PINETIME_IS_RECOVERY") target_compile_options(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h index d5a176d9..a786a8b3 100644 --- a/src/displayapp/UserApps.h +++ b/src/displayapp/UserApps.h @@ -2,19 +2,10 @@ #include "displayapp/apps/Apps.h" #include "Controllers.h" -#include "displayapp/screens/Alarm.h" -#include "displayapp/screens/Dice.h" -#include "displayapp/screens/Timer.h" -#include "displayapp/screens/Twos.h" -#include "displayapp/screens/Tile.h" #include "displayapp/screens/ApplicationList.h" -#include "displayapp/screens/WatchFaceDigital.h" #include "displayapp/screens/WatchFaceFuzzy.h" -#include "displayapp/screens/WatchFaceAnalog.h" -#include "displayapp/screens/WatchFaceCasioStyleG7710.h" -#include "displayapp/screens/WatchFaceInfineat.h" -#include "displayapp/screens/WatchFacePineTimeStyle.h" -#include "displayapp/screens/WatchFaceTerminal.h" +#include "displayapp/screens/WatchFaceSundial.h" +#include "displayapp/screens/WatchFaceDigital.h" namespace Pinetime { namespace Applications { diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 7d809712..6201da6b 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -51,6 +51,7 @@ namespace Pinetime { PineTimeStyle, Terminal, Fuzzy, + Sundial, Infineat, CasioStyleG7710, }; diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index d7858760..17906ff0 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -2,19 +2,11 @@ if(DEFINED ENABLE_USERAPPS) set(USERAPP_TYPES ${ENABLE_USERAPPS} CACHE STRING "List of user apps to build into the firmware") else () set(DEFAULT_USER_APP_TYPES "Apps::StopWatch") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Alarm") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Timer") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Steps") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::HeartRate") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Music") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paint") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Twos") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather") - #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion") set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware") endif () @@ -22,11 +14,8 @@ if(DEFINED ENABLE_WATCHFACES) set(WATCHFACE_TYPES ${ENABLE_WATCHFACES} CACHE STRING "List of watch faces to build into the firmware") else() set(DEFAULT_WATCHFACE_TYPES "WatchFace::Digital") - set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Analog") - 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") - set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::CasioStyleG7710") + set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Fuzzy") + set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Sundial") set(WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}" CACHE STRING "List of watch faces to build into the firmware") endif() diff --git a/src/displayapp/screens/WatchFaceSundial.cpp b/src/displayapp/screens/WatchFaceSundial.cpp new file mode 100644 index 00000000..b99204b0 --- /dev/null +++ b/src/displayapp/screens/WatchFaceSundial.cpp @@ -0,0 +1,149 @@ +#include "displayapp/screens/WatchFaceSundial.h" + +#include +#include +// #include +#include "displayapp/screens/NotificationIcon.h" +#include "displayapp/screens/Symbols.h" +#include "displayapp/screens/WeatherSymbols.h" +#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/ble/SimpleWeatherService.h" +#include "components/settings/Settings.h" +#include "sunset/src/sunset.h" + +using namespace Pinetime::Applications::Screens; + +// namespace { +// int16_t HourLength = 70; +// constexpr int16_t MinuteLength = 90; +// constexpr int16_t SecondLength = 110; +// constexpr int16_t SunDialVerticalOffset = 40; + +// // sin(90) = 1 so the value of _lv_trigo_sin(90) is the scaling factor +// const auto LV_TRIG_SCALE = _lv_trigo_sin(90); +// const lv_color_t DARK_GRAY = lv_color_make(48, 48, 48); +// const lv_color_t DARK_ORANGE = lv_color_make(48, 26, 0); + +// 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)}; +// } + +// int16_t CoordinateYRelocateSundial(int16_t y) { +// return std::abs(y - SunDialVerticalOffset); +// } + +// lv_point_t CoordinateRelocateSundial(int16_t radius, int16_t angle) { +// return lv_point_t {.x = CoordinateXRelocate(radius * static_cast(Sine(angle)) / LV_TRIG_SCALE), +// .y = CoordinateYRelocateSundial(radius * static_cast(Cosine(angle)) / LV_TRIG_SCALE)}; +// } + +// } + +WatchFaceSundial::WatchFaceSundial(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weatherService) + : currentDateTime {{}}, + dateTimeController {dateTimeController}, + notificationManager {notificationManager}, + settingsController {settingsController}, + heartRateController {heartRateController}, + motionController {motionController}, + weatherService {weatherService}, + statusIcons(batteryController, bleController) { + + statusIcons.Create(); + + 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, nullptr, 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, nullptr, LV_ALIGN_IN_TOP_MID, 20, 50); + + label_date = lv_label_create(lv_scr_act(), nullptr); + lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); + lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + + 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_bold_20); + lv_label_set_recolor(label_time, true); + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + Refresh(); +} + +WatchFaceSundial::~WatchFaceSundial() { + lv_task_del(taskRefresh); + lv_obj_clean(lv_scr_act()); +} + +void WatchFaceSundial::Refresh() { + currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + if (currentDateTime.IsUpdated()) { + currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + if (currentDate.IsUpdated()) { + uint16_t year = dateTimeController.Year(); + uint8_t day = dateTimeController.Day(); + lv_label_set_text_fmt(label_date, + "%s %d %s %d", + dateTimeController.DayOfWeekShortToString(), + day, + dateTimeController.MonthShortToString(), + year); + lv_obj_realign(label_date); + } + } + + currentWeather = weatherService.Current(); + if (currentWeather.IsUpdated()) { + auto optCurrentWeather = currentWeather.Get(); + if (optCurrentWeather) { + int16_t temp = optCurrentWeather->temperature; + char tempUnit = 'C'; + if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp); + tempUnit = 'F'; + } + temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); + 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); + } +} diff --git a/src/displayapp/screens/WatchFaceSundial.h b/src/displayapp/screens/WatchFaceSundial.h new file mode 100644 index 00000000..9c02fdfe --- /dev/null +++ b/src/displayapp/screens/WatchFaceSundial.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include +#include +#include "displayapp/screens/Screen.h" +#include "components/datetime/DateTimeController.h" +#include "components/ble/SimpleWeatherService.h" +#include "components/ble/BleController.h" +#include "displayapp/widgets/StatusIcons.h" +#include "utility/DirtyValue.h" +#include "displayapp/apps/Apps.h" + +namespace Pinetime { + namespace Controllers { + class Settings; + class Battery; + class Ble; + class NotificationManager; + class HeartRateController; + class MotionController; + } + + namespace Applications { + namespace Screens { + + class WatchFaceSundial : public Screen { + public: + WatchFaceSundial(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weather); + ~WatchFaceSundial() override; + + void Refresh() override; + + private: + uint8_t displayedHour = -1; + uint8_t displayedMinute = -1; + + Utility::DirtyValue> currentDateTime {}; + Utility::DirtyValue stepCount {}; + Utility::DirtyValue heartbeat {}; + Utility::DirtyValue heartbeatRunning {}; + Utility::DirtyValue notificationState {}; + Utility::DirtyValue> currentWeather {}; + + Utility::DirtyValue> currentDate; + + lv_obj_t* label_time; + lv_obj_t* label_time_ampm; + lv_obj_t* label_date; + lv_obj_t* heartbeatIcon; + lv_obj_t* heartbeatValue; + lv_obj_t* stepIcon; + lv_obj_t* stepValue; + 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; + + lv_task_t* taskRefresh; + Widgets::StatusIcons statusIcons; + }; + } + + template <> + struct WatchFaceTraits { + static constexpr WatchFace watchFace = WatchFace::Sundial; + static constexpr const char* name = "Sundial face"; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::WatchFaceSundial(controllers.dateTimeController, + controllers.batteryController, + controllers.bleController, + controllers.notificationManager, + controllers.settingsController, + controllers.heartRateController, + controllers.motionController, + *controllers.weatherController); + }; + + static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { + return true; + } + }; + } +}