Skip to content

Commit 3f36a69

Browse files
InfiniTimeOrg#1959: settings: Add global widget selection (#25)
* settings: Add global widget selection Instead of each watch face implementing their own settings for which widgets to display, we can have a global selection of widgets. All watch faces can then determine whether it is enabled and so display it in whichever way makes sense for that face. Current widgets supported are heart rate, step counter, and weather. * WatchFaceAnalog: Add configurable widgets * WatchFaceAnalog: Add weather widget --------- Co-authored-by: Victor Kareh <vkareh@redhat.com>
1 parent c886dc9 commit 3f36a69

16 files changed

Lines changed: 492 additions & 264 deletions

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ list(APPEND SOURCE_FILES
412412
displayapp/screens/settings/SettingTimeFormat.cpp
413413
displayapp/screens/settings/SettingWeatherFormat.cpp
414414
displayapp/screens/settings/SettingWakeUp.cpp
415+
displayapp/screens/settings/SettingWidgets.cpp
415416
displayapp/screens/settings/SettingDisplay.cpp
416417
displayapp/screens/settings/SettingHeartRate.cpp
417418
displayapp/screens/settings/SettingSteps.cpp

src/components/settings/Settings.h

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace Pinetime {
1717
enum class Notification : uint8_t { On, Off, Sleep };
1818
enum class ChimesOption : uint8_t { None, Hours, HalfHours };
1919
enum class WakeUpMode : uint8_t { SingleTap = 0, DoubleTap = 1, RaiseWrist = 2, Shake = 3, LowerWrist = 4 };
20+
enum class Widget : uint8_t { HeartRate = 0, Steps = 1, Weather = 2 };
2021
enum class Colors : uint8_t {
2122
White,
2223
Silver,
@@ -38,7 +39,6 @@ namespace Pinetime {
3839
Pink
3940
};
4041
enum class PTSGaugeStyle : uint8_t { Full, Half, Numeric };
41-
enum class PTSWeather : uint8_t { On, Off };
4242
enum class PrideFlag : uint8_t { Gay, Trans, Bi, Lesbian };
4343
enum class DfuAndFsMode : uint8_t { Disabled, Enabled, EnabledTillReboot };
4444

@@ -47,7 +47,6 @@ namespace Pinetime {
4747
Colors ColorBar = Colors::Teal;
4848
Colors ColorBG = Colors::Black;
4949
PTSGaugeStyle gaugeStyle = PTSGaugeStyle::Full;
50-
PTSWeather weatherEnable = PTSWeather::Off;
5150
};
5251

5352
struct WatchFaceInfineat {
@@ -149,16 +148,6 @@ namespace Pinetime {
149148
return settings.PTS.gaugeStyle;
150149
};
151150

152-
void SetPTSWeather(PTSWeather weatherEnable) {
153-
if (weatherEnable != settings.PTS.weatherEnable)
154-
settingsChanged = true;
155-
settings.PTS.weatherEnable = weatherEnable;
156-
};
157-
158-
PTSWeather GetPTSWeather() const {
159-
return settings.PTS.weatherEnable;
160-
};
161-
162151
void SetPrideFlag(PrideFlag prideFlag) {
163152
if (prideFlag != settings.prideFlag)
164153
settingsChanged = true;
@@ -207,6 +196,21 @@ namespace Pinetime {
207196
return settings.weatherFormat;
208197
};
209198

199+
void SetWidget(Widget widget, bool enabled) {
200+
if (enabled != IsWidgetOn(widget)) {
201+
settingsChanged = true;
202+
}
203+
settings.widgets.set(static_cast<size_t>(widget), enabled);
204+
}
205+
206+
std::bitset<3> GetWidgets() const {
207+
return settings.widgets;
208+
}
209+
210+
bool IsWidgetOn(const Widget widget) const {
211+
return GetWidgets()[static_cast<size_t>(widget)];
212+
}
213+
210214
void SetNotificationStatus(Notification status) {
211215
if (status != settings.notificationStatus) {
212216
settingsChanged = true;
@@ -376,6 +380,7 @@ namespace Pinetime {
376380

377381
WatchFaceInfineat watchFaceInfineat;
378382

383+
std::bitset<3> widgets {0b111}; // Set all 3 widgets to enabled by default
379384
std::bitset<5> wakeUpMode {0};
380385
uint16_t shakeWakeThreshold = 150;
381386

src/displayapp/DisplayApp.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "displayapp/screens/settings/SettingTimeFormat.h"
4545
#include "displayapp/screens/settings/SettingWeatherFormat.h"
4646
#include "displayapp/screens/settings/SettingWakeUp.h"
47+
#include "displayapp/screens/settings/SettingWidgets.h"
4748
#include "displayapp/screens/settings/SettingDisplay.h"
4849
#include "displayapp/screens/settings/SettingSteps.h"
4950
#include "displayapp/screens/settings/SettingSetDateTime.h"
@@ -621,6 +622,9 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
621622
case Apps::SettingWakeUp:
622623
currentScreen = std::make_unique<Screens::SettingWakeUp>(settingsController);
623624
break;
625+
case Apps::SettingWidgets:
626+
currentScreen = std::make_unique<Screens::SettingWidgets>(settingsController);
627+
break;
624628
case Apps::SettingHeartRate:
625629
currentScreen = std::make_unique<Screens::SettingHeartRate>(settingsController);
626630
break;

src/displayapp/apps/Apps.h.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ namespace Pinetime {
3939
SettingHeartRate,
4040
SettingDisplay,
4141
SettingWakeUp,
42+
SettingWidgets,
4243
SettingSteps,
4344
SettingSetDateTime,
4445
SettingChimes,

src/displayapp/fonts/fonts.json

Lines changed: 1 addition & 1 deletion
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, 0xf1ec, 0xf55a, 0xf3ed"
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, 0xf0ad, 0xf1ec, 0xf55a, 0xf3ed"
1111
}
1212
],
1313
"bpp": 1,

src/displayapp/screens/Symbols.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ namespace Pinetime {
4242
static constexpr const char* sleep = "\xEE\xBD\x84";
4343
static constexpr const char* calculator = "\xEF\x87\xAC";
4444
static constexpr const char* backspace = "\xEF\x95\x9A";
45+
static constexpr const char* wrench = "\xEF\x82\xAD";
4546

4647
// fontawesome_weathericons.c
4748
// static constexpr const char* sun = "\xEF\x86\x85";

src/displayapp/screens/WatchFaceAnalog.cpp

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
#include "displayapp/screens/BleIcon.h"
77
#include "displayapp/screens/Symbols.h"
88
#include "displayapp/screens/NotificationIcon.h"
9+
#include "displayapp/screens/WeatherSymbols.h"
10+
#include "components/ble/SimpleWeatherService.h"
11+
#include "components/heartrate/HeartRateController.h"
12+
#include "components/motion/MotionController.h"
913
#include "components/settings/Settings.h"
1014
#include "displayapp/InfiniTimeTheme.h"
1115

@@ -48,14 +52,20 @@ WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController,
4852
const Controllers::Battery& batteryController,
4953
const Controllers::Ble& bleController,
5054
Controllers::NotificationManager& notificationManager,
51-
Controllers::Settings& settingsController)
55+
Controllers::Settings& settingsController,
56+
Controllers::HeartRateController& heartRateController,
57+
Controllers::MotionController& motionController,
58+
Controllers::SimpleWeatherService& weatherService)
5259
: currentDateTime {{}},
5360
batteryIcon(true),
5461
dateTimeController {dateTimeController},
5562
batteryController {batteryController},
5663
bleController {bleController},
5764
notificationManager {notificationManager},
58-
settingsController {settingsController} {
65+
settingsController {settingsController},
66+
heartRateController {heartRateController},
67+
motionController {motionController},
68+
weatherService {weatherService} {
5969

6070
sHour = 99;
6171
sMinute = 99;
@@ -114,13 +124,25 @@ WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController,
114124
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
115125

116126
// Date - Day / Week day
117-
118127
label_date_day = lv_label_create(lv_scr_act(), nullptr);
119128
lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange);
120129
lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day());
121130
lv_label_set_align(label_date_day, LV_LABEL_ALIGN_CENTER);
122131
lv_obj_align(label_date_day, nullptr, LV_ALIGN_CENTER, 50, 0);
123132

133+
if (settingsController.IsWidgetOn(Pinetime::Controllers::Settings::Widget::Weather)) {
134+
weatherIcon = lv_label_create(lv_scr_act(), nullptr);
135+
lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
136+
lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons);
137+
lv_label_set_text(weatherIcon, "");
138+
lv_obj_align(weatherIcon, nullptr, LV_ALIGN_CENTER, -50, -12);
139+
140+
temperature = lv_label_create(lv_scr_act(), nullptr);
141+
lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
142+
lv_label_set_text(temperature, "");
143+
lv_obj_align(temperature, nullptr, LV_ALIGN_CENTER, -50, 12);
144+
}
145+
124146
minute_body = lv_line_create(lv_scr_act(), nullptr);
125147
minute_body_trace = lv_line_create(lv_scr_act(), nullptr);
126148
hour_body = lv_line_create(lv_scr_act(), nullptr);
@@ -157,6 +179,30 @@ WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController,
157179
lv_style_set_line_rounded(&hour_line_style_trace, LV_STATE_DEFAULT, false);
158180
lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_line_style_trace);
159181

182+
if (settingsController.IsWidgetOn(Pinetime::Controllers::Settings::Widget::HeartRate)) {
183+
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
184+
lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat);
185+
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
186+
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
187+
188+
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
189+
lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
190+
lv_label_set_text_static(heartbeatValue, "");
191+
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
192+
}
193+
194+
if (settingsController.IsWidgetOn(Pinetime::Controllers::Settings::Widget::Steps)) {
195+
stepValue = lv_label_create(lv_scr_act(), nullptr);
196+
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
197+
lv_label_set_text_static(stepValue, "0");
198+
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
199+
200+
stepIcon = lv_label_create(lv_scr_act(), nullptr);
201+
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
202+
lv_label_set_text_static(stepIcon, Symbols::shoe);
203+
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
204+
}
205+
160206
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
161207

162208
Refresh();
@@ -264,4 +310,50 @@ void WatchFaceAnalog::Refresh() {
264310
lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day());
265311
}
266312
}
313+
314+
if (settingsController.IsWidgetOn(Pinetime::Controllers::Settings::Widget::HeartRate)) {
315+
heartbeat = heartRateController.HeartRate();
316+
heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
317+
if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) {
318+
if (heartbeatRunning.Get()) {
319+
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
320+
lv_label_set_text_fmt(heartbeatValue, "%d", heartbeat.Get());
321+
} else {
322+
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
323+
lv_label_set_text_static(heartbeatValue, "");
324+
}
325+
326+
lv_obj_realign(heartbeatIcon);
327+
lv_obj_realign(heartbeatValue);
328+
}
329+
}
330+
331+
if (settingsController.IsWidgetOn(Pinetime::Controllers::Settings::Widget::Steps)) {
332+
stepCount = motionController.NbSteps();
333+
if (stepCount.IsUpdated()) {
334+
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
335+
lv_obj_realign(stepValue);
336+
lv_obj_realign(stepIcon);
337+
}
338+
}
339+
340+
if (settingsController.IsWidgetOn(Pinetime::Controllers::Settings::Widget::Weather)) {
341+
currentWeather = weatherService.Current();
342+
if (currentWeather.IsUpdated()) {
343+
auto optCurrentWeather = currentWeather.Get();
344+
if (optCurrentWeather) {
345+
int16_t temp = optCurrentWeather->temperature.Celsius();
346+
char tempUnit = 'C';
347+
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
348+
temp = optCurrentWeather->temperature.Fahrenheit();
349+
tempUnit = 'F';
350+
}
351+
lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit);
352+
lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId, weatherService.IsNight()));
353+
} else {
354+
lv_label_set_text_static(temperature, "");
355+
lv_label_set_text(weatherIcon, "");
356+
}
357+
}
358+
}
267359
}

