diff --git a/.gitignore b/.gitignore index 81e49ae0..14872a71 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ src/arm-none-eabi # clangd .cache/ + +node_modules/ \ No newline at end of file diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 602de3a5..b48104de 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -45,6 +45,10 @@ namespace Pinetime { PTSWeather weatherEnable = PTSWeather::Off; }; + struct CasioStyleG7710 { + PTSWeather weatherEnable = PTSWeather::Off; + }; + struct WatchFaceInfineat { bool showSideCover = true; int colorIndex = 0; @@ -154,6 +158,16 @@ namespace Pinetime { return settings.PTS.weatherEnable; }; + void SetCasioWeather(PTSWeather weatherEnable) { + if (weatherEnable != settings.casio.weatherEnable) + settingsChanged = true; + settings.casio.weatherEnable = weatherEnable; + } + + PTSWeather GetCasioWeather() const { + return settings.casio.weatherEnable; + } + void SetAppMenu(uint8_t menu) { appMenu = menu; }; @@ -319,6 +333,8 @@ namespace Pinetime { PineTimeStyle PTS; + CasioStyleG7710 casio; + WatchFaceInfineat watchFaceInfineat; std::bitset<5> wakeUpMode {0}; diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 2104a267..bf4c1e97 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -51,7 +51,7 @@ namespace Pinetime { PineTimeStyle, Terminal, Infineat, - CasioStyleG7710, + CasioStyleG7710 }; template diff --git a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp index c695f852..0bb82fd8 100644 --- a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp +++ b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp @@ -6,14 +6,24 @@ #include "displayapp/screens/BleIcon.h" #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/settings/Settings.h" +#include "components/ble/SimpleWeatherService.h" + using namespace Pinetime::Applications::Screens; +namespace { + void event_handler(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + screen->UpdateSelected(obj, event); + } +} + WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTimeController, const Controllers::Battery& batteryController, const Controllers::Ble& bleController, @@ -21,7 +31,8 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi Controllers::Settings& settingsController, Controllers::HeartRateController& heartRateController, Controllers::MotionController& motionController, - Controllers::FS& filesystem) + Controllers::FS& filesystem, + Controllers::SimpleWeatherService& weatherService) : currentDateTime {{}}, batteryIcon(false), dateTimeController {dateTimeController}, @@ -30,7 +41,8 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi notificatioManager {notificatioManager}, settingsController {settingsController}, heartRateController {heartRateController}, - motionController {motionController} { + motionController {motionController}, + weatherService {weatherService} { lfs_file f = {}; if (filesystem.FileOpen(&f, "/fonts/lv_font_dots_40.bin", LFS_O_RDONLY) >= 0) { @@ -89,6 +101,34 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi lv_obj_set_style_local_text_color(label_day_of_year, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text); lv_obj_set_style_local_text_font(label_day_of_year, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_segment40); lv_label_set_text_static(label_day_of_year, "181-184"); + if (settingsController.GetCasioWeather() == Pinetime::Controllers::Settings::PTSWeather::On) { + lv_obj_set_hidden(label_day_of_year, true); + } else { + lv_obj_set_hidden(label_day_of_year, false); + } + + weatherIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text); + lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons); + lv_label_set_text_static(weatherIcon, ""); + lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 110, 30); + lv_obj_set_auto_realign(weatherIcon, true); + if (settingsController.GetCasioWeather() == Pinetime::Controllers::Settings::PTSWeather::On) { + lv_obj_set_hidden(weatherIcon, false); + } else { + lv_obj_set_hidden(weatherIcon, true); + } + + label_temperature = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(label_temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text); + lv_obj_set_style_local_text_font(label_temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_segment40); + lv_label_set_text(label_temperature, ""); + lv_obj_align(label_temperature, nullptr, LV_ALIGN_IN_TOP_RIGHT, -5, 30); + if (settingsController.GetCasioWeather() == Pinetime::Controllers::Settings::PTSWeather::On) { + lv_obj_set_hidden(label_temperature, false); + } else { + lv_obj_set_hidden(label_temperature, true); + } lv_style_init(&style_line); lv_style_set_line_width(&style_line, LV_STATE_DEFAULT, 2); @@ -116,7 +156,7 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi lv_obj_align(line_day_of_year, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 60); label_date = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 100, 70); + lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -45, 70); lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text); lv_obj_set_style_local_text_font(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_segment40); lv_label_set_text_static(label_date, "6-30"); @@ -168,6 +208,26 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi lv_label_set_text_static(stepIcon, Symbols::shoe); lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); + btnWeather = lv_btn_create(lv_scr_act(), nullptr); + btnWeather->user_data = this; + lv_obj_set_size(btnWeather, 160, 60); + lv_obj_align(btnWeather, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_local_bg_opa(btnWeather, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50); + lv_obj_t* lblWeather = lv_label_create(btnWeather, nullptr); + lv_label_set_text_static(lblWeather, "Weather"); + lv_obj_set_event_cb(btnWeather, event_handler); + lv_obj_set_hidden(btnWeather, true); + + btnClose = lv_btn_create(lv_scr_act(), nullptr); + btnClose->user_data = this; + lv_obj_set_size(btnClose, 60, 60); + lv_obj_align(btnClose, lv_scr_act(), LV_ALIGN_CENTER, 0, -80); + lv_obj_set_style_local_bg_opa(btnClose, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50); + lv_obj_t* lblClose = lv_label_create(btnClose, nullptr); + lv_label_set_text_static(lblClose, "X"); + lv_obj_set_event_cb(btnClose, event_handler); + lv_obj_set_hidden(btnClose, true); + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); Refresh(); } @@ -310,6 +370,41 @@ void WatchFaceCasioStyleG7710::Refresh() { lv_obj_realign(stepValue); lv_obj_realign(stepIcon); } + + if (settingsController.GetCasioWeather() == Pinetime::Controllers::Settings::PTSWeather::On) { + 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(label_temperature, "%d°%c", temp, tempUnit); + lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); + } else { + lv_label_set_text_static(label_temperature, ""); + lv_label_set_text(weatherIcon, ""); + } + + lv_obj_realign(label_temperature); + lv_obj_realign(weatherIcon); + } + } + + if (!lv_obj_get_hidden(btnClose)) { + if ((savedTick > 0) && (lv_tick_get() - savedTick > 3000)) { + CloseMenu(); + savedTick = 0; + } + } } bool WatchFaceCasioStyleG7710::IsAvailable(Pinetime::Controllers::FS& filesystem) { @@ -332,3 +427,55 @@ bool WatchFaceCasioStyleG7710::IsAvailable(Pinetime::Controllers::FS& filesystem filesystem.FileClose(&file); return true; } + +bool WatchFaceCasioStyleG7710::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + if (lv_obj_get_hidden(btnClose) == false) { + savedTick = lv_tick_get(); + } + if ((event == Pinetime::Applications::TouchEvents::LongTap) && lv_obj_get_hidden(btnClose)) { + lv_obj_set_hidden(btnWeather, false); + lv_obj_set_hidden(btnClose, false); + savedTick = lv_tick_get(); + return true; + } + if ((event == Pinetime::Applications::TouchEvents::DoubleTap) && (lv_obj_get_hidden(btnClose) == false)) { + return true; + } + return false; +} + +void WatchFaceCasioStyleG7710::CloseMenu() { + settingsController.SaveSettings(); + lv_obj_set_hidden(btnWeather, true); + lv_obj_set_hidden(btnClose, true); +} + +bool WatchFaceCasioStyleG7710::OnButtonPushed() { + if (!lv_obj_get_hidden(btnClose)) { + CloseMenu(); + return true; + } + + return false; +} + +void WatchFaceCasioStyleG7710::UpdateSelected(lv_obj_t* object, lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + if (object == btnWeather) { + if (lv_obj_get_hidden(weatherIcon)) { + lv_obj_set_hidden(weatherIcon, false); + lv_obj_set_hidden(label_temperature, false); + lv_obj_set_hidden(label_day_of_year, true); + settingsController.SetCasioWeather(Controllers::Settings::PTSWeather::On); + } else { + lv_obj_set_hidden(weatherIcon, true); + lv_obj_set_hidden(label_temperature, true); + lv_obj_set_hidden(label_day_of_year, false); + settingsController.SetCasioWeather(Controllers::Settings::PTSWeather::Off); + } + } + if (object == btnClose) { + CloseMenu(); + } + } +} diff --git a/src/displayapp/screens/WatchFaceCasioStyleG7710.h b/src/displayapp/screens/WatchFaceCasioStyleG7710.h index 0f46a692..1e2e9456 100644 --- a/src/displayapp/screens/WatchFaceCasioStyleG7710.h +++ b/src/displayapp/screens/WatchFaceCasioStyleG7710.h @@ -9,6 +9,7 @@ #include "displayapp/screens/Screen.h" #include "components/datetime/DateTimeController.h" #include "components/ble/BleController.h" +#include "components/ble/SimpleWeatherService.h" #include "utility/DirtyValue.h" #include "displayapp/apps/Apps.h" @@ -34,9 +35,15 @@ namespace Pinetime { Controllers::Settings& settingsController, Controllers::HeartRateController& heartRateController, Controllers::MotionController& motionController, - Controllers::FS& filesystem); + Controllers::FS& filesystem, + Controllers::SimpleWeatherService& weather); ~WatchFaceCasioStyleG7710() override; + bool OnTouchEvent(TouchEvents event) override; + bool OnButtonPushed() override; + + void UpdateSelected(lv_obj_t* object, lv_event_t event); + void Refresh() override; static bool IsAvailable(Pinetime::Controllers::FS& filesystem); @@ -52,6 +59,9 @@ namespace Pinetime { Utility::DirtyValue heartbeatRunning {}; Utility::DirtyValue notificationState {}; Utility::DirtyValue> currentDate; + Utility::DirtyValue> currentWeather {}; + + uint32_t savedTick = 0; lv_point_t line_icons_points[3] {{0, 5}, {117, 5}, {122, 0}}; lv_point_t line_day_of_week_number_points[4] {{0, 0}, {100, 0}, {95, 95}, {0, 95}}; @@ -84,6 +94,10 @@ namespace Pinetime { lv_obj_t* stepValue; lv_obj_t* notificationIcon; lv_obj_t* line_icons; + lv_obj_t* btnWeather; + lv_obj_t* btnClose; + lv_obj_t* weatherIcon; + lv_obj_t* label_temperature; BatteryIcon batteryIcon; @@ -94,11 +108,14 @@ namespace Pinetime { Controllers::Settings& settingsController; Controllers::HeartRateController& heartRateController; Controllers::MotionController& motionController; + Controllers::SimpleWeatherService& weatherService; lv_task_t* taskRefresh; lv_font_t* font_dot40 = nullptr; lv_font_t* font_segment40 = nullptr; lv_font_t* font_segment115 = nullptr; + + void CloseMenu(); }; } @@ -115,7 +132,8 @@ namespace Pinetime { controllers.settingsController, controllers.heartRateController, controllers.motionController, - controllers.filesystem); + controllers.filesystem, + *controllers.weatherController); }; static bool IsAvailable(Pinetime::Controllers::FS& filesystem) { diff --git a/src/resources/fonts.json b/src/resources/fonts.json index c4a63349..6fc3d43f 100644 --- a/src/resources/fonts.json +++ b/src/resources/fonts.json @@ -39,7 +39,7 @@ "sources": [ { "file": "fonts/7segment.woff", - "symbols": "0123456789: -" + "symbols": "0123456789: -°CF" } ], "bpp": 1,