diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index db93bb3fb7..9df636072d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,12 +3,12 @@ name: CI # Run this workflow whenever the build may be affected on: push: - branches: [ main ] + branches: [ main, ghoelian ] paths-ignore: - 'doc/**' - '**.md' pull_request: - branches: [ main ] + branches: [ main, ghoelian ] paths-ignore: - 'doc/**' - '**.md' diff --git a/.gitignore b/.gitignore index 81e49ae083..14872a71c1 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/build.sh b/build.sh new file mode 100755 index 0000000000..09fd0b9f83 --- /dev/null +++ b/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +mkdir -p build +cd build + +echo "Configuring build..." +cmake -DARM_NONE_EABI_TOOLCHAIN_PATH="/workspaces/infinitime/gcc-arm" -DNRF5_SDK_PATH="/workspaces/infinitime/nRF5_SDK" -DCMAKE_BUILD_TYPE="Release" -DBUILD_DFU=1 -DBUILD_RESOURCES=1 -DTARGET_DEVICE="PINETIME" .. +echo "Finished configuring build" + +echo "Building..." +make -j4 pinetime-mcuboot-app +echo "Finished building" diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..89da6e7b39 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,119 @@ +{ + "name": "InfiniTime", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "lv_font_conv": "^1.5.3" + } + }, + "node_modules/lv_font_conv": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/lv_font_conv/-/lv_font_conv-1.5.3.tgz", + "integrity": "sha512-0xJQThBOw2iptFccSXrKDIUTQAwr/2zhKjCI1lATIRgZo8uvYRTmenKafW9yTw6G0y5AyW00tqGpUtYuTuBIbQ==", + "bundleDependencies": [ + "argparse", + "bit-buffer", + "debug", + "make-error", + "mkdirp", + "opentype.js", + "pngjs" + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.0", + "bit-buffer": "^0.2.5", + "debug": "^4.3.3", + "make-error": "^1.3.5", + "mkdirp": "^1.0.4", + "opentype.js": "^1.3.4", + "pngjs": "^6.0.0" + }, + "bin": { + "lv_font_conv": "lv_font_conv.js" + } + }, + "node_modules/lv_font_conv/node_modules/argparse": { + "version": "2.0.1", + "inBundle": true, + "license": "Python-2.0" + }, + "node_modules/lv_font_conv/node_modules/bit-buffer": { + "version": "0.2.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/lv_font_conv/node_modules/debug": { + "version": "4.3.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/lv_font_conv/node_modules/make-error": { + "version": "1.3.6", + "inBundle": true, + "license": "ISC" + }, + "node_modules/lv_font_conv/node_modules/mkdirp": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lv_font_conv/node_modules/ms": { + "version": "2.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/lv_font_conv/node_modules/opentype.js": { + "version": "1.3.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "string.prototype.codepointat": "^0.2.1", + "tiny-inflate": "^1.0.3" + }, + "bin": { + "ot": "bin/ot" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/lv_font_conv/node_modules/pngjs": { + "version": "6.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/lv_font_conv/node_modules/string.prototype.codepointat": { + "version": "0.2.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/lv_font_conv/node_modules/tiny-inflate": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000..f0e20704e8 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "lv_font_conv": "^1.5.3" + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e2b69b8b02..63318e7665 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -418,6 +418,8 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingChimes.cpp displayapp/screens/settings/SettingShakeThreshold.cpp displayapp/screens/settings/SettingBluetooth.cpp + displayapp/screens/settings/SettingNotifVibration.cpp + displayapp/screens/settings/SettingChimeVibration.cpp ## Watch faces displayapp/screens/WatchFaceAnalog.cpp diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 602de3a585..aec492b70d 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -34,6 +34,7 @@ namespace Pinetime { Orange, Pink }; + enum class VibrationStrength : uint8_t { Weak = 15, Normal = 35, Strong = 75 }; enum class PTSGaugeStyle : uint8_t { Full, Half, Numeric }; enum class PTSWeather : uint8_t { On, Off }; @@ -45,6 +46,13 @@ namespace Pinetime { PTSWeather weatherEnable = PTSWeather::Off; }; + enum class CasioWeatherSegment : uint8_t { WeekNumber, DayCounter, DayOfWeek }; + + struct CasioStyleG7710 { + PTSWeather weatherEnable = PTSWeather::Off; + CasioWeatherSegment weatherSegment = CasioWeatherSegment::DayCounter; + }; + struct WatchFaceInfineat { bool showSideCover = true; int colorIndex = 0; @@ -154,6 +162,27 @@ 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 SetCasioWeatherSegment(CasioWeatherSegment weatherSegment) { + if (weatherSegment != settings.casio.weatherSegment) + settingsChanged = true; + + settings.casio.weatherSegment = weatherSegment; + } + + CasioWeatherSegment GetCasioWeatherSegment() const { + return settings.casio.weatherSegment; + } + void SetAppMenu(uint8_t menu) { appMenu = menu; }; @@ -298,6 +327,28 @@ namespace Pinetime { return bleRadioEnabled; }; + void SetNotifVibration(VibrationStrength strength) { + if (strength != settings.notifVibration) { + settingsChanged = true; + } + settings.notifVibration = strength; + }; + + VibrationStrength GetNotifVibration() const { + return settings.notifVibration; + } + + void SetChimeVibration(VibrationStrength strength) { + if (strength != settings.chimeVibration) { + settingsChanged = true; + } + settings.chimeVibration = strength; + }; + + VibrationStrength GetChimeVibration() const { + return settings.chimeVibration; + } + private: Pinetime::Controllers::FS& fs; @@ -319,12 +370,17 @@ namespace Pinetime { PineTimeStyle PTS; + CasioStyleG7710 casio; + WatchFaceInfineat watchFaceInfineat; std::bitset<5> wakeUpMode {0}; uint16_t shakeWakeThreshold = 150; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; + + VibrationStrength notifVibration = VibrationStrength::Normal; + VibrationStrength chimeVibration = VibrationStrength::Normal; }; SettingsData settings; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 6671ac9e51..59bb7c2460 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -49,6 +49,8 @@ #include "displayapp/screens/settings/SettingChimes.h" #include "displayapp/screens/settings/SettingShakeThreshold.h" #include "displayapp/screens/settings/SettingBluetooth.h" +#include "displayapp/screens/settings/SettingNotifVibration.h" +#include "displayapp/screens/settings/SettingChimeVibration.h" #include "libs/lv_conf.h" #include "UserApps.h" @@ -372,7 +374,7 @@ void DisplayApp::Refresh() { } else { LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); } - motorController.RunForDuration(35); + motorController.RunForDuration(static_cast(settingsController.GetNotifVibration())); break; case Messages::AlarmTriggered: if (currentApp == Apps::Alarm) { @@ -384,7 +386,7 @@ void DisplayApp::Refresh() { break; case Messages::ShowPairingKey: LoadNewScreen(Apps::PassKey, DisplayApp::FullRefreshDirections::Up); - motorController.RunForDuration(35); + motorController.RunForDuration(static_cast(settingsController.GetNotifVibration())); break; case Messages::TouchEvent: { if (state != States::Running) { @@ -473,7 +475,7 @@ void DisplayApp::Refresh() { break; case Messages::Chime: LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None); - motorController.RunForDuration(35); + motorController.RunForDuration(static_cast(settingsController.GetChimeVibration())); break; case Messages::OnChargingEvent: motorController.RunForDuration(15); @@ -563,6 +565,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio notificationManager, systemTask->nimble().alertService(), motorController, + settingsController, *systemTask, Screens::Notifications::Modes::Normal); break; @@ -571,6 +574,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio notificationManager, systemTask->nimble().alertService(), motorController, + settingsController, *systemTask, Screens::Notifications::Modes::Preview); break; @@ -623,6 +627,12 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio case Apps::SettingBluetooth: currentScreen = std::make_unique(this, settingsController); break; + case Apps::SettingNotifVibration: + currentScreen = std::make_unique(settingsController, motorController); + break; + case Apps::SettingChimeVibration: + currentScreen = std::make_unique(settingsController, motorController); + break; case Apps::BatteryInfo: currentScreen = std::make_unique(batteryController); break; diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 2104a267c0..318bb82d54 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -42,6 +42,8 @@ namespace Pinetime { SettingChimes, SettingShakeThreshold, SettingBluetooth, + SettingNotifVibration, + SettingChimeVibration, Error }; @@ -50,8 +52,9 @@ namespace Pinetime { Analog, PineTimeStyle, Terminal, + Json, Infineat, - CasioStyleG7710, + CasioStyleG7710 }; template diff --git a/src/displayapp/fonts/CMakeLists.txt b/src/displayapp/fonts/CMakeLists.txt index 562f0801ad..07bf817109 100644 --- a/src/displayapp/fonts/CMakeLists.txt +++ b/src/displayapp/fonts/CMakeLists.txt @@ -1,5 +1,5 @@ set(FONTS jetbrains_mono_42 jetbrains_mono_76 jetbrains_mono_bold_20 - jetbrains_mono_extrabold_compressed lv_font_sys_48 + jetbrains_mono_extrabold_compressed jetbrains_mono_16 lv_font_sys_48 open_sans_light fontawesome_weathericons) find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin") diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index 41c383c0d4..6f5aaf34cb 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -14,6 +14,16 @@ "size": 20, "patches": ["jetbrains_mono_bold_20.c_zero.patch", "jetbrains_mono_bold_20.c_M.patch"] }, + "jetbrains_mono_16": { + "sources": [ + { + "file": "JetBrainsMono-Regular.ttf", + "range": "0x20-0x7e, 0x410-0x44f, 0xB0" + } + ], + "bpp": 1, + "size": 16 + }, "jetbrains_mono_42": { "sources": [ { diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 45f72f2e20..0d455f1e6e 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -14,6 +14,7 @@ Notifications::Notifications(DisplayApp* app, Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::AlertNotificationService& alertNotificationService, Pinetime::Controllers::MotorController& motorController, + Pinetime::Controllers::Settings& settingsController, System::SystemTask& systemTask, Modes mode) : app {app}, @@ -44,7 +45,7 @@ Notifications::Notifications(DisplayApp* app, if (notification.category == Controllers::NotificationManager::Categories::IncomingCall) { motorController.StartRinging(); } else { - motorController.RunForDuration(35); + motorController.RunForDuration(static_cast(settingsController.GetNotifVibration())); } timeoutLine = lv_line_create(lv_scr_act(), nullptr); diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h index 8488dc5bb2..c122d92305 100644 --- a/src/displayapp/screens/Notifications.h +++ b/src/displayapp/screens/Notifications.h @@ -25,6 +25,7 @@ namespace Pinetime { Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::AlertNotificationService& alertNotificationService, Pinetime::Controllers::MotorController& motorController, + Pinetime::Controllers::Settings& settingsController, System::SystemTask& systemTask, Modes mode); ~Notifications() override; diff --git a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp index c695f852fe..d08df86404 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) { @@ -90,6 +102,34 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi 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"); + 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_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_label_set_text(label_temperature, ""); + + label_temperature_segment = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(label_temperature_segment, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text); + lv_obj_set_style_local_text_font(label_temperature_segment, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_segment40); + lv_label_set_text(label_temperature_segment, ""); + + lv_obj_set_hidden(label_temperature_segment, true); + lv_obj_set_hidden(label_temperature, true); + + if (settingsController.GetCasioWeather() == Pinetime::Controllers::Settings::PTSWeather::On) { + UpdateWeatherPosition(); + } + lv_style_init(&style_line); lv_style_set_line_width(&style_line, LV_STATE_DEFAULT, 2); lv_style_set_line_color(&style_line, LV_STATE_DEFAULT, color_text); @@ -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,36 @@ 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); + + btnSegment = lv_btn_create(lv_scr_act(), nullptr); + btnSegment->user_data = this; + lv_obj_set_size(btnSegment, 160, 60); + lv_obj_align(btnSegment, lv_scr_act(), LV_ALIGN_CENTER, 0, 80); + lv_obj_set_style_local_bg_opa(btnSegment, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50); + lv_obj_t* lblSegment = lv_label_create(btnSegment, nullptr); + lv_label_set_text_static(lblSegment, "Segment"); + lv_obj_set_event_cb(btnSegment, event_handler); + lv_obj_set_hidden(btnSegment, 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 +380,91 @@ void WatchFaceCasioStyleG7710::Refresh() { lv_obj_realign(stepValue); lv_obj_realign(stepIcon); } + + if (settingsController.GetCasioWeather() == Pinetime::Controllers::Settings::PTSWeather::On) { + DrawWeather(); + } + + if (!lv_obj_get_hidden(btnClose)) { + if ((savedTick > 0) && (lv_tick_get() - savedTick > 3000)) { + CloseMenu(); + savedTick = 0; + } + } +} + +void WatchFaceCasioStyleG7710::UpdateWeatherPosition() { + lv_obj_set_hidden(label_day_of_year, false); + lv_obj_set_hidden(label_week_number, false); + lv_obj_set_hidden(label_day_of_week, false); + + lv_obj_set_hidden(weatherIcon, true); + lv_obj_set_hidden(label_temperature_segment, true); + lv_obj_set_hidden(label_temperature, true); + + if (settingsController.GetCasioWeather() == Controllers::Settings::PTSWeather::Off) { + return; + } + + lv_obj_set_hidden(weatherIcon, false); + + switch (settingsController.GetCasioWeatherSegment()) { + case Controllers::Settings::CasioWeatherSegment::DayCounter: + lv_obj_set_hidden(label_day_of_year, true); + + lv_obj_set_hidden(label_temperature_segment, false); + lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 110, 30); + lv_obj_align(label_temperature_segment, nullptr, LV_ALIGN_IN_TOP_RIGHT, -5, 30); + break; + case Controllers::Settings::CasioWeatherSegment::WeekNumber: + lv_obj_set_hidden(label_week_number, true); + + lv_obj_set_hidden(label_temperature, false); + lv_obj_align(weatherIcon, label_day_of_week, LV_ALIGN_CENTER, 0, -50); + lv_label_set_align(label_temperature, LV_LABEL_ALIGN_CENTER); + lv_obj_align(label_temperature, label_day_of_week, LV_ALIGN_CENTER, 0, -27); + break; + case Controllers::Settings::CasioWeatherSegment::DayOfWeek: + lv_obj_set_hidden(label_day_of_week, true); + + lv_obj_set_hidden(label_temperature, false); + lv_obj_align(weatherIcon, label_day_of_week, LV_ALIGN_CENTER, 0, -12); + lv_label_set_align(label_temperature, LV_LABEL_ALIGN_CENTER); + lv_obj_align(label_temperature, label_day_of_week, LV_ALIGN_CENTER, 0, 11); + break; + } + + DrawWeather(); +} + +void WatchFaceCasioStyleG7710::DrawWeather() { + currentWeather = weatherService.Current(); + + if (currentWeather.IsUpdated()) { + auto optCurrentWeather = currentWeather.Get(); + + if (optCurrentWeather) { + int16_t temp = optCurrentWeather->temperature.Celsius(); + char tempUnit = 'C'; + + if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + temp = optCurrentWeather->temperature.Fahrenheit(); + tempUnit = 'F'; + } + + lv_label_set_text_fmt(label_temperature, "%d°%c", temp, tempUnit); + lv_label_set_text_fmt(label_temperature_segment, "%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_static(label_temperature_segment, ""); + lv_label_set_text(weatherIcon, ""); + } + + lv_obj_realign(label_temperature); + lv_obj_realign(label_temperature_segment); + lv_obj_realign(weatherIcon); + } } bool WatchFaceCasioStyleG7710::IsAvailable(Pinetime::Controllers::FS& filesystem) { @@ -332,3 +487,80 @@ 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(btnSegment, 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(btnSegment, true); + + lv_obj_set_hidden(btnClose, true); +} + +bool WatchFaceCasioStyleG7710::OnButtonPushed() { + if (!lv_obj_get_hidden(btnClose)) { + CloseMenu(); + return true; + } + + return false; +} + +void WatchFaceCasioStyleG7710::HandleWeatherButton() { + if (lv_obj_get_hidden(weatherIcon)) { + settingsController.SetCasioWeather(Controllers::Settings::PTSWeather::On); + } else { + settingsController.SetCasioWeather(Controllers::Settings::PTSWeather::Off); + } + + UpdateWeatherPosition(); +} + +void WatchFaceCasioStyleG7710::HandleSegmentButton() { + switch (settingsController.GetCasioWeatherSegment()) { + case Controllers::Settings::CasioWeatherSegment::DayCounter: + settingsController.SetCasioWeatherSegment(Controllers::Settings::CasioWeatherSegment::WeekNumber); + break; + case Controllers::Settings::CasioWeatherSegment::WeekNumber: + settingsController.SetCasioWeatherSegment(Controllers::Settings::CasioWeatherSegment::DayOfWeek); + break; + case Controllers::Settings::CasioWeatherSegment::DayOfWeek: + settingsController.SetCasioWeatherSegment(Controllers::Settings::CasioWeatherSegment::DayCounter); + break; + } + + UpdateWeatherPosition(); +} + +void WatchFaceCasioStyleG7710::UpdateSelected(lv_obj_t* object, lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + if (object == btnWeather) { + HandleWeatherButton(); + } + + if (object == btnSegment) { + HandleSegmentButton(); + } + + if (object == btnClose) { + CloseMenu(); + } + } +} diff --git a/src/displayapp/screens/WatchFaceCasioStyleG7710.h b/src/displayapp/screens/WatchFaceCasioStyleG7710.h index 0f46a69251..a71777ab0f 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,11 +35,20 @@ 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; + void UpdateWeatherPosition(); + void DrawWeather(); + static bool IsAvailable(Pinetime::Controllers::FS& filesystem); private: @@ -52,6 +62,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 +97,12 @@ namespace Pinetime { lv_obj_t* stepValue; lv_obj_t* notificationIcon; lv_obj_t* line_icons; + lv_obj_t* btnWeather; + lv_obj_t* btnSegment; + lv_obj_t* btnClose; + lv_obj_t* weatherIcon; + lv_obj_t* label_temperature; + lv_obj_t* label_temperature_segment; BatteryIcon batteryIcon; @@ -94,11 +113,17 @@ 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; + lv_font_t* font_teko_light = nullptr; + + void CloseMenu(); + void HandleWeatherButton(); + void HandleSegmentButton(); }; } @@ -115,7 +140,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/displayapp/screens/settings/SettingChimeVibration.cpp b/src/displayapp/screens/settings/SettingChimeVibration.cpp new file mode 100644 index 0000000000..0b8108ee01 --- /dev/null +++ b/src/displayapp/screens/settings/SettingChimeVibration.cpp @@ -0,0 +1,68 @@ +#include "displayapp/screens/settings/SettingChimeVibration.h" + +#include + +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Styles.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + struct Option { + Pinetime::Controllers::Settings::VibrationStrength vibrationStrength; + const char* name; + }; + + constexpr std::array options = {{ + {Pinetime::Controllers::Settings::VibrationStrength::Weak, "Weak"}, + {Pinetime::Controllers::Settings::VibrationStrength::Normal, "Normal"}, + {Pinetime::Controllers::Settings::VibrationStrength::Strong, "Strong"}, + }}; + + std::array CreateOptionArray() { + std::array optionArray; + for (size_t i = 0; i < CheckboxList::MaxItems; i++) { + if (i >= options.size()) { + optionArray[i].name = ""; + optionArray[i].enabled = false; + } else { + optionArray[i].name = options[i].name; + optionArray[i].enabled = true; + } + } + return optionArray; + } + + uint32_t GetDefaultOption(Pinetime::Controllers::Settings::VibrationStrength currentOption) { + for (size_t i = 0; i < options.size(); i++) { + if (options[i].vibrationStrength == currentOption) { + return i; + } + } + return 0; + } +} + +SettingChimeVibration::SettingChimeVibration(Pinetime::Controllers::Settings& settingsController, + Pinetime::Controllers::MotorController& motorController) + : checkboxList( + 0, + 1, + "Chime strength", + Symbols::tachometer, + GetDefaultOption(settingsController.GetChimeVibration()), + [&settings = settingsController, &motor = motorController](uint32_t index) { + // Preview current setting + motor.RunForDuration(static_cast(options[index].vibrationStrength)); + + settings.SetChimeVibration(options[index].vibrationStrength); + settings.SaveSettings(); + }, + CreateOptionArray()) { +} + +SettingChimeVibration::~SettingChimeVibration() { + lv_obj_clean(lv_scr_act()); +} \ No newline at end of file diff --git a/src/displayapp/screens/settings/SettingChimeVibration.h b/src/displayapp/screens/settings/SettingChimeVibration.h new file mode 100644 index 0000000000..3817622348 --- /dev/null +++ b/src/displayapp/screens/settings/SettingChimeVibration.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +#include "components/settings/Settings.h" +#include "components/motor/MotorController.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/CheckboxList.h" + +namespace Pinetime { + + namespace Applications { + namespace Screens { + + class SettingChimeVibration : public Screen { + public: + explicit SettingChimeVibration(Pinetime::Controllers::Settings& settingsController, + Pinetime::Controllers::MotorController& motorController); + ~SettingChimeVibration() override; + + private: + CheckboxList checkboxList; + }; + } + } +} \ No newline at end of file diff --git a/src/displayapp/screens/settings/SettingNotifVibration.cpp b/src/displayapp/screens/settings/SettingNotifVibration.cpp new file mode 100644 index 0000000000..86aa16c33e --- /dev/null +++ b/src/displayapp/screens/settings/SettingNotifVibration.cpp @@ -0,0 +1,67 @@ +#include "displayapp/screens/settings/SettingNotifVibration.h" + +#include + +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Styles.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + struct Option { + Pinetime::Controllers::Settings::VibrationStrength vibrationStrength; + const char* name; + }; + + constexpr std::array options = {{ + {Pinetime::Controllers::Settings::VibrationStrength::Weak, "Weak"}, + {Pinetime::Controllers::Settings::VibrationStrength::Normal, "Normal"}, + {Pinetime::Controllers::Settings::VibrationStrength::Strong, "Strong"}, + }}; + + std::array CreateOptionArray() { + std::array optionArray; + for (size_t i = 0; i < CheckboxList::MaxItems; i++) { + if (i >= options.size()) { + optionArray[i].name = ""; + optionArray[i].enabled = false; + } else { + optionArray[i].name = options[i].name; + optionArray[i].enabled = true; + } + } + return optionArray; + } + + uint32_t GetDefaultOption(Pinetime::Controllers::Settings::VibrationStrength currentOption) { + for (size_t i = 0; i < options.size(); i++) { + if (options[i].vibrationStrength == currentOption) { + return i; + } + } + return 0; + } +} + +SettingNotifVibration::SettingNotifVibration(Pinetime::Controllers::Settings& settingsController, + Pinetime::Controllers::MotorController& motorController) + : checkboxList( + 0, + 1, + "Notif. strength", + Symbols::tachometer, + GetDefaultOption(settingsController.GetNotifVibration()), + [&settings = settingsController, &motor = motorController](uint32_t index) { + motor.RunForDuration(static_cast(options[index].vibrationStrength)); + + settings.SetNotifVibration(options[index].vibrationStrength); + settings.SaveSettings(); + }, + CreateOptionArray()) { +} + +SettingNotifVibration::~SettingNotifVibration() { + lv_obj_clean(lv_scr_act()); +} \ No newline at end of file diff --git a/src/displayapp/screens/settings/SettingNotifVibration.h b/src/displayapp/screens/settings/SettingNotifVibration.h new file mode 100644 index 0000000000..e33b15ed4a --- /dev/null +++ b/src/displayapp/screens/settings/SettingNotifVibration.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +#include "components/settings/Settings.h" +#include "components/motor/MotorController.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/CheckboxList.h" + +namespace Pinetime { + + namespace Applications { + namespace Screens { + + class SettingNotifVibration : public Screen { + public: + explicit SettingNotifVibration(Pinetime::Controllers::Settings& settingsController, + Pinetime::Controllers::MotorController& motorController); + ~SettingNotifVibration() override; + + private: + CheckboxList checkboxList; + }; + } + } +} \ No newline at end of file diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index 3722c2be39..6f00ef325f 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -43,10 +43,12 @@ namespace Pinetime { {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}, {Symbols::clock, "Chimes", Apps::SettingChimes}, + {Symbols::tachometer, "Notif. str.", Apps::SettingNotifVibration}, + {Symbols::tachometer, "Chime strength", Apps::SettingChimeVibration}, {Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold}, + {Symbols::check, "Firmware", Apps::FirmwareValidation}, {Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth}, - {Symbols::list, "About", Apps::SysInfo}, // {Symbols::none, "None", Apps::None}, diff --git a/src/libs/lv_conf.h b/src/libs/lv_conf.h index c23647f2c0..e01c07d00e 100644 --- a/src/libs/lv_conf.h +++ b/src/libs/lv_conf.h @@ -415,6 +415,7 @@ typedef void* lv_indev_drv_user_data_t; /*Type of user data in the in #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(jetbrains_mono_bold_20) \ LV_FONT_DECLARE(jetbrains_mono_extrabold_compressed) \ + LV_FONT_DECLARE(jetbrains_mono_16) \ LV_FONT_DECLARE(jetbrains_mono_42) \ LV_FONT_DECLARE(jetbrains_mono_76) \ LV_FONT_DECLARE(open_sans_light) \ @@ -538,7 +539,7 @@ typedef void* lv_font_user_data_t; #define lv_snprintf snprintf #define lv_vsnprintf vsnprintf #else /*!LV_SPRINTF_CUSTOM*/ -#define LV_SPRINTF_DISABLE_FLOAT 1 +#define LV_SPRINTF_DISABLE_FLOAT 0 #endif /*LV_SPRINTF_CUSTOM*/ /*=================== diff --git a/src/resources/fonts.json b/src/resources/fonts.json index c4a63349a1..6fc3d43f95 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,