-
-
Notifications
You must be signed in to change notification settings - Fork 947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Terminal Watchface Improvements and added Weather. #2001
base: main
Are you sure you want to change the base?
Changes from all commits
5508615
53c53c6
faae3e0
833b8d6
1189053
3341247
b30f6c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,65 +2,90 @@ | |
#include "displayapp/screens/WatchFaceTerminal.h" | ||
#include "displayapp/screens/BatteryIcon.h" | ||
#include "displayapp/screens/NotificationIcon.h" | ||
#include "displayapp/screens/Symbols.h" | ||
#include "components/battery/BatteryController.h" | ||
#include "components/ble/BleController.h" | ||
#include "components/ble/NotificationManager.h" | ||
#include "components/ble/SimpleWeatherService.h" | ||
#include "components/heartrate/HeartRateController.h" | ||
#include "components/motion/MotionController.h" | ||
#include "components/settings/Settings.h" | ||
#include "displayapp/screens/WeatherSymbols.h" | ||
#include "displayapp/InfiniTimeTheme.h" | ||
|
||
using namespace Pinetime::Applications::Screens; | ||
|
||
namespace { | ||
lv_color_t temperatureColor(int16_t temperature) { | ||
if (temperature <= 0) { // freezing | ||
return Colors::blue; | ||
} else if (temperature <= 400) { // ice | ||
return LV_COLOR_CYAN; | ||
} else if (temperature >= 2700) { // hot | ||
return Colors::deepOrange; | ||
} | ||
return Colors::orange; // normal | ||
} | ||
} | ||
|
||
WatchFaceTerminal::WatchFaceTerminal(Controllers::DateTime& dateTimeController, | ||
const Controllers::Battery& batteryController, | ||
const Controllers::Ble& bleController, | ||
Controllers::NotificationManager& notificationManager, | ||
Controllers::Settings& settingsController, | ||
Controllers::HeartRateController& heartRateController, | ||
Controllers::MotionController& motionController) | ||
Controllers::MotionController& motionController, | ||
Controllers::SimpleWeatherService& weatherService) | ||
: currentDateTime {{}}, | ||
dateTimeController {dateTimeController}, | ||
batteryController {batteryController}, | ||
bleController {bleController}, | ||
notificationManager {notificationManager}, | ||
settingsController {settingsController}, | ||
heartRateController {heartRateController}, | ||
motionController {motionController} { | ||
batteryValue = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(batteryValue, true); | ||
lv_obj_align(batteryValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20); | ||
|
||
connectState = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(connectState, true); | ||
lv_obj_align(connectState, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40); | ||
motionController {motionController}, | ||
weatherService {weatherService} { | ||
|
||
notificationIcon = lv_label_create(lv_scr_act(), nullptr); | ||
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_LEFT_MID, 0, -100); | ||
|
||
label_date = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(label_date, true); | ||
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -40); | ||
|
||
label_prompt_1 = lv_label_create(lv_scr_act(), nullptr); | ||
lv_obj_set_style_local_text_color(label_prompt_1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); | ||
lv_obj_align(label_prompt_1, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -80); | ||
lv_label_set_text_static(label_prompt_1, "user@watch:~ $ now"); | ||
|
||
label_prompt_2 = lv_label_create(lv_scr_act(), nullptr); | ||
lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 60); | ||
lv_label_set_text_static(label_prompt_2, "user@watch:~ $"); | ||
|
||
label_time = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(label_time, true); | ||
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -60); | ||
|
||
heartbeatValue = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(heartbeatValue, true); | ||
lv_obj_align(heartbeatValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 20); | ||
label_date = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(label_date, true); | ||
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -40); | ||
|
||
weather = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(weather, true); | ||
lv_obj_align(weather, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20); | ||
|
||
batteryValue = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(batteryValue, true); | ||
lv_obj_align(batteryValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0); | ||
|
||
stepValue = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(stepValue, true); | ||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0); | ||
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange); | ||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 20); | ||
|
||
heartbeatValue = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(heartbeatValue, true); | ||
lv_obj_align(heartbeatValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40); | ||
|
||
connectState = lv_label_create(lv_scr_act(), nullptr); | ||
lv_label_set_recolor(connectState, true); | ||
lv_obj_align(connectState, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 60); | ||
|
||
label_prompt_2 = lv_label_create(lv_scr_act(), nullptr); | ||
lv_obj_set_style_local_text_color(label_prompt_2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); | ||
lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 80); | ||
lv_label_set_text_static(label_prompt_2, "user@watch:~ $"); | ||
|
||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); | ||
Refresh(); | ||
|
@@ -72,33 +97,10 @@ WatchFaceTerminal::~WatchFaceTerminal() { | |
} | ||
|
||
void WatchFaceTerminal::Refresh() { | ||
powerPresent = batteryController.IsPowerPresent(); | ||
batteryPercentRemaining = batteryController.PercentRemaining(); | ||
if (batteryPercentRemaining.IsUpdated() || powerPresent.IsUpdated()) { | ||
lv_label_set_text_fmt(batteryValue, "[BATT]#387b54 %d%%", batteryPercentRemaining.Get()); | ||
if (batteryController.IsPowerPresent()) { | ||
lv_label_ins_text(batteryValue, LV_LABEL_POS_LAST, " Charging"); | ||
} | ||
} | ||
|
||
bleState = bleController.IsConnected(); | ||
bleRadioEnabled = bleController.IsRadioEnabled(); | ||
if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { | ||
if (!bleRadioEnabled.Get()) { | ||
lv_label_set_text_static(connectState, "[STAT]#0082fc Disabled#"); | ||
} else { | ||
if (bleState.Get()) { | ||
lv_label_set_text_static(connectState, "[STAT]#0082fc Connected#"); | ||
} else { | ||
lv_label_set_text_static(connectState, "[STAT]#0082fc Disconnected#"); | ||
} | ||
} | ||
} | ||
|
||
notificationState = notificationManager.AreNewNotificationsAvailable(); | ||
if (notificationState.IsUpdated()) { | ||
if (notificationState.Get()) { | ||
lv_label_set_text_static(notificationIcon, "You have mail."); | ||
lv_label_set_text_static(notificationIcon, "[1]+ Notify"); | ||
} else { | ||
lv_label_set_text_static(notificationIcon, ""); | ||
} | ||
|
@@ -120,32 +122,89 @@ void WatchFaceTerminal::Refresh() { | |
hour = hour - 12; | ||
ampmChar[0] = 'P'; | ||
} | ||
lv_label_set_text_fmt(label_time, "[TIME]#11cc55 %02d:%02d:%02d %s#", hour, minute, second, ampmChar); | ||
lv_label_set_text_fmt(label_time, "#fffff [TIME]# #11cc55 %02d:%02d:%02d %s#", hour, minute, second, ampmChar); | ||
} else { | ||
lv_label_set_text_fmt(label_time, "[TIME]#11cc55 %02d:%02d:%02d", hour, minute, second); | ||
lv_label_set_text_fmt(label_time, "#ffffff [TIME]# #11cc55 %02d:%02d:%02d#", hour, minute, second); | ||
} | ||
|
||
currentDate = std::chrono::time_point_cast<std::chrono::days>(currentDateTime.Get()); | ||
if (currentDate.IsUpdated()) { | ||
uint16_t year = dateTimeController.Year(); | ||
Controllers::DateTime::Months month = dateTimeController.Month(); | ||
uint8_t day = dateTimeController.Day(); | ||
lv_label_set_text_fmt(label_date, "[DATE]#007fff %04d-%02d-%02d#", short(year), char(month), char(day)); | ||
lv_label_set_text_fmt(label_date, "#ffffff [DATE]# #007fff %04d-%02d-%02d#", short(year), char(month), char(day)); | ||
} | ||
} | ||
|
||
currentWeather = weatherService.Current(); | ||
if (currentWeather.IsUpdated()) { | ||
auto optCurrentWeather = currentWeather.Get(); | ||
if (optCurrentWeather) { | ||
int16_t temp = optCurrentWeather->temperature; | ||
char tempUnit = 'C'; | ||
lv_obj_set_style_local_text_color(weather, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, temperatureColor(temp)); | ||
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { | ||
temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp); | ||
tempUnit = 'F'; | ||
} | ||
lv_label_set_text_fmt(weather, | ||
"#ffffff [WTHR]# %i°%c %s ", | ||
temp / 100, | ||
tempUnit, | ||
Symbols::GetSimpleCondition(optCurrentWeather->iconId)); | ||
} else { | ||
lv_label_set_text(weather, "#ffffff [WTHR]# ---"); | ||
lv_obj_set_style_local_text_color(weather, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray); | ||
} | ||
} | ||
|
||
powerPresent = batteryController.IsPowerPresent(); | ||
batteryPercentRemaining = batteryController.PercentRemaining(); | ||
if (batteryPercentRemaining.IsUpdated() || powerPresent.IsUpdated()) { | ||
// HSV color model has red at 0° and green at 120°. | ||
// We lock satuation and brightness at 100% and traverse the cilinder | ||
// between red and green, thus avoiding the darker RGB on medium battery | ||
// charges and giving us a much nicer color range. | ||
uint8_t hue = batteryPercentRemaining.Get() * 120 / 100; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any chance this can live elsewhere and we can reuse it here? Not super important, since my color PR may not ever be merged though 😛 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe in the theme too? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should I add it to |
||
lv_obj_set_style_local_text_color(batteryValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(hue, 100, 100)); | ||
lv_label_set_text_fmt(batteryValue, "#ffffff [BATT]# %d%%", batteryPercentRemaining.Get()); | ||
if (batteryController.IsCharging()) { | ||
lv_label_ins_text(batteryValue, LV_LABEL_POS_LAST, " Charging"); | ||
} | ||
} | ||
|
||
stepCount = motionController.NbSteps(); | ||
if (stepCount.IsUpdated()) { | ||
lv_label_set_text_fmt(stepValue, "#ffffff [STEP]# %lu steps", stepCount.Get()); | ||
} | ||
|
||
heartbeat = heartRateController.HeartRate(); | ||
heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; | ||
if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) { | ||
if (heartbeatRunning.Get()) { | ||
lv_label_set_text_fmt(heartbeatValue, "[L_HR]#ee3311 %d bpm#", heartbeat.Get()); | ||
|
||
lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::deepOrange); | ||
lv_label_set_text_fmt(heartbeatValue, "#ffffff [L_HR]# %d bpm", heartbeat.Get()); | ||
} else { | ||
lv_label_set_text_static(heartbeatValue, "[L_HR]#ee3311 ---#"); | ||
lv_label_set_text_static(heartbeatValue, "#ffffff [L_HR]# ---"); | ||
lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray); | ||
} | ||
} | ||
|
||
stepCount = motionController.NbSteps(); | ||
if (stepCount.IsUpdated()) { | ||
lv_label_set_text_fmt(stepValue, "[STEP]#ee3377 %lu steps#", stepCount.Get()); | ||
bleState = bleController.IsConnected(); | ||
bleRadioEnabled = bleController.IsRadioEnabled(); | ||
if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { | ||
if (!bleRadioEnabled.Get()) { | ||
lv_label_set_text_static(connectState, "#ffffff [STAT]# Disabled"); | ||
lv_obj_set_style_local_text_color(connectState, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray); | ||
} else { | ||
if (bleState.Get()) { | ||
lv_label_set_text_static(connectState, "#ffffff [STAT]# Connected"); | ||
lv_obj_set_style_local_text_color(connectState, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::blue); | ||
} else { | ||
lv_label_set_text_static(connectState, "#ffffff [STAT]# Disconnected"); | ||
lv_obj_set_style_local_text_color(connectState, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::gray); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes me think that we can make this part of the InfiniTimeTheme...