From f6a558854425aaf14bd70b829d198e1a0eedca51 Mon Sep 17 00:00:00 2001 From: Ryan Rix Date: Mon, 10 Jun 2024 20:19:43 -0700 Subject: [PATCH] add location setting and integrate more sundial code from willb --- .gitignore | 2 + src/CMakeLists.txt | 1 + .../datetime/DateTimeController.cpp | 2 +- src/components/settings/Settings.h | 23 ++ src/displayapp/DisplayApp.cpp | 4 + src/displayapp/apps/Apps.h.in | 1 + src/displayapp/screens/WatchFaceSundial.cpp | 285 ++++++++++++------ src/displayapp/screens/WatchFaceSundial.h | 96 +++--- .../screens/settings/SettingLocation.cpp | 69 +++++ .../screens/settings/SettingLocation.h | 31 ++ src/displayapp/screens/settings/Settings.h | 1 + src/displayapp/widgets/Counter.h | 11 + 12 files changed, 394 insertions(+), 132 deletions(-) create mode 100644 src/displayapp/screens/settings/SettingLocation.cpp create mode 100644 src/displayapp/screens/settings/SettingLocation.h diff --git a/.gitignore b/.gitignore index 81e49ae0..b61095df 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ src/arm-none-eabi # clangd .cache/ + +nRF5_SDK/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5922bca7..3bdd6549 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -416,6 +416,7 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingChimes.cpp displayapp/screens/settings/SettingShakeThreshold.cpp displayapp/screens/settings/SettingBluetooth.cpp + displayapp/screens/settings/SettingLocation.cpp ## Watch faces displayapp/screens/WatchFaceDigital.cpp diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index f0ccb5e5..5335a398 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -129,7 +129,7 @@ std::string DateTime::FormattedTime() { auto hour = Hours(); auto minute = Minutes(); // Return time as a string in 12- or 24-hour format - char buff[9]; + char buff[11]; if (settingsController.GetClockType() == ClockType::H12) { uint8_t hour12; const char* amPmStr; diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index e3be5256..f76be9ff 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,8 @@ namespace Pinetime { uint16_t shakeWakeThreshold = 150; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; + + Location location = {(int16_t)-123,(int16_t)44,(int8_t)-8}; }; SettingsData settings; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 3fd34b3a..8b8378ab 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -49,6 +49,7 @@ #include "displayapp/screens/settings/SettingChimes.h" #include "displayapp/screens/settings/SettingShakeThreshold.h" #include "displayapp/screens/settings/SettingBluetooth.h" +#include "displayapp/screens/settings/SettingLocation.h" #include "libs/lv_conf.h" #include "UserApps.h" @@ -515,6 +516,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 6201da6b..a1421af8 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -39,6 +39,7 @@ namespace Pinetime { SettingWakeUp, SettingSteps, SettingSetDateTime, + SettingLocation, SettingChimes, SettingShakeThreshold, SettingBluetooth, diff --git a/src/displayapp/screens/WatchFaceSundial.cpp b/src/displayapp/screens/WatchFaceSundial.cpp index b99204b0..1999cc78 100644 --- a/src/displayapp/screens/WatchFaceSundial.cpp +++ b/src/displayapp/screens/WatchFaceSundial.cpp @@ -6,6 +6,7 @@ #include "displayapp/screens/NotificationIcon.h" #include "displayapp/screens/Symbols.h" #include "displayapp/screens/WeatherSymbols.h" +#include "displayapp/InfiniTimeTheme.h" #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" #include "components/ble/NotificationManager.h" @@ -17,95 +18,153 @@ 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; +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); + // 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 Cosine(int16_t angle) { + return _lv_trigo_sin(angle + 90); + } -// int16_t Sine(int16_t angle) { -// return _lv_trigo_sin(angle); -// } + 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 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); + } -// 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)}; + } -// 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) + Controllers::Settings& settingsController) : currentDateTime {{}}, dateTimeController {dateTimeController}, notificationManager {notificationManager}, - settingsController {settingsController}, - heartRateController {heartRateController}, - motionController {motionController}, - weatherService {weatherService}, - statusIcons(batteryController, bleController) { + settingsController {settingsController} +{ + // minor_scales = lv_linemeter_create(lv_scr_act(), nullptr); + // lv_linemeter_set_scale(minor_scales, 300, 51); + // lv_linemeter_set_angle_offset(minor_scales, 180); + // lv_obj_set_size(minor_scales, 240, 240); + // lv_obj_align(minor_scales, nullptr, LV_ALIGN_CENTER, 0, 0); + // lv_obj_set_style_local_bg_opa(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + // lv_obj_set_style_local_scale_width(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); + // lv_obj_set_style_local_scale_end_line_width(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 1); + // lv_obj_set_style_local_scale_end_color(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); - statusIcons.Create(); + // major_scales = lv_linemeter_create(lv_scr_act(), nullptr); + // lv_linemeter_set_scale(major_scales, 300, 11); + // lv_linemeter_set_angle_offset(major_scales, 180); + // lv_obj_set_size(major_scales, 240, 240); + // lv_obj_align(major_scales, nullptr, LV_ALIGN_CENTER, 0, 0); + // lv_obj_set_style_local_bg_opa(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + // lv_obj_set_style_local_scale_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 6); + // lv_obj_set_style_local_scale_end_line_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); + // lv_obj_set_style_local_scale_end_color(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - 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); + // large_scales = lv_linemeter_create(lv_scr_act(), nullptr); + // lv_linemeter_set_scale(large_scales, 180, 3); + // lv_linemeter_set_angle_offset(large_scales, 180); + // lv_obj_set_size(large_scales, 240, 240); + // lv_obj_align(large_scales, nullptr, LV_ALIGN_CENTER, 0, 0); + // lv_obj_set_style_local_bg_opa(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + // lv_obj_set_style_local_scale_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 20); + // lv_obj_set_style_local_scale_end_line_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); + // lv_obj_set_style_local_scale_end_color(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); - 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); + // twelve = lv_label_create(lv_scr_act(), nullptr); + // lv_label_set_align(twelve, LV_LABEL_ALIGN_CENTER); + // lv_label_set_text_static(twelve, "12"); + // lv_obj_set_pos(twelve, 110, 10); + // lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); - 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)); + one = lv_label_create(lv_scr_act(), NULL); + lv_label_set_align(one, LV_LABEL_ALIGN_LEFT); + lv_label_set_text(one, "I"); + lv_obj_align(one, NULL, LV_ALIGN_IN_TOP_LEFT, 20, SunDialVerticalOffset-20); + lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - 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); + 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_LIME); + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); + lv_obj_align(notificationIcon, nullptr, 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, DARK_ORANGE); + 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, 50, 0); + + minute_body = lv_line_create(lv_scr_act(), nullptr); + minute_body_trace = lv_line_create(lv_scr_act(), nullptr); + hour_body = lv_line_create(lv_scr_act(), nullptr); + hour_body_trace = lv_line_create(lv_scr_act(), nullptr); + second_body = lv_line_create(lv_scr_act(), nullptr); + + 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); + + 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); + UpdateClock(); Refresh(); } WatchFaceSundial::~WatchFaceSundial() { 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()); } @@ -113,37 +172,85 @@ void WatchFaceSundial::Refresh() { currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); if (currentDateTime.IsUpdated()) { currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + UpdateClock(); 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); + char const* MonthsString[] = {"--", "IANUARIUS","FEBRUARIUS","MARTIUS","APRILIS","MARTIUSIUNIUS","QUINTILIS","SEXTILIS","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"}; + char const* DaysString[] = {"--", "LUNAE", "MARTIS", "MERCURII", "IOVIS", "VENERIS", "SATURNI", "SOLIS"}; + char const* RomanNumeralsString[] = {"--", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"}; + lv_label_set_text_fmt(label_date_day, "%s\n%s %s", + DaysString[static_cast(dateTimeController.DayOfWeek())], + RomanNumeralsString[static_cast(dateTimeController.Day())], + MonthsString[static_cast(dateTimeController.Month())]); + lv_obj_align(label_date_day, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, -20); } } + +} - 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'; +void WatchFaceSundial::UpdateClock() { + uint8_t hour = dateTimeController.Hours(); + uint8_t minute = dateTimeController.Minutes(); + + 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; + lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + } 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_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); + + if(minutesBeforeSunset > minutesDaytime) { // before sunrise + hourAngle = 180.0 * (minutesBeforeSunset - minutesDaytime) / minutesNighttime + 90; + } else { // after sunset + hourAngle = 180 + 180.0 * minutesBeforeSunset / minutesNighttime + 90; } - 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); + /*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; + + printf("<: %d %d @%d/%d+/-%d\n", hour, minute, location.latitude, location.longitude, location.tzOffset); + printf("@: %d %d:%d %d:%d\n", + minutesBeforeSunset, + minutesSunrise/60, minutesSunrise % 60, + minutesSunset/60, minutesSunset % 60); + + hour_point_trace[0] = CoordinateRelocateSundial(HourLength*.75, hourAngle); + hour_point_trace[1] = CoordinateRelocateSundial(HourLength, hourAngle); + + hour_point[0] = CoordinateRelocateSundial(0, hourAngle); + hour_point[1] = CoordinateRelocateSundial(HourLength*.75, hourAngle); + + lv_line_set_points(hour_body, hour_point, 2); + lv_line_set_points(hour_body_trace, hour_point_trace, 2); } } diff --git a/src/displayapp/screens/WatchFaceSundial.h b/src/displayapp/screens/WatchFaceSundial.h index 9c02fdfe..b5721585 100644 --- a/src/displayapp/screens/WatchFaceSundial.h +++ b/src/displayapp/screens/WatchFaceSundial.h @@ -6,11 +6,12 @@ #include #include "displayapp/screens/Screen.h" #include "components/datetime/DateTimeController.h" -#include "components/ble/SimpleWeatherService.h" +#include "components/battery/BatteryController.h" #include "components/ble/BleController.h" -#include "displayapp/widgets/StatusIcons.h" +#include "components/ble/NotificationManager.h" +#include "displayapp/screens/BatteryIcon.h" #include "utility/DirtyValue.h" -#include "displayapp/apps/Apps.h" +#include "sunset/src/sunset.h" namespace Pinetime { namespace Controllers { @@ -18,8 +19,6 @@ namespace Pinetime { class Battery; class Ble; class NotificationManager; - class HeartRateController; - class MotionController; } namespace Applications { @@ -28,50 +27,68 @@ namespace Pinetime { 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); + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController); + ~WatchFaceSundial() override; void Refresh() override; private: - uint8_t displayedHour = -1; - uint8_t displayedMinute = -1; + uint8_t sHour, sMinute, sSecond; - Utility::DirtyValue> currentDateTime {}; - Utility::DirtyValue stepCount {}; - Utility::DirtyValue heartbeat {}; - Utility::DirtyValue heartbeatRunning {}; - Utility::DirtyValue notificationState {}; - Utility::DirtyValue> currentWeather {}; + Utility::DirtyValue batteryPercentRemaining {0}; + Utility::DirtyValue isCharging {}; + Utility::DirtyValue bleState {}; + Utility::DirtyValue> currentDateTime; + Utility::DirtyValue notificationState {false}; + using days = std::chrono::duration>; // TODO: days is standard in c++20 + Utility::DirtyValue> currentDate; - Utility::DirtyValue> currentDate; + lv_obj_t* major_scales; + lv_obj_t* one; + lv_obj_t* twelve; - 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* 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_point_trace[2]; + lv_point_t minute_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_line_style_trace; + lv_style_t minute_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* notificationIcon; - lv_obj_t* weatherIcon; - lv_obj_t* temperature; + lv_obj_t* bleIcon; - Controllers::DateTime& dateTimeController; + Controllers::Settings::Location location; + SunSet sun; + int16_t minutesSunrise; + int16_t minutesSunset; + int16_t minutesDaytime; + int16_t minutesNighttime; + int16_t minutesBeforeSunset; + + const Controllers::DateTime& dateTimeController; Controllers::NotificationManager& notificationManager; Controllers::Settings& settingsController; - Controllers::HeartRateController& heartRateController; - Controllers::MotionController& motionController; - Controllers::SimpleWeatherService& weatherService; + + void drawWatchFaceModeNight(); + void UpdateClock(); + void SetBatteryIcon(); lv_task_t* taskRefresh; - Widgets::StatusIcons statusIcons; }; } @@ -82,13 +99,8 @@ namespace Pinetime { 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); + controllers.notificationManager, + controllers.settingsController); }; static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { diff --git a/src/displayapp/screens/settings/SettingLocation.cpp b/src/displayapp/screens/settings/SettingLocation.cpp new file mode 100644 index 00000000..4de374b5 --- /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); +} 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.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;