Skip to content
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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/displayapp/InfiniTimeTheme.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Colors {
static constexpr lv_color_t green = LV_COLOR_MAKE(0x0, 0xb0, 0x0);
static constexpr lv_color_t blue = LV_COLOR_MAKE(0x0, 0x50, 0xff);
static constexpr lv_color_t lightGray = LV_COLOR_MAKE(0xb0, 0xb0, 0xb0);
static constexpr lv_color_t gray = LV_COLOR_MAKE(0x50, 0x50, 0x50);

static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e);
static constexpr lv_color_t bgAlt = LV_COLOR_MAKE(0x38, 0x38, 0x38);
Expand Down
167 changes: 113 additions & 54 deletions src/displayapp/screens/WatchFaceTerminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Contributor

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...

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();
Expand All @@ -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, "");
}
Expand All @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The 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 😛

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe in the theme too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I add it to InfiniTimeTheme.h in this PR, or should that be a seperate PR?

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);
}
}
}
}
18 changes: 12 additions & 6 deletions src/displayapp/screens/WatchFaceTerminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <displayapp/Controllers.h>
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
#include "components/ble/SimpleWeatherService.h"
#include "utility/DirtyValue.h"

namespace Pinetime {
Expand All @@ -30,7 +31,8 @@ namespace Pinetime {
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController);
Controllers::MotionController& motionController,
Controllers::SimpleWeatherService& weatherService);
~WatchFaceTerminal() override;

void Refresh() override;
Expand All @@ -46,16 +48,18 @@ namespace Pinetime {
Utility::DirtyValue<bool> heartbeatRunning {};
Utility::DirtyValue<bool> notificationState {};
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::days>> currentDate;
Utility::DirtyValue<std::optional<Controllers::SimpleWeatherService::CurrentWeather>> currentWeather {};

lv_obj_t* notificationIcon;
lv_obj_t* label_prompt_1;
lv_obj_t* label_time;
lv_obj_t* label_date;
lv_obj_t* label_prompt_1;
lv_obj_t* label_prompt_2;
lv_obj_t* weather;
lv_obj_t* batteryValue;
lv_obj_t* heartbeatValue;
lv_obj_t* stepValue;
lv_obj_t* notificationIcon;
lv_obj_t* heartbeatValue;
lv_obj_t* connectState;
lv_obj_t* label_prompt_2;

Controllers::DateTime& dateTimeController;
const Controllers::Battery& batteryController;
Expand All @@ -64,6 +68,7 @@ namespace Pinetime {
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
Controllers::SimpleWeatherService& weatherService;

lv_task_t* taskRefresh;
};
Expand All @@ -81,7 +86,8 @@ namespace Pinetime {
controllers.notificationManager,
controllers.settingsController,
controllers.heartRateController,
controllers.motionController);
controllers.motionController,
*controllers.weatherController);
};

static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) {
Expand Down
25 changes: 25 additions & 0 deletions src/displayapp/screens/WeatherSymbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,28 @@ const char* Pinetime::Applications::Screens::Symbols::GetCondition(const Pinetim
return "";
}
}

const char* Pinetime::Applications::Screens::Symbols::GetSimpleCondition(const Pinetime::Controllers::SimpleWeatherService::Icons icon) {
switch (icon) {
case Pinetime::Controllers::SimpleWeatherService::Icons::Sun:
return "Clear";
case Pinetime::Controllers::SimpleWeatherService::Icons::CloudsSun:
return "Clouds";
case Pinetime::Controllers::SimpleWeatherService::Icons::Clouds:
return "Clouds";
case Pinetime::Controllers::SimpleWeatherService::Icons::BrokenClouds:
return "Clouds";
case Pinetime::Controllers::SimpleWeatherService::Icons::CloudShowerHeavy:
return "Rain";
case Pinetime::Controllers::SimpleWeatherService::Icons::CloudSunRain:
return "Drizzle";
case Pinetime::Controllers::SimpleWeatherService::Icons::Thunderstorm:
return "Thunder";
case Pinetime::Controllers::SimpleWeatherService::Icons::Snow:
return "Snow";
case Pinetime::Controllers::SimpleWeatherService::Icons::Smog:
return "Mist";
default:
return "";
}
}
1 change: 1 addition & 0 deletions src/displayapp/screens/WeatherSymbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Pinetime {
namespace Symbols {
const char* GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon);
const char* GetCondition(const Pinetime::Controllers::SimpleWeatherService::Icons icon);
const char* GetSimpleCondition(const Pinetime::Controllers::SimpleWeatherService::Icons icon);
}
}
}
Expand Down
Loading