Merged upstream
This commit is contained in:
@@ -8,13 +8,18 @@
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp *app) :
|
||||
ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp *app,
|
||||
Pinetime::Controllers::Settings &settingsController) :
|
||||
Screen(app),
|
||||
screens{app, {
|
||||
settingsController{settingsController},
|
||||
screens{app,
|
||||
settingsController.GetAppMenu(),
|
||||
{
|
||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen1(); },
|
||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen2(); },
|
||||
//[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
|
||||
}
|
||||
},
|
||||
Screens::ScreenListModes::UpDown
|
||||
} {}
|
||||
|
||||
|
||||
@@ -51,7 +56,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
|
||||
|
||||
};
|
||||
|
||||
return std::unique_ptr<Screen>(new Screens::Tile(app, applications));
|
||||
return std::unique_ptr<Screen>(new Screens::Tile(0, app, settingsController, applications));
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
||||
@@ -65,7 +70,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
||||
}
|
||||
};
|
||||
|
||||
return std::unique_ptr<Screen>(new Screens::Tile(app, applications));
|
||||
return std::unique_ptr<Screen>(new Screens::Tile(1, app, settingsController, applications));
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> ApplicationList::CreateScreen3() {
|
||||
@@ -79,6 +84,6 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen3() {
|
||||
}
|
||||
};
|
||||
|
||||
return std::unique_ptr<Screen>(new Screens::Tile(app, applications));
|
||||
return std::unique_ptr<Screen>(new Screens::Tile(2, app, settingsController, applications));
|
||||
}
|
||||
|
||||
|
@@ -10,12 +10,16 @@ namespace Pinetime {
|
||||
namespace Screens {
|
||||
class ApplicationList : public Screen {
|
||||
public:
|
||||
explicit ApplicationList(DisplayApp* app);
|
||||
explicit ApplicationList(DisplayApp* app,
|
||||
Pinetime::Controllers::Settings &settingsController);
|
||||
~ApplicationList() override;
|
||||
bool Refresh() override;
|
||||
bool OnButtonPushed() override;
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
private:
|
||||
|
||||
Controllers::Settings& settingsController;
|
||||
|
||||
bool running = true;
|
||||
|
||||
ScreenList<2> screens;
|
||||
|
@@ -10,248 +10,74 @@
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "components/heartrate/HeartRateController.h"
|
||||
#include "../DisplayApp.h"
|
||||
#include "WatchFaceDigital.h"
|
||||
#include "WatchFaceAnalog.h"
|
||||
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
|
||||
char const *DaysString[] = {
|
||||
"",
|
||||
"MONDAY",
|
||||
"TUESDAY",
|
||||
"WEDNESDAY",
|
||||
"THURSDAY",
|
||||
"FRIDAY",
|
||||
"SATURDAY",
|
||||
"SUNDAY"
|
||||
};
|
||||
|
||||
char const *MonthsString[] = {
|
||||
"",
|
||||
"JAN",
|
||||
"FEB",
|
||||
"MAR",
|
||||
"APR",
|
||||
"MAY",
|
||||
"JUN",
|
||||
"JUL",
|
||||
"AUG",
|
||||
"SEP",
|
||||
"OCT",
|
||||
"NOV",
|
||||
"DEC"
|
||||
};
|
||||
|
||||
const char *MonthToString(Pinetime::Controllers::DateTime::Months month) {
|
||||
return MonthsString[static_cast<uint8_t>(month)];
|
||||
}
|
||||
|
||||
const char *DayOfWeekToString(Pinetime::Controllers::DateTime::Days dayOfWeek) {
|
||||
return DaysString[static_cast<uint8_t>(dayOfWeek)];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void event_handler(lv_obj_t * obj, lv_event_t event) {
|
||||
Clock* screen = static_cast<Clock *>(obj->user_data);
|
||||
screen->OnObjectEvent(obj, event);
|
||||
}
|
||||
|
||||
Clock::Clock(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::HeartRateController& heartRateController): Screen(app), currentDateTime{{}},
|
||||
dateTimeController{dateTimeController}, batteryController{batteryController},
|
||||
bleController{bleController}, notificatioManager{notificatioManager},
|
||||
heartRateController{heartRateController} {
|
||||
displayedChar[0] = 0;
|
||||
displayedChar[1] = 0;
|
||||
displayedChar[2] = 0;
|
||||
displayedChar[3] = 0;
|
||||
displayedChar[4] = 0;
|
||||
Controllers::Settings &settingsController,
|
||||
Controllers::HeartRateController& heartRateController) : Screen(app),
|
||||
dateTimeController{dateTimeController}, batteryController{batteryController},
|
||||
bleController{bleController}, notificatioManager{notificatioManager},
|
||||
settingsController{settingsController},
|
||||
heartRateController{heartRateController},
|
||||
screens{app,
|
||||
settingsController.GetClockFace(),
|
||||
{
|
||||
[this]() -> std::unique_ptr<Screen> { return WatchFaceDigitalScreen(); },
|
||||
[this]() -> std::unique_ptr<Screen> { return WatchFaceAnalogScreen(); },
|
||||
// Examples for more watch faces
|
||||
//[this]() -> std::unique_ptr<Screen> { return WatchFaceMinimalScreen(); },
|
||||
//[this]() -> std::unique_ptr<Screen> { return WatchFaceCustomScreen(); }
|
||||
},
|
||||
Screens::ScreenListModes::LongPress
|
||||
} {
|
||||
|
||||
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(batteryIcon, Symbols::batteryFull);
|
||||
lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -5, 2);
|
||||
settingsController.SetAppMenu(0);
|
||||
|
||||
batteryPlug = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(batteryPlug, Symbols::plug);
|
||||
lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
bleIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(bleIcon, Symbols::bluetooth);
|
||||
lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
notificationIcon = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
|
||||
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 10, 0);
|
||||
|
||||
label_date = lv_label_create(lv_scr_act(), nullptr);
|
||||
|
||||
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 60);
|
||||
|
||||
label_time = lv_label_create(lv_scr_act(), nullptr);
|
||||
|
||||
lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed);
|
||||
|
||||
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0);
|
||||
|
||||
backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
backgroundLabel->user_data = this;
|
||||
lv_obj_set_click(backgroundLabel, true);
|
||||
lv_obj_set_event_cb(backgroundLabel, event_handler);
|
||||
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
|
||||
lv_obj_set_size(backgroundLabel, 240, 240);
|
||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||
lv_label_set_text(backgroundLabel, "");
|
||||
|
||||
|
||||
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(heartbeatIcon, Symbols::heartBeat);
|
||||
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
|
||||
|
||||
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(heartbeatValue, "0");
|
||||
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
||||
|
||||
heartbeatBpm = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(heartbeatBpm, "BPM");
|
||||
lv_obj_align(heartbeatBpm, heartbeatValue, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
||||
|
||||
stepValue = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(stepValue, "0");
|
||||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, -2);
|
||||
|
||||
stepIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(stepIcon, Symbols::shoe);
|
||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Clock::~Clock() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
bool Clock::Refresh() {
|
||||
batteryPercentRemaining = batteryController.PercentRemaining();
|
||||
if (batteryPercentRemaining.IsUpdated()) {
|
||||
auto batteryPercent = batteryPercentRemaining.Get();
|
||||
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
|
||||
auto isCharging = batteryController.IsCharging() || batteryController.IsPowerPresent();
|
||||
lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
|
||||
}
|
||||
|
||||
bleState = bleController.IsConnected();
|
||||
if (bleState.IsUpdated()) {
|
||||
if(bleState.Get() == true) {
|
||||
lv_label_set_text(bleIcon, BleIcon::GetIcon(true));
|
||||
} else {
|
||||
lv_label_set_text(bleIcon, BleIcon::GetIcon(false));
|
||||
}
|
||||
}
|
||||
lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -5, 5);
|
||||
lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
||||
if(notificationState.IsUpdated()) {
|
||||
if(notificationState.Get() == true)
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true));
|
||||
else
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
|
||||
}
|
||||
|
||||
currentDateTime = dateTimeController.CurrentDateTime();
|
||||
|
||||
if(currentDateTime.IsUpdated()) {
|
||||
auto newDateTime = currentDateTime.Get();
|
||||
|
||||
auto dp = date::floor<date::days>(newDateTime);
|
||||
auto time = date::make_time(newDateTime-dp);
|
||||
auto yearMonthDay = date::year_month_day(dp);
|
||||
|
||||
auto year = (int)yearMonthDay.year();
|
||||
auto month = static_cast<Pinetime::Controllers::DateTime::Months>((unsigned)yearMonthDay.month());
|
||||
auto day = (unsigned)yearMonthDay.day();
|
||||
auto dayOfWeek = static_cast<Pinetime::Controllers::DateTime::Days>(date::weekday(yearMonthDay).iso_encoding());
|
||||
|
||||
auto hour = time.hours().count();
|
||||
auto minute = time.minutes().count();
|
||||
|
||||
char minutesChar[3];
|
||||
sprintf(minutesChar, "%02d", static_cast<int>(minute));
|
||||
|
||||
char hoursChar[3];
|
||||
sprintf(hoursChar, "%02d", static_cast<int>(hour));
|
||||
|
||||
char timeStr[6];
|
||||
sprintf(timeStr, "%c%c:%c%c", hoursChar[0],hoursChar[1],minutesChar[0], minutesChar[1]);
|
||||
|
||||
if(hoursChar[0] != displayedChar[0] || hoursChar[1] != displayedChar[1] || minutesChar[0] != displayedChar[2] || minutesChar[1] != displayedChar[3]) {
|
||||
displayedChar[0] = hoursChar[0];
|
||||
displayedChar[1] = hoursChar[1];
|
||||
displayedChar[2] = minutesChar[0];
|
||||
displayedChar[3] = minutesChar[1];
|
||||
|
||||
lv_label_set_text(label_time, timeStr);
|
||||
}
|
||||
|
||||
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
|
||||
char dateStr[22];
|
||||
sprintf(dateStr, "%s %d %s %d", DayOfWeekToString(dayOfWeek), day, MonthToString(month), year);
|
||||
lv_label_set_text(label_date, dateStr);
|
||||
|
||||
|
||||
currentYear = year;
|
||||
currentMonth = month;
|
||||
currentDayOfWeek = dayOfWeek;
|
||||
currentDay = day;
|
||||
}
|
||||
}
|
||||
|
||||
heartbeat = heartRateController.HeartRate();
|
||||
heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
|
||||
if(heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) {
|
||||
char heartbeatBuffer[4];
|
||||
if(heartbeatRunning.Get())
|
||||
sprintf(heartbeatBuffer, "%d", heartbeat.Get());
|
||||
else
|
||||
sprintf(heartbeatBuffer, "---");
|
||||
|
||||
lv_label_set_text(heartbeatValue, heartbeatBuffer);
|
||||
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
|
||||
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
||||
lv_obj_align(heartbeatBpm, heartbeatValue, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
||||
}
|
||||
|
||||
// TODO stepCount = stepController.GetValue();
|
||||
if(stepCount.IsUpdated()) {
|
||||
char stepBuffer[5];
|
||||
sprintf(stepBuffer, "%lu", stepCount.Get());
|
||||
lv_label_set_text(stepValue, stepBuffer);
|
||||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, -2);
|
||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
}
|
||||
|
||||
bool Clock::Refresh() {
|
||||
screens.Refresh();
|
||||
return running;
|
||||
}
|
||||
|
||||
|
||||
void Clock::OnObjectEvent(lv_obj_t *obj, lv_event_t event) {
|
||||
if(obj == backgroundLabel) {
|
||||
if (event == LV_EVENT_CLICKED) {
|
||||
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Clock::OnButtonPushed() {
|
||||
running = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
||||
return screens.OnTouchEvent(event);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
|
||||
return std::unique_ptr<Screen>(new Screens::WatchFaceDigital(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController, heartRateController));
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
|
||||
return std::unique_ptr<Screen>(new Screens::WatchFaceAnalog(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController));
|
||||
}
|
||||
|
||||
/*
|
||||
// Examples for more watch faces
|
||||
std::unique_ptr<Screen> Clock::WatchFaceMinimalScreen() {
|
||||
return std::unique_ptr<Screen>(new Screens::WatchFaceMinimal(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController));
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::WatchFaceCustomScreen() {
|
||||
return std::unique_ptr<Screen>(new Screens::WatchFaceCustom(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController));
|
||||
}
|
||||
*/
|
@@ -5,38 +5,22 @@
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "Screen.h"
|
||||
#include "ScreenList.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
class BMA421;
|
||||
}
|
||||
namespace Controllers {
|
||||
class Settings;
|
||||
class Battery;
|
||||
class Ble;
|
||||
class NotificationManager;
|
||||
class HeartRateController;
|
||||
}
|
||||
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
template <class T>
|
||||
class DirtyValue {
|
||||
public:
|
||||
DirtyValue() = default; // Use NSDMI
|
||||
explicit DirtyValue(T const& v):value{v}{} // Use MIL and const-lvalue-ref
|
||||
bool IsUpdated() const { return isUpdated; }
|
||||
T const& Get() { this->isUpdated = false; return value; } // never expose a non-const lvalue-ref
|
||||
DirtyValue& operator=(const T& other) {
|
||||
if (this->value != other) {
|
||||
this->value = other;
|
||||
this->isUpdated = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
T value{}; // NSDMI - default initialise type
|
||||
bool isUpdated{true}; // NSDMI - use brace initilisation
|
||||
};
|
||||
|
||||
class Clock : public Screen {
|
||||
public:
|
||||
Clock(DisplayApp* app,
|
||||
@@ -44,48 +28,32 @@ namespace Pinetime {
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings &settingsController,
|
||||
Controllers::HeartRateController& heartRateController);
|
||||
~Clock() override;
|
||||
|
||||
bool Refresh() override;
|
||||
bool OnButtonPushed() override;
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
void OnObjectEvent(lv_obj_t *pObj, lv_event_t i);
|
||||
private:
|
||||
char displayedChar[5];
|
||||
|
||||
uint16_t currentYear = 1970;
|
||||
Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
|
||||
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
|
||||
uint8_t currentDay = 0;
|
||||
|
||||
DirtyValue<int> batteryPercentRemaining {};
|
||||
DirtyValue<bool> bleState {};
|
||||
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime{};
|
||||
DirtyValue<uint32_t> stepCount {};
|
||||
DirtyValue<uint8_t> heartbeat {};
|
||||
DirtyValue<bool> heartbeatRunning {};
|
||||
DirtyValue<bool> notificationState {};
|
||||
|
||||
lv_obj_t* label_time;
|
||||
lv_obj_t* label_date;
|
||||
lv_obj_t* backgroundLabel;
|
||||
lv_obj_t* batteryIcon;
|
||||
lv_obj_t* bleIcon;
|
||||
lv_obj_t* batteryPlug;
|
||||
lv_obj_t* heartbeatIcon;
|
||||
lv_obj_t* heartbeatValue;
|
||||
lv_obj_t* heartbeatBpm;
|
||||
lv_obj_t* stepIcon;
|
||||
lv_obj_t* stepValue;
|
||||
lv_obj_t* notificationIcon;
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
Controllers::NotificationManager& notificatioManager;
|
||||
Controllers::Settings& settingsController;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
|
||||
|
||||
ScreenList<2> screens;
|
||||
std::unique_ptr<Screen> WatchFaceDigitalScreen();
|
||||
std::unique_ptr<Screen> WatchFaceAnalogScreen();
|
||||
|
||||
// Examples for more watch faces
|
||||
//std::unique_ptr<Screen> WatchFaceMinimalScreen();
|
||||
//std::unique_ptr<Screen> WatchFaceCustomScreen();
|
||||
|
||||
bool running = true;
|
||||
|
||||
};
|
||||
|
@@ -7,6 +7,26 @@ namespace Pinetime {
|
||||
namespace Applications {
|
||||
class DisplayApp;
|
||||
namespace Screens {
|
||||
|
||||
template <class T>
|
||||
class DirtyValue {
|
||||
public:
|
||||
DirtyValue() = default; // Use NSDMI
|
||||
explicit DirtyValue(T const& v):value{v}{} // Use MIL and const-lvalue-ref
|
||||
bool IsUpdated() const { return isUpdated; }
|
||||
T const& Get() { this->isUpdated = false; return value; } // never expose a non-const lvalue-ref
|
||||
DirtyValue& operator=(const T& other) {
|
||||
if (this->value != other) {
|
||||
this->value = other;
|
||||
this->isUpdated = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
T value{}; // NSDMI - default initialise type
|
||||
bool isUpdated{true}; // NSDMI - use brace initilisation
|
||||
};
|
||||
|
||||
class Screen {
|
||||
public:
|
||||
explicit Screen(DisplayApp* app) : app{app} {}
|
||||
|
@@ -9,16 +9,19 @@
|
||||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
enum class ScreenListModes {UpDown, RightLeft, LongPress};
|
||||
template <size_t N>
|
||||
class ScreenList : public Screen {
|
||||
public:
|
||||
ScreenList(DisplayApp* app, std::array<std::function<std::unique_ptr<Screen>()>, N>&& screens)
|
||||
: Screen(app), screens{std::move(screens)}, current{this->screens[0]()} {
|
||||
|
||||
ScreenList(DisplayApp* app, uint8_t initScreen, std::array<std::function<std::unique_ptr<Screen>()>, N>&& screens, ScreenListModes mode)
|
||||
: Screen(app), initScreen{initScreen}, screens{std::move(screens)}, mode{mode}, current{this->screens[initScreen]()} {
|
||||
screenIndex = initScreen;
|
||||
}
|
||||
|
||||
~ScreenList() override {
|
||||
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
bool Refresh() override {
|
||||
@@ -32,34 +35,80 @@ namespace Pinetime {
|
||||
}
|
||||
|
||||
bool OnTouchEvent(TouchEvents event) override {
|
||||
switch (event) {
|
||||
case TouchEvents::SwipeDown:
|
||||
if (screenIndex > 0) {
|
||||
current.reset(nullptr);
|
||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Down);
|
||||
screenIndex--;
|
||||
current = screens[screenIndex]();
|
||||
}
|
||||
return true;
|
||||
case TouchEvents::SwipeUp:
|
||||
if (screenIndex < screens.size() - 1) {
|
||||
current.reset(nullptr);
|
||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up);
|
||||
screenIndex++;
|
||||
current = screens[screenIndex]();
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
if ( mode == ScreenListModes::UpDown) {
|
||||
switch (event) {
|
||||
case TouchEvents::SwipeDown:
|
||||
if (screenIndex > 0) {
|
||||
current.reset(nullptr);
|
||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Down);
|
||||
screenIndex--;
|
||||
current = screens[screenIndex]();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
case TouchEvents::SwipeUp:
|
||||
if (screenIndex < screens.size() - 1) {
|
||||
current.reset(nullptr);
|
||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up);
|
||||
screenIndex++;
|
||||
current = screens[screenIndex]();
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else if ( mode == ScreenListModes::RightLeft) {
|
||||
switch (event) {
|
||||
case TouchEvents::SwipeRight:
|
||||
if (screenIndex > 0) {
|
||||
current.reset(nullptr);
|
||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::None);
|
||||
screenIndex--;
|
||||
current = screens[screenIndex]();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
case TouchEvents::SwipeLeft:
|
||||
if (screenIndex < screens.size() - 1) {
|
||||
current.reset(nullptr);
|
||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::None);
|
||||
screenIndex++;
|
||||
current = screens[screenIndex]();
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else if ( event == TouchEvents::LongTap ) {
|
||||
if (screenIndex < screens.size() - 1) {
|
||||
screenIndex++;
|
||||
} else {
|
||||
screenIndex = 0;
|
||||
}
|
||||
current.reset(nullptr);
|
||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::None);
|
||||
current = screens[screenIndex]();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool running = true;
|
||||
uint8_t screenIndex = 0;
|
||||
|
||||
uint8_t initScreen = 0;
|
||||
std::array<std::function<std::unique_ptr<Screen>()>, N> screens;
|
||||
ScreenListModes mode = ScreenListModes::UpDown;
|
||||
|
||||
uint8_t screenIndex = 0;
|
||||
std::unique_ptr<Screen> current;
|
||||
|
||||
bool running = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -20,11 +20,14 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp *app,
|
||||
Screen(app),
|
||||
dateTimeController{dateTimeController}, batteryController{batteryController},
|
||||
brightnessController{brightnessController}, bleController{bleController}, watchdog{watchdog},
|
||||
screens{app, {
|
||||
screens{app,
|
||||
0,
|
||||
{
|
||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen1(); },
|
||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen2(); },
|
||||
[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
|
||||
}
|
||||
},
|
||||
Screens::ScreenListModes::UpDown
|
||||
} {}
|
||||
|
||||
|
||||
@@ -119,6 +122,6 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen3() {
|
||||
"Public License v3\n"
|
||||
"Source code:\n"
|
||||
"https://github.com/\n"
|
||||
" JF002/Pinetime");
|
||||
" JF002/InfiniTime");
|
||||
return std::unique_ptr<Screen>(new Screens::Label(app, t3));
|
||||
}
|
||||
|
@@ -10,7 +10,10 @@ static void event_handler(lv_obj_t * obj, lv_event_t event) {
|
||||
screen->OnObjectEvent(obj, event, eventData);
|
||||
}
|
||||
|
||||
Tile::Tile(DisplayApp* app, std::array<Applications, 6>& applications) : Screen(app) {
|
||||
Tile::Tile(uint8_t screenID, DisplayApp* app, Controllers::Settings& settingsController, std::array<Applications, 6>& applications) : Screen(app) {
|
||||
|
||||
settingsController.SetAppMenu(screenID);
|
||||
|
||||
for(int i = 0, appIndex = 0; i < 8; i++) {
|
||||
if(i == 3) btnm_map1[i] = "\n";
|
||||
else if(i == 7) btnm_map1[i] = "";
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include <memory>
|
||||
#include "Screen.h"
|
||||
#include "../Apps.h"
|
||||
#include "components/settings/Settings.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
@@ -16,7 +17,7 @@ namespace Pinetime {
|
||||
Pinetime::Applications::Apps application;
|
||||
};
|
||||
|
||||
explicit Tile(DisplayApp* app, std::array<Applications, 6>& applications);
|
||||
explicit Tile(uint8_t screenID, DisplayApp* app, Controllers::Settings& settingsController, std::array<Applications, 6>& applications);
|
||||
~Tile() override;
|
||||
|
||||
bool Refresh() override;
|
||||
|
208
src/displayapp/screens/WatchFaceAnalog.cpp
Normal file
208
src/displayapp/screens/WatchFaceAnalog.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
#include <libs/lvgl/lvgl.h>
|
||||
#include "WatchFaceAnalog.h"
|
||||
#include "BatteryIcon.h"
|
||||
#include "BleIcon.h"
|
||||
#include "Symbols.h"
|
||||
#include "NotificationIcon.h"
|
||||
|
||||
LV_IMG_DECLARE(bg_clock);
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
#define HOUR_LENGTH 70
|
||||
#define MINUTE_LENGTH 90
|
||||
#define SECOND_LENGTH 110
|
||||
#define PI 3.14159265358979323846
|
||||
|
||||
// ##
|
||||
static int16_t coordinate_x_relocate(int16_t x)
|
||||
{
|
||||
return ((x) + LV_HOR_RES / 2);
|
||||
}
|
||||
|
||||
// ##
|
||||
static int16_t coordinate_y_relocate(int16_t y)
|
||||
{
|
||||
return (((y) - LV_HOR_RES / 2) < 0) ? (0 - ((y) - LV_HOR_RES / 2)) : ((y) - LV_HOR_RES / 2);
|
||||
}
|
||||
|
||||
WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp *app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings &settingsController) : Screen(app), currentDateTime{{}},
|
||||
dateTimeController{dateTimeController}, batteryController{batteryController},
|
||||
bleController{bleController}, notificatioManager{notificatioManager},
|
||||
settingsController{settingsController} {
|
||||
settingsController.SetClockFace(1);
|
||||
|
||||
sHour = 99;
|
||||
sMinute = 99;
|
||||
sSecond = 99;
|
||||
|
||||
lv_obj_t * bg_clock_img = lv_img_create(lv_scr_act(), NULL);
|
||||
lv_img_set_src(bg_clock_img, &bg_clock);
|
||||
lv_obj_align(bg_clock_img, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(batteryIcon, Symbols::batteryHalf);
|
||||
lv_obj_align(batteryIcon, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, -8, -4);
|
||||
|
||||
|
||||
notificationIcon = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
|
||||
lv_obj_align(notificationIcon, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 8, -4);
|
||||
|
||||
// Date - Day / Week day
|
||||
|
||||
label_date_day = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xf0a500));
|
||||
lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day());
|
||||
lv_label_set_align( label_date_day, LV_LABEL_ALIGN_CENTER );
|
||||
lv_obj_align(label_date_day, NULL, LV_ALIGN_CENTER, 50, 0);
|
||||
|
||||
minute_body = lv_line_create(lv_scr_act(), NULL);
|
||||
minute_body_trace = lv_line_create(lv_scr_act(), NULL);
|
||||
hour_body = lv_line_create(lv_scr_act(), NULL);
|
||||
hour_body_trace = lv_line_create(lv_scr_act(), NULL);
|
||||
second_body = lv_line_create(lv_scr_act(), NULL);
|
||||
|
||||
|
||||
lv_style_init(&second_line_style);
|
||||
lv_style_set_line_width(&second_line_style, LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_line_color(&second_line_style, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
lv_style_set_line_rounded(&second_line_style, LV_STATE_DEFAULT, true);
|
||||
lv_obj_add_style(second_body, LV_LINE_PART_MAIN, &second_line_style);
|
||||
|
||||
lv_style_init(&minute_line_style);
|
||||
lv_style_set_line_width(&minute_line_style, LV_STATE_DEFAULT, 7);
|
||||
lv_style_set_line_color(&minute_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_style_set_line_rounded(&minute_line_style, LV_STATE_DEFAULT, true);
|
||||
lv_obj_add_style(minute_body, LV_LINE_PART_MAIN, &minute_line_style);
|
||||
|
||||
lv_style_init(&minute_line_style_trace);
|
||||
lv_style_set_line_width(&minute_line_style_trace, LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_line_color(&minute_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_style_set_line_rounded(&minute_line_style_trace, LV_STATE_DEFAULT, false);
|
||||
lv_obj_add_style(minute_body_trace, LV_LINE_PART_MAIN, &minute_line_style_trace);
|
||||
|
||||
|
||||
lv_style_init(&hour_line_style);
|
||||
lv_style_set_line_width(&hour_line_style, LV_STATE_DEFAULT, 7);
|
||||
lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_style_set_line_rounded(&hour_line_style, LV_STATE_DEFAULT, true);
|
||||
lv_obj_add_style(hour_body, LV_LINE_PART_MAIN, &hour_line_style);
|
||||
|
||||
lv_style_init(&hour_line_style_trace);
|
||||
lv_style_set_line_width(&hour_line_style_trace, LV_STATE_DEFAULT, 3);
|
||||
lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_style_set_line_rounded(&hour_line_style_trace, LV_STATE_DEFAULT, false);
|
||||
lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_line_style_trace);
|
||||
|
||||
UpdateClock();
|
||||
|
||||
}
|
||||
|
||||
WatchFaceAnalog::~WatchFaceAnalog() {
|
||||
|
||||
lv_style_reset(&hour_line_style);
|
||||
lv_style_reset(&hour_line_style_trace);
|
||||
lv_style_reset(&minute_line_style);
|
||||
lv_style_reset(&minute_line_style_trace);
|
||||
lv_style_reset(&second_line_style);
|
||||
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
void WatchFaceAnalog::UpdateClock() {
|
||||
|
||||
hour = dateTimeController.Hours();
|
||||
minute = dateTimeController.Minutes();
|
||||
second = dateTimeController.Seconds();
|
||||
|
||||
if(sMinute != minute) {
|
||||
minute_point[0].x = coordinate_x_relocate(30 * sin(minute * 6 * PI / 180));
|
||||
minute_point[0].y = coordinate_y_relocate(30 * cos(minute * 6 * PI / 180));
|
||||
minute_point[1].x = coordinate_x_relocate(MINUTE_LENGTH * sin(minute * 6 * PI / 180));
|
||||
minute_point[1].y = coordinate_y_relocate(MINUTE_LENGTH * cos(minute * 6 * PI / 180));
|
||||
|
||||
minute_point_trace[0].x = coordinate_x_relocate(5 * sin(minute * 6 * PI / 180));
|
||||
minute_point_trace[0].y = coordinate_y_relocate(5 * cos(minute * 6 * PI / 180));
|
||||
minute_point_trace[1].x = coordinate_x_relocate(31 * sin(minute * 6 * PI / 180));
|
||||
minute_point_trace[1].y = coordinate_y_relocate(31 * cos(minute * 6 * PI / 180));
|
||||
|
||||
lv_line_set_points(minute_body, minute_point, 2);
|
||||
lv_line_set_points(minute_body_trace, minute_point_trace, 2);
|
||||
}
|
||||
|
||||
if(sHour != hour || sMinute != minute) {
|
||||
sHour = hour;
|
||||
sMinute = minute;
|
||||
hour_point[0].x = coordinate_x_relocate(30 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point[0].y = coordinate_y_relocate(30 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point[1].x = coordinate_x_relocate(HOUR_LENGTH * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point[1].y = coordinate_y_relocate(HOUR_LENGTH * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
|
||||
hour_point_trace[0].x = coordinate_x_relocate(5 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point_trace[0].y = coordinate_y_relocate(5 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point_trace[1].x = coordinate_x_relocate(31 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
hour_point_trace[1].y = coordinate_y_relocate(31 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
|
||||
|
||||
lv_line_set_points(hour_body, hour_point, 2);
|
||||
lv_line_set_points(hour_body_trace, hour_point_trace, 2);
|
||||
}
|
||||
|
||||
if(sSecond != second) {
|
||||
sSecond = second;
|
||||
second_point[0].x = coordinate_x_relocate(20 * sin((180 + second * 6) * PI / 180));
|
||||
second_point[0].y = coordinate_y_relocate(20 * cos((180 + second * 6) * PI / 180));
|
||||
second_point[1].x = coordinate_x_relocate(SECOND_LENGTH * sin(second * 6 * PI / 180));
|
||||
second_point[1].y = coordinate_y_relocate(SECOND_LENGTH * cos(second * 6 * PI / 180));
|
||||
lv_line_set_points(second_body, second_point, 2);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool WatchFaceAnalog::Refresh() {
|
||||
|
||||
batteryPercentRemaining = batteryController.PercentRemaining();
|
||||
if (batteryPercentRemaining.IsUpdated()) {
|
||||
auto batteryPercent = batteryPercentRemaining.Get();
|
||||
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
|
||||
}
|
||||
|
||||
|
||||
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
||||
|
||||
if(notificationState.IsUpdated()) {
|
||||
if(notificationState.Get() == true)
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true));
|
||||
else
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
|
||||
}
|
||||
|
||||
currentDateTime = dateTimeController.CurrentDateTime();
|
||||
|
||||
if(currentDateTime.IsUpdated()) {
|
||||
|
||||
month = dateTimeController.Month();
|
||||
day = dateTimeController.Day();
|
||||
dayOfWeek = dateTimeController.DayOfWeek();
|
||||
|
||||
UpdateClock();
|
||||
|
||||
if ((month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
|
||||
|
||||
lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), day);
|
||||
|
||||
currentMonth = month;
|
||||
currentDayOfWeek = dayOfWeek;
|
||||
currentDay = day;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
90
src/displayapp/screens/WatchFaceAnalog.h
Normal file
90
src/displayapp/screens/WatchFaceAnalog.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include <lvgl/src/lv_core/lv_obj.h>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "Screen.h"
|
||||
#include "ScreenList.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/ble/NotificationManager.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Settings;
|
||||
class Battery;
|
||||
class Ble;
|
||||
class NotificationManager;
|
||||
}
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class WatchFaceAnalog : public Screen {
|
||||
public:
|
||||
WatchFaceAnalog(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings &settingsController);
|
||||
|
||||
~WatchFaceAnalog() override;
|
||||
|
||||
bool Refresh() override;
|
||||
|
||||
private:
|
||||
uint8_t sHour, sMinute, sSecond;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
|
||||
Pinetime::Controllers::DateTime::Months month;
|
||||
uint8_t day;
|
||||
Pinetime::Controllers::DateTime::Days dayOfWeek;
|
||||
|
||||
Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
|
||||
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
|
||||
uint8_t currentDay = 0;
|
||||
|
||||
DirtyValue<float> batteryPercentRemaining {0};
|
||||
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
|
||||
DirtyValue<bool> notificationState {false};
|
||||
|
||||
lv_obj_t *hour_body;
|
||||
lv_obj_t *hour_body_trace;
|
||||
lv_obj_t *minute_body;
|
||||
lv_obj_t *minute_body_trace;
|
||||
lv_obj_t *second_body;
|
||||
|
||||
// ##
|
||||
lv_point_t hour_point[2];
|
||||
lv_point_t hour_point_trace[2];
|
||||
lv_point_t minute_point[2];
|
||||
lv_point_t minute_point_trace[2];
|
||||
lv_point_t second_point[2];
|
||||
|
||||
// ##
|
||||
lv_style_t hour_line_style;
|
||||
lv_style_t hour_line_style_trace;
|
||||
lv_style_t minute_line_style;
|
||||
lv_style_t minute_line_style_trace;
|
||||
lv_style_t second_line_style;
|
||||
|
||||
lv_obj_t* label_date_day;
|
||||
lv_obj_t* batteryIcon;
|
||||
lv_obj_t* notificationIcon;
|
||||
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
Controllers::NotificationManager& notificatioManager;
|
||||
Controllers::Settings& settingsController;
|
||||
|
||||
void UpdateClock();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
257
src/displayapp/screens/WatchFaceDigital.cpp
Normal file
257
src/displayapp/screens/WatchFaceDigital.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
#include "WatchFaceDigital.h"
|
||||
|
||||
#include <date/date.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <cstdio>
|
||||
#include "BatteryIcon.h"
|
||||
#include "BleIcon.h"
|
||||
#include "NotificationIcon.h"
|
||||
#include "Symbols.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "components/heartrate/HeartRateController.h"
|
||||
#include "components/settings/Settings.h"
|
||||
#include "../DisplayApp.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
|
||||
WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings &settingsController,
|
||||
Controllers::HeartRateController& heartRateController): Screen(app), currentDateTime{{}},
|
||||
dateTimeController{dateTimeController}, batteryController{batteryController},
|
||||
bleController{bleController}, notificatioManager{notificatioManager},
|
||||
settingsController{settingsController},
|
||||
heartRateController{heartRateController} {
|
||||
settingsController.SetClockFace(0);
|
||||
|
||||
displayedChar[0] = 0;
|
||||
displayedChar[1] = 0;
|
||||
displayedChar[2] = 0;
|
||||
displayedChar[3] = 0;
|
||||
displayedChar[4] = 0;
|
||||
|
||||
batteryIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(batteryIcon, Symbols::batteryFull);
|
||||
lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -5, 2);
|
||||
|
||||
batteryPlug = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
|
||||
lv_label_set_text(batteryPlug, Symbols::plug);
|
||||
lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
bleIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0000FF));
|
||||
lv_label_set_text(bleIcon, Symbols::bluetooth);
|
||||
lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
notificationIcon = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
|
||||
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 10, 0);
|
||||
|
||||
label_date = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60);
|
||||
lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
|
||||
|
||||
label_time = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed);
|
||||
|
||||
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0);
|
||||
|
||||
label_time_ampm = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text_static(label_time_ampm, "");
|
||||
lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -30, -55);
|
||||
|
||||
backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_click(backgroundLabel, true);
|
||||
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
|
||||
lv_obj_set_size(backgroundLabel, 240, 240);
|
||||
lv_obj_set_pos(backgroundLabel, 0, 0);
|
||||
lv_label_set_text(backgroundLabel, "");
|
||||
|
||||
|
||||
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text(heartbeatIcon, Symbols::heartBeat);
|
||||
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
|
||||
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
|
||||
|
||||
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
|
||||
lv_label_set_text(heartbeatValue, "---");
|
||||
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
||||
|
||||
heartbeatBpm = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(heartbeatBpm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
|
||||
lv_label_set_text(heartbeatBpm, "BPM");
|
||||
lv_obj_align(heartbeatBpm, heartbeatValue, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
||||
|
||||
stepValue = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
||||
lv_label_set_text(stepValue, "0");
|
||||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, -2);
|
||||
|
||||
stepIcon = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
||||
lv_label_set_text(stepIcon, Symbols::shoe);
|
||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
}
|
||||
|
||||
WatchFaceDigital::~WatchFaceDigital() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
bool WatchFaceDigital::Refresh() {
|
||||
batteryPercentRemaining = batteryController.PercentRemaining();
|
||||
if (batteryPercentRemaining.IsUpdated()) {
|
||||
auto batteryPercent = batteryPercentRemaining.Get();
|
||||
lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent));
|
||||
auto isCharging = batteryController.IsCharging() || batteryController.IsPowerPresent();
|
||||
lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging));
|
||||
}
|
||||
|
||||
bleState = bleController.IsConnected();
|
||||
if (bleState.IsUpdated()) {
|
||||
if(bleState.Get() == true) {
|
||||
lv_label_set_text(bleIcon, BleIcon::GetIcon(true));
|
||||
} else {
|
||||
lv_label_set_text(bleIcon, BleIcon::GetIcon(false));
|
||||
}
|
||||
}
|
||||
lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -5, 5);
|
||||
lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
notificationState = notificatioManager.AreNewNotificationsAvailable();
|
||||
if(notificationState.IsUpdated()) {
|
||||
if(notificationState.Get() == true)
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true));
|
||||
else
|
||||
lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false));
|
||||
}
|
||||
|
||||
currentDateTime = dateTimeController.CurrentDateTime();
|
||||
|
||||
if(currentDateTime.IsUpdated()) {
|
||||
auto newDateTime = currentDateTime.Get();
|
||||
|
||||
auto dp = date::floor<date::days>(newDateTime);
|
||||
auto time = date::make_time(newDateTime-dp);
|
||||
auto yearMonthDay = date::year_month_day(dp);
|
||||
|
||||
auto year = (int)yearMonthDay.year();
|
||||
auto month = static_cast<Pinetime::Controllers::DateTime::Months>((unsigned)yearMonthDay.month());
|
||||
auto day = (unsigned)yearMonthDay.day();
|
||||
auto dayOfWeek = static_cast<Pinetime::Controllers::DateTime::Days>(date::weekday(yearMonthDay).iso_encoding());
|
||||
|
||||
int hour = time.hours().count();
|
||||
auto minute = time.minutes().count();
|
||||
|
||||
char minutesChar[3];
|
||||
sprintf(minutesChar, "%02d", static_cast<int>(minute));
|
||||
|
||||
char hoursChar[3];
|
||||
char ampmChar[3];
|
||||
if ( settingsController.GetClockType() == Controllers::Settings::ClockType::H24 ) {
|
||||
sprintf(hoursChar, "%02d", hour);
|
||||
} else {
|
||||
if (hour == 0 && hour != 12) {
|
||||
hour = 12;
|
||||
sprintf(ampmChar, "AM");
|
||||
}
|
||||
else if (hour == 12 && hour != 0) {
|
||||
hour = 12;
|
||||
sprintf(ampmChar, "PM");
|
||||
}
|
||||
else if (hour < 12 && hour != 0) {
|
||||
sprintf(ampmChar, "AM");
|
||||
}
|
||||
else if (hour > 12 && hour != 0)
|
||||
{
|
||||
hour = hour - 12;
|
||||
sprintf(ampmChar, "PM");
|
||||
}
|
||||
sprintf(hoursChar, "%02d", hour);
|
||||
}
|
||||
|
||||
if(hoursChar[0] != displayedChar[0] || hoursChar[1] != displayedChar[1] || minutesChar[0] != displayedChar[2] || minutesChar[1] != displayedChar[3]) {
|
||||
displayedChar[0] = hoursChar[0];
|
||||
displayedChar[1] = hoursChar[1];
|
||||
displayedChar[2] = minutesChar[0];
|
||||
displayedChar[3] = minutesChar[1];
|
||||
|
||||
char timeStr[6];
|
||||
|
||||
if ( settingsController.GetClockType() == Controllers::Settings::ClockType::H12 ) {
|
||||
lv_label_set_text(label_time_ampm, ampmChar);
|
||||
if ( hoursChar[0] == '0' ) { hoursChar[0] = ' '; }
|
||||
}
|
||||
|
||||
sprintf(timeStr, "%c%c:%c%c", hoursChar[0],hoursChar[1],minutesChar[0], minutesChar[1]);
|
||||
lv_label_set_text(label_time, timeStr);
|
||||
|
||||
if ( settingsController.GetClockType() == Controllers::Settings::ClockType::H12 ) {
|
||||
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0);
|
||||
} else {
|
||||
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
|
||||
char dateStr[22];
|
||||
if ( settingsController.GetClockType() == Controllers::Settings::ClockType::H24 ) {
|
||||
sprintf(dateStr, "%s %d %s %d", dateTimeController.DayOfWeekShortToString(), day, dateTimeController.MonthShortToString(), year);
|
||||
} else {
|
||||
sprintf(dateStr, "%s %s %d %d", dateTimeController.DayOfWeekShortToString(), dateTimeController.MonthShortToString(), day, year);
|
||||
}
|
||||
lv_label_set_text(label_date, dateStr);
|
||||
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60);
|
||||
|
||||
|
||||
currentYear = year;
|
||||
currentMonth = month;
|
||||
currentDayOfWeek = dayOfWeek;
|
||||
currentDay = day;
|
||||
}
|
||||
}
|
||||
|
||||
heartbeat = heartRateController.HeartRate();
|
||||
heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
|
||||
if(heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) {
|
||||
char heartbeatBuffer[4];
|
||||
if(heartbeatRunning.Get())
|
||||
sprintf(heartbeatBuffer, "%d", heartbeat.Get());
|
||||
else
|
||||
sprintf(heartbeatBuffer, "---");
|
||||
|
||||
lv_label_set_text(heartbeatValue, heartbeatBuffer);
|
||||
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
|
||||
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
||||
lv_obj_align(heartbeatBpm, heartbeatValue, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
|
||||
}
|
||||
|
||||
// TODO stepCount = stepController.GetValue();
|
||||
if(stepCount.IsUpdated()) {
|
||||
char stepBuffer[5];
|
||||
sprintf(stepBuffer, "%lu", stepCount.Get());
|
||||
lv_label_set_text(stepValue, stepBuffer);
|
||||
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, -2);
|
||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
}
|
||||
|
||||
return running;
|
||||
}
|
||||
|
||||
|
||||
bool WatchFaceDigital::OnButtonPushed() {
|
||||
running = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
82
src/displayapp/screens/WatchFaceDigital.h
Normal file
82
src/displayapp/screens/WatchFaceDigital.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <lvgl/src/lv_core/lv_obj.h>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "Screen.h"
|
||||
#include "ScreenList.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class Settings;
|
||||
class Battery;
|
||||
class Ble;
|
||||
class NotificationManager;
|
||||
class HeartRateController;
|
||||
}
|
||||
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class WatchFaceDigital : public Screen {
|
||||
public:
|
||||
WatchFaceDigital(DisplayApp* app,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::Battery& batteryController,
|
||||
Controllers::Ble& bleController,
|
||||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings &settingsController,
|
||||
Controllers::HeartRateController& heartRateController);
|
||||
~WatchFaceDigital() override;
|
||||
|
||||
bool Refresh() override;
|
||||
bool OnButtonPushed() override;
|
||||
|
||||
void OnObjectEvent(lv_obj_t *pObj, lv_event_t i);
|
||||
private:
|
||||
|
||||
|
||||
char displayedChar[5];
|
||||
|
||||
uint16_t currentYear = 1970;
|
||||
Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown;
|
||||
Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown;
|
||||
uint8_t currentDay = 0;
|
||||
|
||||
DirtyValue<int> batteryPercentRemaining {};
|
||||
DirtyValue<bool> bleState {};
|
||||
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime{};
|
||||
DirtyValue<uint32_t> stepCount {};
|
||||
DirtyValue<uint8_t> heartbeat {};
|
||||
DirtyValue<bool> heartbeatRunning {};
|
||||
DirtyValue<bool> notificationState {};
|
||||
|
||||
lv_obj_t* label_time;
|
||||
lv_obj_t* label_time_ampm;
|
||||
lv_obj_t* label_date;
|
||||
lv_obj_t* backgroundLabel;
|
||||
lv_obj_t* batteryIcon;
|
||||
lv_obj_t* bleIcon;
|
||||
lv_obj_t* batteryPlug;
|
||||
lv_obj_t* heartbeatIcon;
|
||||
lv_obj_t* heartbeatValue;
|
||||
lv_obj_t* heartbeatBpm;
|
||||
lv_obj_t* stepIcon;
|
||||
lv_obj_t* stepValue;
|
||||
lv_obj_t* notificationIcon;
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
Controllers::Battery& batteryController;
|
||||
Controllers::Ble& bleController;
|
||||
Controllers::NotificationManager& notificatioManager;
|
||||
Controllers::Settings& settingsController;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
|
||||
bool running = true;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user