Skip to content

Commit 88f0190

Browse files
committed
add terminal watchface
1 parent 26ae828 commit 88f0190

4 files changed

Lines changed: 351 additions & 0 deletions

File tree

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ list(APPEND SOURCE_FILES
454454
displayapp/icons/bg_clock.c
455455
displayapp/screens/WatchFaceAnalog.cpp
456456
displayapp/screens/WatchFaceDigital.cpp
457+
displayapp/screens/WatchFaceTerminal.cpp
457458
displayapp/screens/PineTimeStyle.cpp
458459

459460
##

src/displayapp/screens/Clock.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "components/settings/Settings.h"
1010
#include "displayapp/DisplayApp.h"
1111
#include "displayapp/screens/WatchFaceDigital.h"
12+
#include "displayapp/screens/WatchFaceTerminal.h"
1213
#include "displayapp/screens/WatchFaceAnalog.h"
1314
#include "displayapp/screens/PineTimeStyle.h"
1415

@@ -41,6 +42,9 @@ Clock::Clock(DisplayApp* app,
4142
case 2:
4243
return PineTimeStyleScreen();
4344
break;
45+
case 3:
46+
return WatchFaceTerminalScreen();
47+
break;
4448
}
4549
return WatchFaceDigitalScreen();
4650
}()} {
@@ -84,3 +88,14 @@ std::unique_ptr<Screen> Clock::PineTimeStyleScreen() {
8488
settingsController,
8589
motionController);
8690
}
91+
92+
std::unique_ptr<Screen> Clock::WatchFaceTerminalScreen() {
93+
return std::make_unique<Screens::WatchFaceTerminal>(app,
94+
dateTimeController,
95+
batteryController,
96+
bleController,
97+
notificatioManager,
98+
settingsController,
99+
heartRateController,
100+
motionController);
101+
}
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
#include "WatchFaceTerminal.h"
2+
3+
#include <date/date.h>
4+
#include <lvgl/lvgl.h>
5+
#include <cstdio>
6+
#include "BatteryIcon.h"
7+
#include "BleIcon.h"
8+
#include "NotificationIcon.h"
9+
#include "Symbols.h"
10+
#include "components/battery/BatteryController.h"
11+
#include "components/ble/BleController.h"
12+
#include "components/ble/NotificationManager.h"
13+
#include "components/heartrate/HeartRateController.h"
14+
#include "components/motion/MotionController.h"
15+
#include "components/settings/Settings.h"
16+
#include "../DisplayApp.h"
17+
18+
using namespace Pinetime::Applications::Screens;
19+
20+
WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app,
21+
Controllers::DateTime& dateTimeController,
22+
Controllers::Battery& batteryController,
23+
Controllers::Ble& bleController,
24+
Controllers::NotificationManager& notificatioManager,
25+
Controllers::Settings& settingsController,
26+
Controllers::HeartRateController& heartRateController,
27+
Controllers::MotionController& motionController)
28+
: Screen(app),
29+
currentDateTime {{}},
30+
dateTimeController {dateTimeController},
31+
batteryController {batteryController},
32+
bleController {bleController},
33+
notificatioManager {notificatioManager},
34+
settingsController {settingsController},
35+
heartRateController {heartRateController},
36+
motionController {motionController} {
37+
settingsController.SetClockFace(0);
38+
39+
displayedChar[0] = 0;
40+
displayedChar[1] = 0;
41+
displayedChar[2] = 0;
42+
displayedChar[3] = 0;
43+
displayedChar[4] = 0;
44+
45+
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
46+
lv_label_set_text(batteryIcon, Symbols::batteryFull);
47+
lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, 2);
48+
49+
batteryPlug = lv_label_create(lv_scr_act(), nullptr);
50+
lv_label_set_text(batteryPlug, Symbols::plug);
51+
lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
52+
53+
batteryPercent = lv_label_create(lv_scr_act(), nullptr);
54+
lv_label_set_recolor(batteryPercent, true);
55+
lv_obj_align(batteryPercent, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20);
56+
57+
bleIcon = lv_label_create(lv_scr_act(), nullptr);
58+
lv_label_set_text(bleIcon, Symbols::bluetooth);
59+
lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
60+
61+
notificationIcon = lv_label_create(lv_scr_act(), NULL);
62+
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
63+
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 10, 0);
64+
65+
label_date = lv_label_create(lv_scr_act(), nullptr);
66+
lv_label_set_recolor(label_date, true);
67+
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -40);
68+
69+
label_prompt_1 = lv_label_create(lv_scr_act(), nullptr);
70+
lv_obj_align(label_prompt_1, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -80);
71+
lv_label_set_text(label_prompt_1, "user@watch:~ $ now");
72+
73+
label_prompt_2 = lv_label_create(lv_scr_act(), nullptr);
74+
lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40);
75+
lv_label_set_text(label_prompt_2, "user@watch:~ $");
76+
77+
label_time = lv_label_create(lv_scr_act(), nullptr);
78+
lv_label_set_recolor(label_time, true);
79+
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -60);
80+
81+
backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
82+
lv_obj_set_click(backgroundLabel, true);
83+
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
84+
lv_obj_set_size(backgroundLabel, 240, 240);
85+
lv_obj_set_pos(backgroundLabel, 0, 0);
86+
lv_label_set_text(backgroundLabel, "");
87+
88+
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
89+
lv_label_set_recolor(heartbeatValue, true);
90+
lv_label_set_text(heartbeatValue, "[L_HR]#ee3311 0 bpm#");
91+
lv_obj_align(heartbeatValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 20);
92+
93+
stepValue = lv_label_create(lv_scr_act(), nullptr);
94+
lv_label_set_recolor(stepValue, true);
95+
lv_label_set_text(stepValue, "[STEP]#ee3377 0 steps#");
96+
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0);
97+
}
98+
99+
WatchFaceTerminal::~WatchFaceTerminal() {
100+
lv_obj_clean(lv_scr_act());
101+
}
102+
103+
bool WatchFaceTerminal::Refresh() {
104+
batteryPercentRemaining = batteryController.PercentRemaining();
105+
if (batteryPercentRemaining.IsUpdated()) {
106+
auto batteryPercent = batteryPercentRemaining.Get();
107+
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
108+
auto isCharging = batteryController.IsCharging() || batteryController.IsPowerPresent();
109+
lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
110+
}
111+
112+
bleState = bleController.IsConnected();
113+
if (bleState.IsUpdated()) {
114+
if(bleState.Get() == true) {
115+
lv_label_set_text(bleIcon, BleIcon::GetIcon(true));
116+
} else {
117+
lv_label_set_text(bleIcon, BleIcon::GetIcon(false));
118+
}
119+
}
120+
lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -5, 5);
121+
lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
122+
lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
123+
124+
notificationState = notificatioManager.AreNewNotificationsAvailable();
125+
if(notificationState.IsUpdated()) {
126+
if(notificationState.Get() == true)
127+
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true));
128+
else
129+
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
130+
}
131+
132+
currentDateTime = dateTimeController.CurrentDateTime();
133+
134+
if(currentDateTime.IsUpdated()) {
135+
auto newDateTime = currentDateTime.Get();
136+
137+
auto dp = date::floor<date::days>(newDateTime);
138+
auto time = date::make_time(newDateTime-dp);
139+
auto yearMonthDay = date::year_month_day(dp);
140+
141+
auto year = (int)yearMonthDay.year();
142+
auto month = static_cast<Pinetime::Controllers::DateTime::Months>((unsigned)yearMonthDay.month());
143+
auto day = (unsigned)yearMonthDay.day();
144+
auto dayOfWeek = static_cast<Pinetime::Controllers::DateTime::Days>(date::weekday(yearMonthDay).iso_encoding());
145+
146+
auto hour = time.hours().count();
147+
auto minute = time.minutes().count();
148+
auto second = time.seconds().count();
149+
150+
char minutesChar[6];
151+
sprintf(minutesChar, "%02d", static_cast<int>(minute));
152+
153+
char hoursChar[8];
154+
155+
char ampmChar[3];
156+
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
157+
sprintf(hoursChar, "%02d", hour);
158+
} else {
159+
if (hour == 0 && hour != 12) {
160+
hour = 12;
161+
sprintf(ampmChar, "AM");
162+
} else if (hour == 12 && hour != 0) {
163+
hour = 12;
164+
sprintf(ampmChar, "PM");
165+
} else if (hour < 12 && hour != 0) {
166+
sprintf(ampmChar, "AM");
167+
} else if (hour > 12 && hour != 0) {
168+
hour = hour - 12;
169+
sprintf(ampmChar, "PM");
170+
}
171+
sprintf(hoursChar, "%02d", hour);
172+
}
173+
174+
char secondsChar[5];
175+
sprintf(secondsChar, "%02d", static_cast<int>(second));
176+
177+
auto batteryValue = static_cast<uint8_t>(batteryController.PercentRemaining());
178+
/*
179+
char batteryGauge[12];
180+
if (batteryValue > 75){
181+
sprintf(batteryGauge, "[++++]"); //100-75
182+
}
183+
else if (batteryValue > 50){
184+
sprintf(batteryGauge, "[+++.]"); //75-50
185+
}
186+
else if (batteryValue > 25){
187+
sprintf(batteryGauge, "[++..]"); //50-25
188+
}
189+
else if (batteryValue > 10){
190+
sprintf(batteryGauge, "[+....]"); //25-10
191+
}
192+
else if (batteryValue > 0){
193+
sprintf(batteryGauge, "[!!!!!]"); //10-0
194+
}
195+
*/
196+
char battStr[24];
197+
sprintf(battStr, "[BATT]#387b54 %d%\%#", batteryValue);
198+
lv_label_set_text(batteryPercent, battStr);
199+
200+
201+
if(hoursChar[0] != displayedChar[0] || hoursChar[1] != displayedChar[1] || minutesChar[0] != displayedChar[2] || minutesChar[1] != displayedChar[3]) {
202+
displayedChar[0] = hoursChar[0];
203+
displayedChar[1] = hoursChar[1];
204+
displayedChar[2] = minutesChar[0];
205+
displayedChar[3] = minutesChar[1];
206+
207+
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
208+
if (hoursChar[0] == '0') {
209+
hoursChar[0] = ' ';
210+
}
211+
}
212+
213+
char timeStr[42];
214+
sprintf(timeStr, "[TIME]#11cc55 %c%c:%c%c:%c%c %s#", hoursChar[0],hoursChar[1],minutesChar[0], minutesChar[1], secondsChar[0], secondsChar[1], ampmChar);
215+
216+
lv_label_set_text(label_time, timeStr);
217+
}
218+
219+
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
220+
221+
char dateStr[38];
222+
sprintf(dateStr, "[DATE]#007fff %s %s %d#", dateTimeController.DayOfWeekShortToString(), dateTimeController.MonthShortToString(), char(day));
223+
lv_label_set_text(label_date, dateStr);
224+
225+
226+
currentYear = year;
227+
currentMonth = month;
228+
currentDayOfWeek = dayOfWeek;
229+
currentDay = day;
230+
}
231+
}
232+
233+
heartbeat = heartRateController.HeartRate();
234+
heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
235+
if(heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) {
236+
char heartbeatBuffer[28];
237+
if(heartbeatRunning.Get())
238+
sprintf(heartbeatBuffer, "[L_HR]#ee3311 %d bpm#", heartbeat.Get());
239+
else
240+
sprintf(heartbeatBuffer, "[L_HR]#ee3311 ---#");
241+
242+
lv_label_set_text(heartbeatValue, heartbeatBuffer);
243+
}
244+
245+
stepCount = motionController.NbSteps();
246+
motionSensorOk = motionController.IsSensorOk();
247+
char stepString[34];
248+
if (stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
249+
sprintf(stepString, "[STEP]#ee3377 %lu steps#", stepCount.Get());
250+
lv_label_set_text(stepValue, stepString);
251+
}
252+
return running;
253+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#pragma once
2+
3+
#include <lvgl/src/lv_core/lv_obj.h>
4+
#include <chrono>
5+
#include <cstdint>
6+
#include <memory>
7+
#include "Screen.h"
8+
#include "ScreenList.h"
9+
#include "components/datetime/DateTimeController.h"
10+
11+
namespace Pinetime {
12+
namespace Controllers {
13+
class Settings;
14+
class Battery;
15+
class Ble;
16+
class NotificationManager;
17+
class HeartRateController;
18+
class MotionController;
19+
}
20+
21+
namespace Applications {
22+
namespace Screens {
23+
24+
class WatchFaceDigital : public Screen {
25+
public:
26+
WatchFaceDigital(DisplayApp* app,
27+
Controllers::DateTime& dateTimeController,
28+
Controllers::Battery& batteryController,
29+
Controllers::Ble& bleController,
30+
Controllers::NotificationManager& notificatioManager,
31+
Controllers::Settings& settingsController,
32+
Controllers::HeartRateController& heartRateController,
33+
Controllers::MotionController& motionController);
34+
~WatchFaceDigital() override;
35+
36+
bool Refresh() override;
37+
38+
void OnObjectEvent(lv_obj_t *pObj, lv_event_t i);
39+
40+
private:
41+
char displayedChar[8];
42+
43+
uint16_t currentYear = 1970;
44+
Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
45+
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
46+
uint8_t currentDay = 0;
47+
48+
DirtyValue<int> batteryPercentRemaining {};
49+
DirtyValue<bool> bleState {};
50+
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime{};
51+
DirtyValue<bool> motionSensorOk {};
52+
DirtyValue<uint32_t> stepCount {};
53+
DirtyValue<uint8_t> heartbeat {};
54+
DirtyValue<bool> heartbeatRunning {};
55+
DirtyValue<bool> notificationState {};
56+
57+
lv_obj_t* label_time;
58+
lv_obj_t* label_date;
59+
lv_obj_t* label_prompt_1;
60+
lv_obj_t* label_prompt_2;
61+
lv_obj_t* backgroundLabel;
62+
lv_obj_t* batteryIcon;
63+
lv_obj_t* bleIcon;
64+
lv_obj_t* batteryPlug;
65+
lv_obj_t* batteryPercent;
66+
lv_obj_t* heartbeatIcon;
67+
lv_obj_t* heartbeatValue;
68+
lv_obj_t* heartbeatBpm;
69+
lv_obj_t* stepValue;
70+
lv_obj_t* notificationIcon;
71+
72+
Controllers::DateTime& dateTimeController;
73+
Controllers::Battery& batteryController;
74+
Controllers::Ble& bleController;
75+
Controllers::NotificationManager& notificatioManager;
76+
Controllers::Settings& settingsController;
77+
Controllers::HeartRateController& heartRateController;
78+
Controllers::MotionController& motionController;
79+
};
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)