Skip to content

Commit c7c9111

Browse files
committed
Add sleep settings
Add a settings page for enabling/disabling actions to be done when sleep is turned on or off. Added Options: - [x] Allow Always on Display - [x] Allow Chimes - [x] Allow Notifications - [x] Disable BLE
1 parent 7b39d81 commit c7c9111

File tree

11 files changed

+212
-21
lines changed

11 files changed

+212
-21
lines changed

src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ list(APPEND SOURCE_FILES
412412
displayapp/screens/settings/SettingWakeUp.cpp
413413
displayapp/screens/settings/SettingDisplay.cpp
414414
displayapp/screens/settings/SettingSteps.cpp
415+
displayapp/screens/settings/SettingSleep.cpp
415416
displayapp/screens/settings/SettingSetDateTime.cpp
416417
displayapp/screens/settings/SettingSetDate.cpp
417418
displayapp/screens/settings/SettingSetTime.cpp

src/components/settings/Settings.h

+40-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace Pinetime {
1414
enum class Notification : uint8_t { On, Off, Sleep };
1515
enum class ChimesOption : uint8_t { None, Hours, HalfHours };
1616
enum class WakeUpMode : uint8_t { SingleTap = 0, DoubleTap = 1, RaiseWrist = 2, Shake = 3, LowerWrist = 4 };
17+
enum class SleepOption : uint8_t { AllowAOD = 0, AllowChimes = 1, AllowNotify = 2, DisableBle = 3 };
1718
enum class Colors : uint8_t {
1819
White,
1920
Silver,
@@ -215,7 +216,11 @@ namespace Pinetime {
215216
};
216217

217218
bool GetAlwaysOnDisplay() const {
218-
return settings.alwaysOnDisplay && GetNotificationStatus() != Notification::Sleep;
219+
if (isSleepOptionOn(Controllers::Settings::SleepOption::AllowAOD)) {
220+
return settings.alwaysOnDisplay;
221+
} else {
222+
return settings.alwaysOnDisplay && GetNotificationStatus() != Notification::Sleep;
223+
}
219224
};
220225

221226
void SetAlwaysOnDisplaySetting(bool state) {
@@ -268,6 +273,37 @@ namespace Pinetime {
268273
return getWakeUpModes()[static_cast<size_t>(mode)];
269274
}
270275

276+
bool sleepDisabledBle = false;
277+
278+
void setSleepOption(SleepOption option, bool enabled) {
279+
if (enabled != isSleepOptionOn(option)) {
280+
settingsChanged = true;
281+
}
282+
settings.sleepOption.set(static_cast<size_t>(option), enabled);
283+
284+
// Handle special behavior
285+
if (enabled) {
286+
switch (option) {
287+
case SleepOption::AllowNotify:
288+
settings.sleepOption.set(static_cast<size_t>(SleepOption::DisableBle), false);
289+
break;
290+
case SleepOption::DisableBle:
291+
settings.sleepOption.set(static_cast<size_t>(SleepOption::AllowNotify), false);
292+
break;
293+
default:
294+
break;
295+
}
296+
}
297+
};
298+
299+
std::bitset<4> getSleepOptions() const {
300+
return settings.sleepOption;
301+
}
302+
303+
bool isSleepOptionOn(const SleepOption option) const {
304+
return getSleepOptions()[static_cast<size_t>(option)];
305+
}
306+
271307
void SetBrightness(Controllers::BrightnessController::Levels level) {
272308
if (level != settings.brightLevel) {
273309
settingsChanged = true;
@@ -301,7 +337,7 @@ namespace Pinetime {
301337
private:
302338
Pinetime::Controllers::FS& fs;
303339

304-
static constexpr uint32_t settingsVersion = 0x0008;
340+
static constexpr uint32_t settingsVersion = 0x0009;
305341

306342
struct SettingsData {
307343
uint32_t version = settingsVersion;
@@ -324,6 +360,8 @@ namespace Pinetime {
324360
std::bitset<5> wakeUpMode {0};
325361
uint16_t shakeWakeThreshold = 150;
326362

363+
std::bitset<4> sleepOption {0};
364+
327365
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
328366
};
329367

src/displayapp/DisplayApp.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "displayapp/screens/settings/SettingWakeUp.h"
4646
#include "displayapp/screens/settings/SettingDisplay.h"
4747
#include "displayapp/screens/settings/SettingSteps.h"
48+
#include "displayapp/screens/settings/SettingSleep.h"
4849
#include "displayapp/screens/settings/SettingSetDateTime.h"
4950
#include "displayapp/screens/settings/SettingChimes.h"
5051
#include "displayapp/screens/settings/SettingShakeThreshold.h"
@@ -301,6 +302,7 @@ void DisplayApp::Refresh() {
301302
if (state != States::Running || !systemTask->IsSleeping()) {
302303
break;
303304
}
305+
304306
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Low) {
305307
brightnessController.Lower();
306308
vTaskDelay(100);
@@ -311,6 +313,7 @@ void DisplayApp::Refresh() {
311313
} else {
312314
brightnessController.Set(Controllers::BrightnessController::Levels::Off);
313315
}
316+
314317
// Since the active screen is not really an app, go back to Clock.
315318
if (currentApp == Apps::Launcher || currentApp == Apps::Notifications || currentApp == Apps::QuickSettings ||
316319
currentApp == Apps::Settings) {
@@ -611,6 +614,9 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
611614
case Apps::SettingSteps:
612615
currentScreen = std::make_unique<Screens::SettingSteps>(settingsController);
613616
break;
617+
case Apps::SettingSleep:
618+
currentScreen = std::make_unique<Screens::SettingSleep>(settingsController);
619+
break;
614620
case Apps::SettingSetDateTime:
615621
currentScreen = std::make_unique<Screens::SettingSetDateTime>(this, dateTimeController, settingsController);
616622
break;

src/displayapp/apps/Apps.h.in

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace Pinetime {
3838
SettingDisplay,
3939
SettingWakeUp,
4040
SettingSteps,
41+
SettingSleep,
4142
SettingSetDateTime,
4243
SettingChimes,
4344
SettingShakeThreshold,

src/displayapp/fonts/fonts.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
},
88
{
99
"file": "FontAwesome5-Solid+Brands+Regular.woff",
10-
"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"
10+
"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, 0xf186"
1111
}
1212
],
1313
"bpp": 1,

src/displayapp/screens/Symbols.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ namespace Pinetime {
3838
static constexpr const char* dice = "\xEF\x94\xA2";
3939
static constexpr const char* eye = "\xEF\x81\xAE";
4040
static constexpr const char* home = "\xEF\x80\x95";
41-
static constexpr const char* sleep = "\xEE\xBD\x84";
41+
static constexpr const char* crescentMoon = "\xEF\x86\x86";
4242

4343
// fontawesome_weathericons.c
4444
// static constexpr const char* sun = "\xEF\x86\x85";
@@ -61,6 +61,7 @@ namespace Pinetime {
6161

6262
static constexpr const char* notificationsOff = "\xEE\x9F\xB6";
6363
static constexpr const char* notificationsOn = "\xEE\x9F\xB7";
64+
static constexpr const char* sleep = "\xEE\xBD\x84";
6465

6566
static constexpr const char* flashlight = "\xEF\x80\x8B";
6667
static constexpr const char* paintbrushLg = "\xEE\x90\x8A";

src/displayapp/screens/settings/QuickSettings.cpp

+25-2
Original file line numberDiff line numberDiff line change
@@ -146,22 +146,45 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object) {
146146
settingsController.SetBrightness(brightness.Level());
147147

148148
} else if (object == btn3) {
149-
149+
// Turn notifications off
150150
if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::On) {
151151
settingsController.SetNotificationStatus(Controllers::Settings::Notification::Off);
152152
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOff);
153153
lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::NotificationsOff));
154+
// Turn sleep on
154155
} else if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::Off) {
155156
settingsController.SetNotificationStatus(Controllers::Settings::Notification::Sleep);
156157
lv_label_set_text_static(btn3_lvl, Symbols::sleep);
157158
lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::Sleep));
158-
} else {
159+
160+
if (settingsController.isSleepOptionOn(Controllers::Settings::SleepOption::DisableBle)) {
161+
if (settingsController.GetBleRadioEnabled()) {
162+
settingsController.SetBleRadioEnabled(false);
163+
app->PushMessage(Pinetime::Applications::Display::Messages::BleRadioEnableToggle);
164+
settingsController.sleepDisabledBle = true;
165+
}
166+
}
167+
// Turn notifications on
168+
} else if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::Sleep) {
159169
settingsController.SetNotificationStatus(Controllers::Settings::Notification::On);
160170
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
161171
lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::NotificationsOn));
162172
motorController.RunForDuration(35);
163173
}
164174

175+
// Re-enable Bluetooth settings for all notification statuses except Sleep
176+
// (Prevents the need to modify logic if additional statuses are added)
177+
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep) {
178+
// Enable Ble if previously disabled
179+
if (settingsController.sleepDisabledBle == true) {
180+
if (!settingsController.GetBleRadioEnabled()) {
181+
settingsController.SetBleRadioEnabled(true);
182+
this->app->PushMessage(Pinetime::Applications::Display::Messages::BleRadioEnableToggle);
183+
}
184+
settingsController.sleepDisabledBle = false;
185+
}
186+
}
187+
165188
} else if (object == btn4) {
166189
settingsController.SetSettingsMenu(0);
167190
app->StartApp(Apps::Settings, DisplayApp::FullRefreshDirections::Up);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include "displayapp/screens/settings/SettingSleep.h"
2+
#include <lvgl/lvgl.h>
3+
#include "displayapp/DisplayApp.h"
4+
#include "displayapp/screens/Screen.h"
5+
#include "displayapp/screens/Symbols.h"
6+
#include "components/settings/Settings.h"
7+
#include "displayapp/screens/Styles.h"
8+
9+
using namespace Pinetime::Applications::Screens;
10+
11+
constexpr std::array<SettingSleep::Option, 4> SettingSleep::options;
12+
13+
namespace {
14+
void event_handler(lv_obj_t* obj, lv_event_t event) {
15+
auto* screen = static_cast<SettingSleep*>(obj->user_data);
16+
if (event == LV_EVENT_VALUE_CHANGED) {
17+
screen->UpdateSelected(obj);
18+
}
19+
}
20+
}
21+
22+
SettingSleep::SettingSleep(Pinetime::Controllers::Settings& settingsController) : settingsController {settingsController} {
23+
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
24+
25+
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
26+
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
27+
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
28+
lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
29+
30+
lv_obj_set_pos(container1, 10, 35);
31+
lv_obj_set_width(container1, LV_HOR_RES - 20);
32+
lv_obj_set_height(container1, LV_VER_RES - 20);
33+
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
34+
35+
lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr);
36+
lv_label_set_text_static(title, "Sleep Actions");
37+
lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
38+
lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15);
39+
40+
lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr);
41+
lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
42+
lv_label_set_text_static(icon, Symbols::crescentMoon);
43+
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
44+
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
45+
46+
for (unsigned int i = 0; i < options.size(); i++) {
47+
cbOption[i] = lv_checkbox_create(container1, nullptr);
48+
lv_checkbox_set_text(cbOption[i], options[i].name);
49+
if (settingsController.isSleepOptionOn(static_cast<Controllers::Settings::SleepOption>(i))) {
50+
lv_checkbox_set_checked(cbOption[i], true);
51+
}
52+
cbOption[i]->user_data = this;
53+
lv_obj_set_event_cb(cbOption[i], event_handler);
54+
}
55+
}
56+
57+
SettingSleep::~SettingSleep() {
58+
lv_obj_clean(lv_scr_act());
59+
settingsController.SaveSettings();
60+
}
61+
62+
void SettingSleep::UpdateSelected(lv_obj_t* object) {
63+
// Find the index of the checkbox that triggered the event
64+
for (size_t i = 0; i < options.size(); i++) {
65+
if (cbOption[i] == object) {
66+
bool currentState = settingsController.isSleepOptionOn(options[i].sleepOption);
67+
settingsController.setSleepOption(options[i].sleepOption, !currentState);
68+
break;
69+
}
70+
}
71+
72+
// Update checkbox according to current sleep options.
73+
// This is needed because we can have extra logic when setting or unsetting sleep options,
74+
// for example, when setting AllowNotify, DisableBle is unset and vice versa.
75+
auto sleepOptions = settingsController.getSleepOptions();
76+
for (size_t i = 0; i < options.size(); ++i) {
77+
lv_checkbox_set_checked(cbOption[i], sleepOptions[i]);
78+
}
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#pragma once
2+
3+
#include <array>
4+
#include <cstdint>
5+
#include <lvgl/lvgl.h>
6+
#include "components/settings/Settings.h"
7+
#include "displayapp/screens/Screen.h"
8+
9+
namespace Pinetime {
10+
11+
namespace Applications {
12+
namespace Screens {
13+
14+
class SettingSleep : public Screen {
15+
public:
16+
SettingSleep(Pinetime::Controllers::Settings& settingsController);
17+
~SettingSleep() override;
18+
19+
void UpdateSelected(lv_obj_t* object);
20+
21+
private:
22+
struct Option {
23+
Controllers::Settings::SleepOption sleepOption;
24+
const char* name;
25+
};
26+
27+
Controllers::Settings& settingsController;
28+
static constexpr std::array<Option, 4> options = {{
29+
{Controllers::Settings::SleepOption::AllowAOD, "Allow AOD"},
30+
{Controllers::Settings::SleepOption::AllowChimes, "Allow Chimes"},
31+
{Controllers::Settings::SleepOption::AllowNotify, "Allow Notify"},
32+
{Controllers::Settings::SleepOption::DisableBle, "Disable BLE"},
33+
}};
34+
35+
lv_obj_t* cbOption[options.size()];
36+
};
37+
}
38+
}
39+
}

src/displayapp/screens/settings/Settings.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,17 @@ namespace Pinetime {
3737
{Symbols::clock, "Time format", Apps::SettingTimeFormat},
3838
{Symbols::home, "Watch face", Apps::SettingWatchFace},
3939

40+
{Symbols::crescentMoon, "Sleep", Apps::SettingSleep},
4041
{Symbols::shoe, "Steps", Apps::SettingSteps},
4142
{Symbols::clock, "Date & Time", Apps::SettingSetDateTime},
4243
{Symbols::cloudSunRain, "Weather", Apps::SettingWeatherFormat},
43-
{Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
4444

45+
{Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
4546
{Symbols::clock, "Chimes", Apps::SettingChimes},
4647
{Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold},
4748
{Symbols::check, "Firmware", Apps::FirmwareValidation},
48-
{Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth},
4949

50+
{Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth},
5051
{Symbols::list, "About", Apps::SysInfo},
5152

5253
// {Symbols::none, "None", Apps::None},

src/systemtask/SystemTask.cpp

+15-13
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,9 @@ void SystemTask::Work() {
207207
}
208208
break;
209209
case Messages::OnNewNotification:
210-
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On) {
210+
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On ||
211+
(settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::Sleep &&
212+
settingsController.isSleepOptionOn(Pinetime::Controllers::Settings::SleepOption::AllowNotify))) {
211213
if (IsSleeping()) {
212214
GoToRunning();
213215
}
@@ -321,19 +323,17 @@ void SystemTask::Work() {
321323
stepCounterMustBeReset = true;
322324
break;
323325
case Messages::OnNewHour:
324-
using Pinetime::Controllers::AlarmController;
325-
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
326-
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && !alarmController.IsAlerting()) {
327-
GoToRunning();
328-
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime);
329-
}
330-
break;
331326
case Messages::OnNewHalfHour:
332327
using Pinetime::Controllers::AlarmController;
333-
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
334-
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours && !alarmController.IsAlerting()) {
335-
GoToRunning();
336-
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime);
328+
329+
if (settingsController.GetChimeOption() != Controllers::Settings::ChimesOption::None && !alarmController.IsAlerting()) {
330+
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep ||
331+
settingsController.isSleepOptionOn(Pinetime::Controllers::Settings::SleepOption::AllowChimes)) {
332+
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep) {
333+
GoToRunning();
334+
}
335+
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime);
336+
}
337337
}
338338
break;
339339
case Messages::OnChargingEvent:
@@ -418,10 +418,12 @@ void SystemTask::GoToSleep() {
418418
if (IsSleepDisabled()) {
419419
return;
420420
}
421-
NRF_LOG_INFO("[systemtask] Going to sleep");
421+
422422
if (settingsController.GetAlwaysOnDisplay()) {
423+
NRF_LOG_INFO("[systemtask] Going To Always On Display");
423424
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToAOD);
424425
} else {
426+
NRF_LOG_INFO("[systemtask] Going To sleep");
425427
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToSleep);
426428
}
427429
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::GoToSleep);

0 commit comments

Comments
 (0)