From d8c3624f6f15e66b0b726cf1bf6ddc97bfed311b Mon Sep 17 00:00:00 2001 From: Will Bradley Date: Mon, 8 Jan 2024 17:40:56 -0800 Subject: [PATCH] Add location, timezone, and long-press switching --- .github/workflows/main.yml | 3 + docker/infinisim-cmake.patch | 19 +++ src/CMakeLists.txt | 21 ++-- src/components/settings/Settings.h | 22 ++++ src/displayapp/DisplayApp.cpp | 4 + src/displayapp/apps/Apps.h.in | 1 + src/displayapp/screens/WatchFaceAnalog.cpp | 71 ++++++----- src/displayapp/screens/WatchFaceAnalog.h | 3 + src/displayapp/screens/WatchFaceDigital.cpp | 112 ++++++++++++------ src/displayapp/screens/WatchFaceDigital.h | 5 +- .../screens/settings/SettingLocation.cpp | 69 +++++++++++ .../screens/settings/SettingLocation.h | 31 +++++ src/displayapp/screens/settings/Settings.h | 1 + src/displayapp/widgets/Counter.cpp | 3 +- src/displayapp/widgets/Counter.h | 11 ++ 15 files changed, 297 insertions(+), 79 deletions(-) create mode 100644 docker/infinisim-cmake.patch create mode 100644 src/displayapp/screens/settings/SettingLocation.cpp create mode 100644 src/displayapp/screens/settings/SettingLocation.h diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 20c6bd7d..0ae1825b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -88,6 +88,9 @@ jobs: git clone https://github.com/InfiniTimeOrg/InfiniSim.git --depth 1 --branch main git -C InfiniSim submodule update --init lv_drivers + - name: Add sunset lib to InfiniSim + run: patch -i docker/infinisim-cmake.patch InfiniSim/CMakeLists.txt + - name: CMake # disable BUILD_RESOURCES as this is already done when building the firmware run: | diff --git a/docker/infinisim-cmake.patch b/docker/infinisim-cmake.patch new file mode 100644 index 00000000..cf725db7 --- /dev/null +++ b/docker/infinisim-cmake.patch @@ -0,0 +1,19 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index edd6748..641b74a 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -243,6 +243,14 @@ add_library(littlefs STATIC + target_include_directories(littlefs PUBLIC "${InfiniTime_DIR}/src/libs/littlefs") + target_link_libraries(infinisim PRIVATE littlefs) + ++# sunset ++add_library(sunset STATIC ++ ${InfiniTime_DIR}/src/libs/sunset/src/sunset.h ++ ${InfiniTime_DIR}/src/libs/sunset/src/sunset.cpp ++) ++target_include_directories(sunset PUBLIC "${InfiniTime_DIR}/src/libs/sunset") ++target_link_libraries(infinisim PRIVATE sunset) ++ + # QCBOR + add_library(QCBOR STATIC + ${InfiniTime_DIR}/src/libs/QCBOR/src/ieee754.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8537563c..2efa7997 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -174,7 +174,7 @@ set(LITTLEFS_SRC libs/littlefs/lfs.c ) -set(SUNRISE_SRC +set(SUNSET_SRC libs/sunset/src/sunset.h libs/sunset/src/sunset.cpp ) @@ -417,6 +417,7 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingSetDateTime.cpp displayapp/screens/settings/SettingSetDate.cpp displayapp/screens/settings/SettingSetTime.cpp + displayapp/screens/settings/SettingLocation.cpp displayapp/screens/settings/SettingChimes.cpp displayapp/screens/settings/SettingShakeThreshold.cpp displayapp/screens/settings/SettingBluetooth.cpp @@ -902,11 +903,11 @@ target_compile_options(littlefs PRIVATE $<$: ${ASM_FLAGS}> ) -# SUNRISE_SRC -add_library(sunrise STATIC ${SUNRISE_SRC}) -target_include_directories(sunrise SYSTEM PUBLIC . ../) -target_include_directories(sunrise SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) -target_compile_options(sunrise PRIVATE +# 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}> @@ -920,7 +921,7 @@ set(EXECUTABLE_FILE_NAME ${EXECUTABLE_NAME}-${pinetime_VERSION_MAJOR}.${pinetime 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 sunrise 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} @@ -954,7 +955,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 sunrise 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} @@ -996,7 +997,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 sunrise 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 @@ -1028,7 +1029,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 sunrise 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/components/settings/Settings.h b/src/components/settings/Settings.h index 60ab0249..55b5a32c 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -50,6 +50,12 @@ namespace Pinetime { int colorIndex = 0; }; + struct Location { + int16_t latitude; + int16_t longitude; + int8_t tzOffset; + }; + Settings(Pinetime::Controllers::FS& fs); Settings(const Settings&) = delete; @@ -275,6 +281,21 @@ namespace Pinetime { return settings.stepsGoal; }; + void SetLocation(Location loc) { + if ( + loc.latitude != settings.location.latitude || + loc.longitude != settings.location.longitude || + loc.tzOffset != settings.location.tzOffset + ) { + settingsChanged = true; + } + settings.location = loc; + }; + + Location GetLocation() const { + return settings.location; + }; + void SetBleRadioEnabled(bool enabled) { bleRadioEnabled = enabled; }; @@ -308,6 +329,7 @@ namespace Pinetime { uint16_t shakeWakeThreshold = 150; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; + Location location = {(int16_t)0,(int16_t)0,(int8_t)0}; }; SettingsData settings; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 2792009f..8e0c4052 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -44,6 +44,7 @@ #include "displayapp/screens/settings/SettingDisplay.h" #include "displayapp/screens/settings/SettingSteps.h" #include "displayapp/screens/settings/SettingSetDateTime.h" +#include "displayapp/screens/settings/SettingLocation.h" #include "displayapp/screens/settings/SettingChimes.h" #include "displayapp/screens/settings/SettingShakeThreshold.h" #include "displayapp/screens/settings/SettingBluetooth.h" @@ -514,6 +515,9 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio case Apps::SettingSetDateTime: currentScreen = std::make_unique(this, dateTimeController, settingsController); break; + case Apps::SettingLocation: + currentScreen = std::make_unique(settingsController); + break; case Apps::SettingChimes: currentScreen = std::make_unique(settingsController); break; diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 11fe17b5..a5e60c80 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -37,6 +37,7 @@ namespace Pinetime { SettingWakeUp, SettingSteps, SettingSetDateTime, + SettingLocation, SettingChimes, SettingShakeThreshold, SettingBluetooth, diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index 1b88fee3..6d67f1e4 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -8,6 +8,7 @@ #include "displayapp/screens/NotificationIcon.h" #include "components/settings/Settings.h" #include "displayapp/InfiniTimeTheme.h" +#include "sunset/src/sunset.h" using namespace Pinetime::Applications::Screens; @@ -71,12 +72,9 @@ WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController, sMinute = 99; sSecond = 99; - minutesSunrise = 360; //sun.calcSunrise(); - minutesSunset = 1080; //sun.calcSunset(); - minutesDaytime = (minutesSunset - minutesSunrise); - minutesNighttime = (1440 - minutesDaytime); + location = settingsController.GetLocation(); - // begin sundial + // begin sundial watch face if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) { major_scales = lv_linemeter_create(lv_scr_act(), nullptr); lv_linemeter_set_scale(major_scales, 165, 11); @@ -217,30 +215,49 @@ WatchFaceAnalog::~WatchFaceAnalog() { void WatchFaceAnalog::drawWatchFaceModeNight(){ uint8_t hour = dateTimeController.Hours(); uint8_t minute = dateTimeController.Minutes(); - minutesBeforeSunset = minutesSunset - (hour * 60 + minute); // i.e.zero degrees - HourLength = 90; // sundial hand length - - int16_t hourAngle; - - if(minutesBeforeSunset > 0 && minutesBeforeSunset < minutesDaytime) { // day (after sunrise) - hourAngle = 180.0 * minutesBeforeSunset / minutesDaytime + 90; - } else { // night (before sunrise or after sunset) - lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, DARK_GRAY); - lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, DARK_GRAY); - lv_obj_set_style_local_scale_end_color(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY); - lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_ORANGE); - lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY); - lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY); - - if(minutesBeforeSunset > minutesDaytime) { // before sunrise - hourAngle = 180.0 * (minutesBeforeSunset - minutesDaytime) / minutesNighttime + 90; - } else { // after sunset - hourAngle = 180 + 180.0 * minutesBeforeSunset / minutesNighttime + 90; - } - } - //NRF_LOG_INFO("angle : %d, sun %d day %d len %d", hourAngle, minutesBeforeSunset, minutesDaytime, HourLength); if (sHour != hour || sMinute != minute) { + // sun.setPosition(settings.lat.toFloat(), settings.lon.toFloat(), settings.gmtOffset / 3600); + sun.setPosition((float)location.latitude, (float)location.longitude, location.tzOffset); + + //from minutes past midnight + sun.setCurrentDate(dateTimeController.Year(), static_cast(dateTimeController.Month())+1, dateTimeController.Day()); + sun.setTZOffset(location.tzOffset); + + minutesSunrise = sun.calcSunrise(); //360; + minutesSunset = sun.calcSunset(); //1080; + minutesDaytime = (minutesSunset - minutesSunrise); + minutesNighttime = (1440 - minutesDaytime); + + minutesBeforeSunset = minutesSunset - (hour * 60 + minute); // i.e.zero degrees + HourLength = 90; // sundial hand length + + int16_t hourAngle; + + if(minutesBeforeSunset > 0 && minutesBeforeSunset < minutesDaytime) { // day (after sunrise) + hourAngle = 180.0 * minutesBeforeSunset / minutesDaytime + 90; + } else { // night (before sunrise or after sunset) + lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, DARK_GRAY); + lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, DARK_GRAY); + lv_obj_set_style_local_scale_end_color(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY); + lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_ORANGE); + lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY); + lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY); + + if(minutesBeforeSunset > minutesDaytime) { // before sunrise + hourAngle = 180.0 * (minutesBeforeSunset - minutesDaytime) / minutesNighttime + 90; + } else { // after sunset + hourAngle = 180 + 180.0 * minutesBeforeSunset / minutesNighttime + 90; + } + } + /*NRF_LOG_INFO("a: %d, la: %f, lo: %f, ri: %d, se: %d, be: %d", + hourAngle, + (float)location.latitude, + (float)location.longitude, + minutesSunrise, + minutesSunset, + minutesBeforeSunset);*/ + sHour = hour; sMinute = minute; diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h index 91e9c812..05bb9e3f 100644 --- a/src/displayapp/screens/WatchFaceAnalog.h +++ b/src/displayapp/screens/WatchFaceAnalog.h @@ -11,6 +11,7 @@ #include "components/ble/NotificationManager.h" #include "displayapp/screens/BatteryIcon.h" #include "utility/DirtyValue.h" +#include "sunset/src/sunset.h" namespace Pinetime { namespace Controllers { @@ -77,6 +78,8 @@ namespace Pinetime { BatteryIcon batteryIcon; + Controllers::Settings::Location location; + SunSet sun; int16_t minutesSunrise; int16_t minutesSunset; int16_t minutesDaytime; diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 51ac2630..f8d9a314 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -28,6 +28,8 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController, motionController {motionController}, statusIcons(batteryController, bleController) { + sHour = 99; + sMinute = 99; statusIcons.Create(); notificationIcon = lv_label_create(lv_scr_act(), nullptr); @@ -40,14 +42,18 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController, 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_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) { + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + } else if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); + lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); } else { + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); } - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); - label_time_ampm = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(label_time_ampm, ""); lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -30, -55); @@ -89,51 +95,63 @@ void WatchFaceDigital::Refresh() { lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); } - currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + currentDateTime = dateTimeController.CurrentDateTime(); if (currentDateTime.IsUpdated()) { + uint8_t hour = dateTimeController.Hours(); uint8_t minute = dateTimeController.Minutes(); - /* Begin difference from WatchFaceDigital*/ - if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) { - std::string hourStr, timeStr; - hour = hour % 12; // 12 becomes 0, 13 becomes 1 - auto sector = minute / 15 + (minute % 15 > 7); - // advance the hour modulo 12 and reset the minutes if we're close to the top - // so we get "quarter to $hour+1" instead of needing "three quarters past $hour" - if (sector > 3) { - hour = (hour + 1) % 12; - sector = 0; - } + if (sHour != hour || sMinute != minute || forceRefresh == true) { + forceRefresh = false; + sHour = hour; + sMinute = minute; - timeStr = timeSectors[sector]; - if (timeStr.find("%1") != std::string::npos) { - hour = (hour + 1) % 12; - } - //hourStr = std::string("#") + timeAccent + " " + hourNames[hour] + "#"; - hourStr = hourNames[hour]; - timeStr.replace(timeStr.find("%"), 2, hourStr); + /* Begin difference from WatchFaceDigital*/ + if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) { + std::string hourStr, timeStr; + hour = hour % 12; // 12 becomes 0, 13 becomes 1 + auto sector = minute / 15 + (minute % 15 > 7); + // advance the hour modulo 12 and reset the minutes if we're close to the top + // so we get "quarter to $hour+1" instead of needing "three quarters past $hour" + if (sector > 3) { + hour = (hour + 1) % 12; + sector = 0; + } - lv_label_set_text(label_time, timeStr.c_str()); - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); - /* End difference from WatchFaceDigital*/ - } else 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'; + timeStr = timeSectors[sector]; + if (timeStr.find("%1") != std::string::npos) { + hour = (hour + 1) % 12; + } + //hourStr = std::string("#") + timeAccent + " " + hourNames[hour] + "#"; + hourStr = hourNames[hour]; + timeStr.replace(timeStr.find("%"), 2, hourStr); + + lv_label_set_text(label_time_ampm, ""); + lv_label_set_text(label_time, timeStr.c_str()); + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, -10); + lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + /* End difference from WatchFaceDigital*/ + } else if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { + char ampmChar[3] = "AM"; + if (hour == 0) { + hour = 12; + } else if (hour == 12) { + ampmChar[0] = 'P'; + } else if (hour > 12) { + hour = hour - 12; + ampmChar[0] = 'P'; + } + lv_label_set_text(label_time_ampm, ampmChar); + lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute); + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); + lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); + } else { + lv_label_set_text_fmt(label_time, "%02d:%02d", hour, minute); + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); } - lv_label_set_text(label_time_ampm, ampmChar); - lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute); - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); - } else { - lv_label_set_text_fmt(label_time, "%02d:%02d", hour, minute); - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + lv_obj_realign(label_time); } currentDate = std::chrono::time_point_cast(currentDateTime.Get()); @@ -182,6 +200,22 @@ void WatchFaceDigital::Refresh() { } } +bool WatchFaceDigital::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + if ((event == Pinetime::Applications::TouchEvents::LongTap)) { + Pinetime::Controllers::Settings::ClockType clockType = settingsController.GetClockType(); + if (clockType == Pinetime::Controllers::Settings::ClockType::Fuzzy) { + settingsController.SetClockType(Pinetime::Controllers::Settings::ClockType::H12); + } else { + settingsController.SetClockType(Pinetime::Controllers::Settings::ClockType::Fuzzy); + } + settingsController.SaveSettings(); + forceRefresh=true; + WatchFaceDigital::Refresh(); + return true; + } + return false; +} + /* Inspired by XFCE4-panel's fuzzy clock. * * https://salsa.debian.org/xfce-team/desktop/xfce4-panel/-/blob/debian/master/plugins/clock/clock-fuzzy.c diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index c847ec2a..bfb50562 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -35,9 +35,11 @@ namespace Pinetime { Controllers::MotionController& motionController); ~WatchFaceDigital() override; + bool OnTouchEvent(TouchEvents event) override; void Refresh() override; private: + uint8_t sHour, sMinute; uint8_t displayedHour = -1; uint8_t displayedMinute = -1; static const char* timeSectors[4]; @@ -47,7 +49,7 @@ namespace Pinetime { Utility::DirtyValue powerPresent {}; Utility::DirtyValue bleState {}; Utility::DirtyValue bleRadioEnabled {}; - Utility::DirtyValue> currentDateTime {}; + Utility::DirtyValue> currentDateTime; Utility::DirtyValue stepCount {}; Utility::DirtyValue heartbeat {}; Utility::DirtyValue heartbeatRunning {}; @@ -71,6 +73,7 @@ namespace Pinetime { Controllers::MotionController& motionController; lv_task_t* taskRefresh; + bool forceRefresh=false; Widgets::StatusIcons statusIcons; }; } diff --git a/src/displayapp/screens/settings/SettingLocation.cpp b/src/displayapp/screens/settings/SettingLocation.cpp new file mode 100644 index 00000000..07b2c468 --- /dev/null +++ b/src/displayapp/screens/settings/SettingLocation.cpp @@ -0,0 +1,69 @@ +#include "displayapp/screens/settings/SettingLocation.h" +#include +#include +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Symbols.h" +#include "components/settings/Settings.h" +#include "displayapp/InfiniTimeTheme.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + constexpr int16_t POS_Y_TEXT = 25; + + void ValueChangedHandler(void* userData) { + auto* screen = static_cast(userData); + screen->UpdateScreen(); + } +} + +SettingLocation::SettingLocation(Pinetime::Controllers::Settings& settingsController) + : settingsController {settingsController} { + + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(title, "Set location\n(lat/long/tz)"); + lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); + lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 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::map); + lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); + lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); + + Controllers::Settings::Location loc = settingsController.GetLocation(); + + latCounter.Create(); + latCounter.SetWidth(80); + latCounter.SetValue(loc.latitude); + lv_obj_align(latCounter.GetObject(), nullptr, LV_ALIGN_CENTER, -90, POS_Y_TEXT); + latCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + longCounter.Create(); + longCounter.SetWidth(110); + longCounter.SetValue(loc.longitude); + lv_obj_align(longCounter.GetObject(), nullptr, LV_ALIGN_CENTER, -5, POS_Y_TEXT); + longCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + tzCounter.Create(); + tzCounter.SetWidth(60); + tzCounter.SetValue(loc.tzOffset); + lv_obj_align(tzCounter.GetObject(), nullptr, LV_ALIGN_CENTER, 75, POS_Y_TEXT); + tzCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + UpdateScreen(); +} + +SettingLocation::~SettingLocation() { + lv_obj_clean(lv_scr_act()); + settingsController.SaveSettings(); +} + +void SettingLocation::UpdateScreen() { + Controllers::Settings::Location loc = { + latitude: (int16_t)latCounter.GetValue(), + longitude: (int16_t)longCounter.GetValue(), + tzOffset: (int8_t)tzCounter.GetValue(), + }; + settingsController.SetLocation(loc); +} \ No newline at end of file diff --git a/src/displayapp/screens/settings/SettingLocation.h b/src/displayapp/screens/settings/SettingLocation.h new file mode 100644 index 00000000..9596d12f --- /dev/null +++ b/src/displayapp/screens/settings/SettingLocation.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include "components/datetime/DateTimeController.h" +#include "components/settings/Settings.h" +#include "displayapp/widgets/Counter.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/widgets/DotIndicator.h" +#include "displayapp/screens/settings/SettingSetDateTime.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class SettingLocation : public Screen { + public: + SettingLocation(Pinetime::Controllers::Settings& settingsController); + ~SettingLocation() override; + + void UpdateScreen(); + + private: + Controllers::Settings& settingsController; + + Widgets::Counter latCounter = Widgets::Counter(-90, 90, jetbrains_mono_42); + Widgets::Counter longCounter = Widgets::Counter(-180, 180, jetbrains_mono_42); + Widgets::Counter tzCounter = Widgets::Counter(-12, 12, jetbrains_mono_42); + }; + } + } +} diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index a21b4ccd..4e131938 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -39,6 +39,7 @@ namespace Pinetime { {Symbols::shoe, "Steps", Apps::SettingSteps}, {Symbols::clock, "Date&Time", Apps::SettingSetDateTime}, + {Symbols::map, "Location", Apps::SettingLocation}, {Symbols::cloudSunRain, "Weather", Apps::SettingWeatherFormat}, {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}, diff --git a/src/displayapp/widgets/Counter.cpp b/src/displayapp/widgets/Counter.cpp index b486e372..91cf1e18 100644 --- a/src/displayapp/widgets/Counter.cpp +++ b/src/displayapp/widgets/Counter.cpp @@ -136,8 +136,7 @@ void Counter::Create() { static constexpr uint8_t padding = 5; const uint8_t width = std::max(lv_obj_get_width(number) + padding * 2, 58); - static constexpr uint8_t btnHeight = 50; - const uint8_t containerHeight = btnHeight * 2 + lv_obj_get_height(number) + padding * 2; + containerHeight = btnHeight * 2 + lv_obj_get_height(number) + padding * 2; lv_obj_set_size(counterContainer, width, containerHeight); diff --git a/src/displayapp/widgets/Counter.h b/src/displayapp/widgets/Counter.h index 825860b8..2deb3a99 100644 --- a/src/displayapp/widgets/Counter.h +++ b/src/displayapp/widgets/Counter.h @@ -18,6 +18,15 @@ namespace Pinetime { void EnableMonthMode(); void SetMax(int newMax); void SetValueChangedEventCallback(void* userData, void (*handler)(void* userData)); + void SetWidth(uint8_t width) { + lv_obj_set_size(counterContainer, width, containerHeight); + lv_obj_set_size(upBtn, width, btnHeight); + lv_obj_set_size(downBtn, width, btnHeight); + linePoints[0] = {0, 0}; + linePoints[1] = {width, 0}; + lv_line_set_points(upperLine, linePoints, 2); + lv_line_set_points(lowerLine, linePoints, 2); + } int GetValue() const { return value; @@ -42,6 +51,8 @@ namespace Pinetime { int max; int value; const int leadingZeroCount; + uint8_t containerHeight; + static constexpr uint8_t btnHeight = 50; bool twelveHourMode = false; bool monthMode = false; lv_font_t& font;