src/displayapp/screens/WatchFaceAnalog.h

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "components/battery/BatteryController.h"
1010
#include "components/ble/BleController.h"
1111
#include "components/ble/NotificationManager.h"
12+
#include "components/ble/SimpleWeatherService.h"
1213
#include "displayapp/screens/BatteryIcon.h"
1314
#include "utility/DirtyValue.h"
1415

@@ -18,6 +19,8 @@ namespace Pinetime {
1819
class Battery;
1920
class Ble;
2021
class NotificationManager;
22+
class HeartRateController;
23+
class MotionController;
2124
}
2225

2326
namespace Applications {
@@ -29,8 +32,10 @@ namespace Pinetime {
2932
const Controllers::Battery& batteryController,
3033
const Controllers::Ble& bleController,
3134
Controllers::NotificationManager& notificationManager,
32-
Controllers::Settings& settingsController);
33-
35+
Controllers::Settings& settingsController,
36+
Controllers::HeartRateController& heartRateController,
37+
Controllers::MotionController& motionController,
38+
Controllers::SimpleWeatherService& weather);
3439
~WatchFaceAnalog() override;
3540

3641
void Refresh() override;
@@ -42,8 +47,12 @@ namespace Pinetime {
4247
Utility::DirtyValue<bool> isCharging {};
4348
Utility::DirtyValue<bool> bleState {};
4449
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
50+
Utility::DirtyValue<uint32_t> stepCount {};
51+
Utility::DirtyValue<uint8_t> heartbeat {};
52+
Utility::DirtyValue<bool> heartbeatRunning {};
4553
Utility::DirtyValue<bool> notificationState {false};
4654
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::days>> currentDate;
55+
Utility::DirtyValue<std::optional<Pinetime::Controllers::SimpleWeatherService::CurrentWeather>> currentWeather {};
4756

4857
lv_obj_t* minor_scales;
4958
lv_obj_t* major_scales;
@@ -73,13 +82,23 @@ namespace Pinetime {
7382
lv_obj_t* notificationIcon;
7483
lv_obj_t* bleIcon;
7584

85+
lv_obj_t* heartbeatIcon;
86+
lv_obj_t* heartbeatValue;
87+
lv_obj_t* stepIcon;
88+
lv_obj_t* stepValue;
89+
lv_obj_t* weatherIcon;
90+
lv_obj_t* temperature;
91+
7692
BatteryIcon batteryIcon;
7793

7894
Controllers::DateTime& dateTimeController;
7995
const Controllers::Battery& batteryController;
8096
const Controllers::Ble& bleController;
8197
Controllers::NotificationManager& notificationManager;
8298
Controllers::Settings& settingsController;
99+
Controllers::HeartRateController& heartRateController;
100+
Controllers::MotionController& motionController;
101+
Controllers::SimpleWeatherService& weatherService;
83102

84103
void UpdateClock();
85104
void SetBatteryIcon();
@@ -98,7 +117,10 @@ namespace Pinetime {
98117
controllers.batteryController,
99118
controllers.bleController,
100119
controllers.notificationManager,
101-
controllers.settingsController);
120+
controllers.settingsController,
121+
controllers.heartRateController,
122+
controllers.motionController,
123+
*controllers.weatherController);
102124
};
103125

104126
static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) {

0 commit comments

Comments
 (0)