22#include " displayapp/screens/WatchFaceTerminal.h"
33#include " displayapp/screens/BatteryIcon.h"
44#include " displayapp/screens/NotificationIcon.h"
5- #include " displayapp/screens/Symbols.h"
65#include " components/battery/BatteryController.h"
76#include " components/ble/BleController.h"
87#include " components/ble/NotificationManager.h"
8+ #include " components/ble/SimpleWeatherService.h"
99#include " components/heartrate/HeartRateController.h"
1010#include " components/motion/MotionController.h"
1111#include " components/settings/Settings.h"
12+ #include " displayapp/screens/WeatherSymbols.h"
13+ #include " displayapp/InfiniTimeTheme.h"
14+
1215
1316using namespace Pinetime ::Applications::Screens;
1417
18+ namespace {
19+ lv_color_t temperatureColor (int16_t temperature) {
20+ if (temperature <= 0 ) { // freezing
21+ return Colors::blue;
22+ } else if (temperature <= 400 ) { // ice
23+ return LV_COLOR_CYAN;
24+ } else if (temperature >= 2700 ) { // hot
25+ return Colors::deepOrange;
26+ }
27+ return Colors::orange; // normal
28+ }
29+ }
30+
1531WatchFaceTerminal::WatchFaceTerminal (Controllers::DateTime& dateTimeController,
1632 const Controllers::Battery& batteryController,
1733 const Controllers::Ble& bleController,
1834 Controllers::NotificationManager& notificationManager,
1935 Controllers::Settings& settingsController,
2036 Controllers::HeartRateController& heartRateController,
21- Controllers::MotionController& motionController)
37+ Controllers::MotionController& motionController,
38+ Controllers::SimpleWeatherService& weatherService)
2239 : currentDateTime {{}},
2340 dateTimeController {dateTimeController},
2441 batteryController {batteryController},
2542 bleController {bleController},
2643 notificationManager {notificationManager},
2744 settingsController {settingsController},
2845 heartRateController {heartRateController},
29- motionController {motionController} {
30- batteryValue = lv_label_create (lv_scr_act (), nullptr );
31- lv_label_set_recolor (batteryValue, true );
32- lv_obj_align (batteryValue, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , -20 );
33-
34- connectState = lv_label_create (lv_scr_act (), nullptr );
35- lv_label_set_recolor (connectState, true );
36- lv_obj_align (connectState, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , 40 );
46+ motionController {motionController},
47+ weatherService {weatherService} {
3748
3849 notificationIcon = lv_label_create (lv_scr_act (), nullptr );
3950 lv_obj_align (notificationIcon, nullptr , LV_ALIGN_IN_LEFT_MID, 0 , -100 );
4051
41- label_date = lv_label_create (lv_scr_act (), nullptr );
42- lv_label_set_recolor (label_date, true );
43- lv_obj_align (label_date, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , -40 );
44-
4552 label_prompt_1 = lv_label_create (lv_scr_act (), nullptr );
4653 lv_obj_align (label_prompt_1, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , -80 );
4754 lv_label_set_text_static (label_prompt_1, " user@watch:~ $ now" );
4855
49- label_prompt_2 = lv_label_create (lv_scr_act (), nullptr );
50- lv_obj_align (label_prompt_2, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , 60 );
51- lv_label_set_text_static (label_prompt_2, " user@watch:~ $" );
52-
5356 label_time = lv_label_create (lv_scr_act (), nullptr );
54- lv_label_set_recolor (label_time, true );
57+ lv_obj_set_style_local_text_color (label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::blue );
5558 lv_obj_align (label_time, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , -60 );
5659
57- heartbeatValue = lv_label_create (lv_scr_act (), nullptr );
58- lv_label_set_recolor (heartbeatValue, true );
59- lv_obj_align (heartbeatValue, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , 20 );
60+ label_date = lv_label_create (lv_scr_act (), nullptr );
61+ lv_obj_set_style_local_text_color (label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::blue);
62+ lv_obj_align (label_date, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , -40 );
63+
64+ weather = lv_label_create (lv_scr_act (), nullptr );
65+ lv_obj_align (weather, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , -20 );
66+
67+ batteryValue = lv_label_create (lv_scr_act (), nullptr );
68+ lv_obj_align (batteryValue, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , 0 );
6069
6170 stepValue = lv_label_create (lv_scr_act (), nullptr );
62- lv_label_set_recolor (stepValue, true );
63- lv_obj_align (stepValue, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , 0 );
71+ lv_obj_set_style_local_text_color (stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange);
72+ lv_obj_align (stepValue, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , 20 );
73+
74+ heartbeatValue = lv_label_create (lv_scr_act (), nullptr );
75+ lv_obj_align (heartbeatValue, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , 40 );
76+
77+ connectState = lv_label_create (lv_scr_act (), nullptr );
78+ lv_obj_align (connectState, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , 60 );
79+
80+ label_prompt_2 = lv_label_create (lv_scr_act (), nullptr );
81+ lv_obj_align (label_prompt_2, lv_scr_act (), LV_ALIGN_IN_LEFT_MID, 0 , 80 );
82+ lv_label_set_text_static (label_prompt_2, " user@watch:~ $" );
6483
6584 taskRefresh = lv_task_create (RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this );
6685 Refresh ();
@@ -72,29 +91,6 @@ WatchFaceTerminal::~WatchFaceTerminal() {
7291}
7392
7493void WatchFaceTerminal::Refresh () {
75- powerPresent = batteryController.IsPowerPresent ();
76- batteryPercentRemaining = batteryController.PercentRemaining ();
77- if (batteryPercentRemaining.IsUpdated () || powerPresent.IsUpdated ()) {
78- lv_label_set_text_fmt (batteryValue, " [BATT]#387b54 %d%%" , batteryPercentRemaining.Get ());
79- if (batteryController.IsPowerPresent ()) {
80- lv_label_ins_text (batteryValue, LV_LABEL_POS_LAST, " Charging" );
81- }
82- }
83-
84- bleState = bleController.IsConnected ();
85- bleRadioEnabled = bleController.IsRadioEnabled ();
86- if (bleState.IsUpdated () || bleRadioEnabled.IsUpdated ()) {
87- if (!bleRadioEnabled.Get ()) {
88- lv_label_set_text_static (connectState, " [STAT]#0082fc Disabled#" );
89- } else {
90- if (bleState.Get ()) {
91- lv_label_set_text_static (connectState, " [STAT]#0082fc Connected#" );
92- } else {
93- lv_label_set_text_static (connectState, " [STAT]#0082fc Disconnected#" );
94- }
95- }
96- }
97-
9894 notificationState = notificationManager.AreNewNotificationsAvailable ();
9995 if (notificationState.IsUpdated ()) {
10096 if (notificationState.Get ()) {
@@ -104,6 +100,7 @@ void WatchFaceTerminal::Refresh() {
104100 }
105101 }
106102
103+
107104 currentDateTime = std::chrono::time_point_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime ());
108105 if (currentDateTime.IsUpdated ()) {
109106 uint8_t hour = dateTimeController.Hours ();
@@ -120,32 +117,90 @@ void WatchFaceTerminal::Refresh() {
120117 hour = hour - 12 ;
121118 ampmChar[0 ] = ' P' ;
122119 }
123- lv_label_set_text_fmt (label_time, " [TIME]#11cc55 %02d:%02d:%02d %s#" , hour, minute, second, ampmChar);
120+ lv_label_set_text_fmt (label_time, " [TIME] %02d:%02d:%02d %s#" , hour, minute, second, ampmChar);
124121 } else {
125- lv_label_set_text_fmt (label_time, " [TIME]#11cc55 %02d:%02d:%02d" , hour, minute, second);
122+ lv_label_set_text_fmt (label_time, " [TIME] %02d:%02d:%02d" , hour, minute, second);
126123 }
127124
128125 currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get ());
129126 if (currentDate.IsUpdated ()) {
130127 uint16_t year = dateTimeController.Year ();
131128 Controllers::DateTime::Months month = dateTimeController.Month ();
132129 uint8_t day = dateTimeController.Day ();
133- lv_label_set_text_fmt (label_date, " [DATE]#007fff %04d-%02d-%02d#" , short (year), char (month), char (day));
130+ lv_label_set_text_fmt (label_date, " [DATE] %04d-%02d-%02d#" , short (year), char (month), char (day));
131+ }
132+ }
133+
134+
135+ currentWeather = weatherService.Current ();
136+ if (currentWeather.IsUpdated ()) {
137+ auto optCurrentWeather = currentWeather.Get ();
138+ if (optCurrentWeather) {
139+ int16_t temp = optCurrentWeather->temperature ;
140+ char tempUnit = ' C' ;
141+ lv_obj_set_style_local_text_color (weather, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, temperatureColor (temp));
142+ if (settingsController.GetWeatherFormat () == Controllers::Settings::WeatherFormat::Imperial) {
143+ condition = Symbols::GetSimpleCondition (optCurrentWeather->iconId );
144+ temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit (temp);
145+ tempUnit = ' F' ;
146+ }
147+ lv_label_set_text_fmt (weather, " [WTHR] %i°%c %s " , temp/100 , tempUnit, condition);
148+ } else {
149+ lv_label_set_text (weather, " [WTHR] ---°" );
150+ lv_obj_set_style_local_text_color (weather, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray);
134151 }
135152 }
136153
154+
155+ powerPresent = batteryController.IsPowerPresent ();
156+ batteryPercentRemaining = batteryController.PercentRemaining ();
157+ if (batteryPercentRemaining.IsUpdated () || powerPresent.IsUpdated ()) {
158+ // HSV color model has red at 0° and green at 120°.
159+ // We lock satuation and brightness at 100% and traverse the cilinder
160+ // between red and green, thus avoiding the darker RGB on medium battery
161+ // charges and giving us a much nicer color range.
162+ uint8_t hue = batteryPercentRemaining.Get () * 120 / 100 ;
163+ lv_obj_set_style_local_text_color (batteryValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hsv_to_rgb (hue, 100 , 100 ));
164+ lv_label_set_text_fmt (batteryValue, " [BATT] %d%%" , batteryPercentRemaining.Get ());
165+ if (batteryController.IsPowerPresent ()) {
166+ lv_label_ins_text (batteryValue, LV_LABEL_POS_LAST, " Charging" );
167+ }
168+ }
169+
170+
171+ stepCount = motionController.NbSteps ();
172+ if (stepCount.IsUpdated ()) {
173+ lv_label_set_text_fmt (stepValue, " [STEP] %lu steps#" , stepCount.Get ());
174+ }
175+
176+
137177 heartbeat = heartRateController.HeartRate ();
138178 heartbeatRunning = heartRateController.State () != Controllers::HeartRateController::States::Stopped;
139179 if (heartbeat.IsUpdated () || heartbeatRunning.IsUpdated ()) {
140180 if (heartbeatRunning.Get ()) {
141- lv_label_set_text_fmt (heartbeatValue, " [L_HR]#ee3311 %d bpm#" , heartbeat.Get ());
181+
182+ lv_obj_set_style_local_text_color (heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::deepOrange);
183+ lv_label_set_text_fmt (heartbeatValue, " [L_HR] %d bpm#" , heartbeat.Get ());
142184 } else {
143- lv_label_set_text_static (heartbeatValue, " [L_HR]#ee3311 ---#" );
185+ lv_label_set_text_static (heartbeatValue, " [L_HR] ---#" );
186+ lv_obj_set_style_local_text_color (heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray);
144187 }
145188 }
146189
147- stepCount = motionController.NbSteps ();
148- if (stepCount.IsUpdated ()) {
149- lv_label_set_text_fmt (stepValue, " [STEP]#ee3377 %lu steps#" , stepCount.Get ());
190+ bleState = bleController.IsConnected ();
191+ bleRadioEnabled = bleController.IsRadioEnabled ();
192+ if (bleState.IsUpdated () || bleRadioEnabled.IsUpdated ()) {
193+ if (!bleRadioEnabled.Get ()) {
194+ lv_label_set_text_static (connectState, " [STAT] Disabled#" );
195+ lv_obj_set_style_local_text_color (connectState, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray);
196+ } else {
197+ if (bleState.Get ()) {
198+ lv_label_set_text_static (connectState, " [STAT] Connected#" );
199+ lv_obj_set_style_local_text_color (connectState, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::blue);
200+ } else {
201+ lv_label_set_text_static (connectState, " [STAT] Disconnected#" );
202+ lv_obj_set_style_local_text_color (connectState, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray);
203+ }
204+ }
150205 }
151206}
0 commit comments