diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e4a354df64..0e5ab4607e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -421,6 +421,7 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingShakeThreshold.cpp displayapp/screens/settings/SettingBluetooth.cpp displayapp/screens/settings/SettingOTA.cpp + displayapp/screens/settings/SettingQuietHours.cpp ## Watch faces displayapp/screens/WatchFaceAnalog.cpp diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 9133d3fea1..c56089a052 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -351,10 +351,62 @@ namespace Pinetime { settings.heartRateBackgroundPeriod = newIntervalInSeconds.value(); } + bool GetQuietHoursEnabled() const { + return settings.quietHoursEnabled; + } + + void SetQuietHoursEnabled(bool enabled) { + if (enabled != settings.quietHoursEnabled) { + settingsChanged = true; + } + settings.quietHoursEnabled = enabled; + } + + uint8_t GetQuietHoursStart() const { + return settings.quietHoursStart; + } + + void SetQuietHoursStart(uint8_t hour) { + if (hour != settings.quietHoursStart) { + settingsChanged = true; + } + settings.quietHoursStart = hour; + } + + uint8_t GetQuietHoursEnd() const { + return settings.quietHoursEnd; + } + + void SetQuietHoursEnd(uint8_t hour) { + if (hour != settings.quietHoursEnd) { + settingsChanged = true; + } + settings.quietHoursEnd = hour; + } + + void EnterQuietHours() { + if (!inQuietHours) { + notificationStatusBeforeQuietHours = settings.notificationStatus; + inQuietHours = true; + SetNotificationStatus(Notification::Sleep); + } + } + + void ExitQuietHours() { + if (inQuietHours) { + inQuietHours = false; + SetNotificationStatus(notificationStatusBeforeQuietHours); + } + } + + bool IsInQuietHours() const { + return inQuietHours; + } + private: Pinetime::Controllers::FS& fs; - static constexpr uint32_t settingsVersion = 0x000a; + static constexpr uint32_t settingsVersion = 0x000b; struct SettingsData { uint32_t version = settingsVersion; @@ -383,6 +435,10 @@ namespace Pinetime { bool dfuAndFsEnabledOnBoot = false; uint16_t heartRateBackgroundPeriod = std::numeric_limits::max(); // Disabled by default + + bool quietHoursEnabled = false; + uint8_t quietHoursStart = 21; // 9 PM + uint8_t quietHoursEnd = 9; // 9 AM }; SettingsData settings; @@ -397,6 +453,9 @@ namespace Pinetime { bool bleRadioEnabled = true; bool dfuAndFsEnabledTillReboot = false; + Notification notificationStatusBeforeQuietHours = Notification::On; + bool inQuietHours = false; + void LoadSettingsFromFile(); void SaveSettingsToFile(); }; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 84fa603622..fa5229c8af 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -52,6 +52,7 @@ #include "displayapp/screens/settings/SettingShakeThreshold.h" #include "displayapp/screens/settings/SettingBluetooth.h" #include "displayapp/screens/settings/SettingOTA.h" +#include "displayapp/screens/settings/SettingQuietHours.h" #include "utility/Math.h" @@ -634,6 +635,9 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio case Apps::SettingOTA: currentScreen = std::make_unique(this, settingsController); break; + case Apps::SettingQuietHours: + currentScreen = std::make_unique(settingsController); + 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 d440b598d1..3993bec24c 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -45,6 +45,7 @@ namespace Pinetime { SettingShakeThreshold, SettingBluetooth, SettingOTA, + SettingQuietHours, Error }; diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index 3221c2f171..87ae9673de 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -7,7 +7,7 @@ }, { "file": "FontAwesome5-Solid+Brands+Regular.woff", - "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf1ec, 0xf55a, 0xf3ed" + "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf186, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf1ec, 0xf55a, 0xf3ed" } ], "bpp": 1, diff --git a/src/displayapp/screens/settings/SettingQuietHours.cpp b/src/displayapp/screens/settings/SettingQuietHours.cpp new file mode 100644 index 0000000000..d9791ca06b --- /dev/null +++ b/src/displayapp/screens/settings/SettingQuietHours.cpp @@ -0,0 +1,147 @@ +#include "displayapp/screens/settings/SettingQuietHours.h" +#include +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.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); + } + + void checkbox_event_handler(lv_obj_t* obj, lv_event_t event) { + if (event == LV_EVENT_VALUE_CHANGED) { + auto* screen = static_cast(obj->user_data); + screen->ToggleEnabled(); + } + } +} + +SettingQuietHours::SettingQuietHours(Pinetime::Controllers::Settings& settingsController) : settingsController {settingsController} { + + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(title, "Quiet hours"); + 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::moon); + lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); + lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); + + enabledCheckbox = lv_checkbox_create(lv_scr_act(), nullptr); + lv_checkbox_set_text(enabledCheckbox, "Enabled"); + lv_checkbox_set_checked(enabledCheckbox, settingsController.GetQuietHoursEnabled()); + enabledCheckbox->user_data = this; + lv_obj_set_event_cb(enabledCheckbox, checkbox_event_handler); + lv_obj_align(enabledCheckbox, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, 55); + + static constexpr uint8_t btnWidth = 50; + static constexpr uint8_t btnHeight = 40; + + // Start hour row + lv_obj_t* startLabel = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(startLabel, "Start"); + lv_obj_align(startLabel, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 10, -15); + + btnStartMinus = lv_btn_create(lv_scr_act(), nullptr); + btnStartMinus->user_data = this; + lv_obj_set_size(btnStartMinus, btnWidth, btnHeight); + lv_obj_align(btnStartMinus, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 70, -15); + lv_obj_set_style_local_bg_color(btnStartMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_t* lblStartMinus = lv_label_create(btnStartMinus, nullptr); + lv_label_set_text_static(lblStartMinus, "-"); + lv_obj_set_event_cb(btnStartMinus, event_handler); + + startValue = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(startValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_label_set_text_fmt(startValue, "%02d:00", settingsController.GetQuietHoursStart()); + lv_obj_align(startValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 132, -15); + + btnStartPlus = lv_btn_create(lv_scr_act(), nullptr); + btnStartPlus->user_data = this; + lv_obj_set_size(btnStartPlus, btnWidth, btnHeight); + lv_obj_align(btnStartPlus, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 195, -15); + lv_obj_set_style_local_bg_color(btnStartPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_t* lblStartPlus = lv_label_create(btnStartPlus, nullptr); + lv_label_set_text_static(lblStartPlus, "+"); + lv_obj_set_event_cb(btnStartPlus, event_handler); + + // End hour row + lv_obj_t* endLabel = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(endLabel, "End"); + lv_obj_align(endLabel, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 10, 40); + + btnEndMinus = lv_btn_create(lv_scr_act(), nullptr); + btnEndMinus->user_data = this; + lv_obj_set_size(btnEndMinus, btnWidth, btnHeight); + lv_obj_align(btnEndMinus, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 70, 40); + lv_obj_set_style_local_bg_color(btnEndMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_t* lblEndMinus = lv_label_create(btnEndMinus, nullptr); + lv_label_set_text_static(lblEndMinus, "-"); + lv_obj_set_event_cb(btnEndMinus, event_handler); + + endValue = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(endValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_label_set_text_fmt(endValue, "%02d:00", settingsController.GetQuietHoursEnd()); + lv_obj_align(endValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 132, 40); + + btnEndPlus = lv_btn_create(lv_scr_act(), nullptr); + btnEndPlus->user_data = this; + lv_obj_set_size(btnEndPlus, btnWidth, btnHeight); + lv_obj_align(btnEndPlus, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 195, 40); + lv_obj_set_style_local_bg_color(btnEndPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_t* lblEndPlus = lv_label_create(btnEndPlus, nullptr); + lv_label_set_text_static(lblEndPlus, "+"); + lv_obj_set_event_cb(btnEndPlus, event_handler); +} + +SettingQuietHours::~SettingQuietHours() { + lv_obj_clean(lv_scr_act()); + settingsController.SaveSettings(); +} + +void SettingQuietHours::ToggleEnabled() { + bool wasEnabled = settingsController.GetQuietHoursEnabled(); + settingsController.SetQuietHoursEnabled(!wasEnabled); + if (wasEnabled && settingsController.IsInQuietHours()) { + settingsController.ExitQuietHours(); + } + lv_checkbox_set_checked(enabledCheckbox, settingsController.GetQuietHoursEnabled()); +} + +void SettingQuietHours::UpdateSelected(lv_obj_t* object, lv_event_t event) { + if (event != LV_EVENT_SHORT_CLICKED && event != LV_EVENT_LONG_PRESSED_REPEAT) { + return; + } + + if (object == btnStartPlus) { + uint8_t val = settingsController.GetQuietHoursStart(); + val = (val + 1) % 24; + settingsController.SetQuietHoursStart(val); + lv_label_set_text_fmt(startValue, "%02d:00", val); + lv_obj_realign(startValue); + } else if (object == btnStartMinus) { + uint8_t val = settingsController.GetQuietHoursStart(); + val = (val + 23) % 24; + settingsController.SetQuietHoursStart(val); + lv_label_set_text_fmt(startValue, "%02d:00", val); + lv_obj_realign(startValue); + } else if (object == btnEndPlus) { + uint8_t val = settingsController.GetQuietHoursEnd(); + val = (val + 1) % 24; + settingsController.SetQuietHoursEnd(val); + lv_label_set_text_fmt(endValue, "%02d:00", val); + lv_obj_realign(endValue); + } else if (object == btnEndMinus) { + uint8_t val = settingsController.GetQuietHoursEnd(); + val = (val + 23) % 24; + settingsController.SetQuietHoursEnd(val); + lv_label_set_text_fmt(endValue, "%02d:00", val); + lv_obj_realign(endValue); + } +} diff --git a/src/displayapp/screens/settings/SettingQuietHours.h b/src/displayapp/screens/settings/SettingQuietHours.h new file mode 100644 index 0000000000..f4ac6eb313 --- /dev/null +++ b/src/displayapp/screens/settings/SettingQuietHours.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include "components/settings/Settings.h" +#include "displayapp/screens/Screen.h" + +namespace Pinetime { + + namespace Applications { + namespace Screens { + + class SettingQuietHours : public Screen { + public: + SettingQuietHours(Pinetime::Controllers::Settings& settingsController); + ~SettingQuietHours() override; + + void UpdateSelected(lv_obj_t* object, lv_event_t event); + void ToggleEnabled(); + + private: + Controllers::Settings& settingsController; + + lv_obj_t* enabledCheckbox; + lv_obj_t* startValue; + lv_obj_t* endValue; + lv_obj_t* btnStartPlus; + lv_obj_t* btnStartMinus; + lv_obj_t* btnEndPlus; + lv_obj_t* btnEndMinus; + }; + } + } +} diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index 32ac3ca943..8b4d0f6946 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -49,6 +49,7 @@ namespace Pinetime { {Symbols::shieldAlt, "Over-the-air", Apps::SettingOTA}, {Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth}, + {Symbols::moon, "Quiet hours", Apps::SettingQuietHours}, {Symbols::list, "About", Apps::SysInfo}, }}; ScreenList screens; diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 56bf9273e1..808ee2a929 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -222,6 +222,22 @@ void SystemTask::Work() { if (alarmController.IsEnabled()) { alarmController.ScheduleAlarm(); } + if (settingsController.GetQuietHoursEnabled()) { + uint8_t currentHour = dateTimeController.Hours(); + uint8_t start = settingsController.GetQuietHoursStart(); + uint8_t end = settingsController.GetQuietHoursEnd(); + bool shouldBeInQuietHours; + if (start <= end) { + shouldBeInQuietHours = (currentHour >= start && currentHour < end); + } else { + shouldBeInQuietHours = (currentHour >= start || currentHour < end); + } + if (shouldBeInQuietHours) { + settingsController.EnterQuietHours(); + } else { + settingsController.ExitQuietHours(); + } + } break; case Messages::OnNewNotification: if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On) { @@ -232,6 +248,7 @@ void SystemTask::Work() { } break; case Messages::SetOffAlarm: + settingsController.ExitQuietHours(); GoToRunning(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered); break; @@ -338,6 +355,14 @@ void SystemTask::Work() { break; case Messages::OnNewHour: using Pinetime::Controllers::AlarmController; + if (settingsController.GetQuietHoursEnabled()) { + uint8_t currentHour = dateTimeController.Hours(); + if (currentHour == settingsController.GetQuietHoursStart()) { + settingsController.EnterQuietHours(); + } else if (currentHour == settingsController.GetQuietHoursEnd()) { + settingsController.ExitQuietHours(); + } + } if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep && settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && !alarmController.IsAlerting()) { GoToRunning(); @@ -462,10 +487,10 @@ void SystemTask::UpdateMotion() { motionController.CurrentShakeSpeed() > settingsController.GetShakeThreshold())) { GoToRunning(); } - } - if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::LowerWrist) && state == SystemTaskState::Running && - motionController.ShouldLowerSleep()) { - GoToSleep(); + if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::LowerWrist) && state == SystemTaskState::Running && + motionController.ShouldLowerSleep()) { + GoToSleep(); + } } }