WORKING 35 entries. Will use on trip
This commit is contained in:
parent
8f32478141
commit
e54d78a04b
|
@ -66,7 +66,7 @@ void Pinetime::Controllers::AgendaService::Init() {
|
|||
ASSERT(res == 0);
|
||||
|
||||
m_agenda_times[0] = 1655327841;
|
||||
m_agenda_pieces[0] = "Write AgendaService";
|
||||
m_agenda_pieces[0] = "C++ Fumbling";
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::AgendaService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
|
@ -81,7 +81,7 @@ int Pinetime::Controllers::AgendaService::OnCommand(uint16_t conn_handle, uint16
|
|||
uint8_t itemIndex = (uint8_t) data[0];
|
||||
uint32_t itemTime = ((uint32_t) data[1]) << 24 | ((uint32_t) data[2]) << 16 | ((uint32_t) data[3]) << 8 | ((uint32_t) data[4]);
|
||||
char* sAgendaItem = (char*) &data[5];
|
||||
if (itemIndex <= 15) { // don't allow a buffer overflow
|
||||
if (itemIndex < AGENDA_CAPACITY) { // don't allow a buffer overflow
|
||||
m_agenda_times[itemIndex] = itemTime;
|
||||
// implicit std::string copy/conversion here:
|
||||
m_agenda_pieces[itemIndex] = sAgendaItem;
|
||||
|
@ -93,7 +93,7 @@ int Pinetime::Controllers::AgendaService::OnCommand(uint16_t conn_handle, uint16
|
|||
}
|
||||
|
||||
uint32_t Pinetime::Controllers::AgendaService::getAgendaTime(uint8_t index) {
|
||||
if (index <= 15) {
|
||||
if (index < AGENDA_CAPACITY) {
|
||||
return m_agenda_times[index];
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -101,7 +101,7 @@ uint32_t Pinetime::Controllers::AgendaService::getAgendaTime(uint8_t index) {
|
|||
}
|
||||
|
||||
std::string Pinetime::Controllers::AgendaService::getAgendaPiece(uint8_t index) {
|
||||
if (index <= 15) {
|
||||
if (index < AGENDA_CAPACITY) {
|
||||
return m_agenda_pieces[index];
|
||||
} else {
|
||||
return 0;
|
||||
|
|
|
@ -34,6 +34,8 @@ namespace Pinetime {
|
|||
|
||||
class AgendaService {
|
||||
public:
|
||||
static const uint8_t AGENDA_CAPACITY = 35;
|
||||
|
||||
explicit AgendaService(Pinetime::System::SystemTask& system);
|
||||
|
||||
void Init();
|
||||
|
@ -48,8 +50,8 @@ namespace Pinetime {
|
|||
struct ble_gatt_chr_def characteristicDefinition[2];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint32_t m_agenda_times[16];
|
||||
std::string m_agenda_pieces[16];
|
||||
uint32_t m_agenda_times[AGENDA_CAPACITY];
|
||||
std::string m_agenda_pieces[AGENDA_CAPACITY];
|
||||
|
||||
Pinetime::System::SystemTask& m_system;
|
||||
};
|
||||
|
|
|
@ -325,7 +325,8 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||
notificationManager,
|
||||
settingsController,
|
||||
heartRateController,
|
||||
motionController);
|
||||
motionController,
|
||||
systemTask->nimble().agenda());
|
||||
break;
|
||||
|
||||
case Apps::Error:
|
||||
|
@ -517,6 +518,9 @@ void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
|||
case DisplayApp::FullRefreshDirections::RightAnim:
|
||||
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::RightAnim);
|
||||
break;
|
||||
// case DisplayApp::FullRefreshDirections::None:
|
||||
// lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::None);
|
||||
// break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#include "displayapp/screens/Agenda.h"
|
||||
#include "displayapp/DisplayApp.h"
|
||||
#include "components/ble/AgendaService.h"
|
||||
#include <date/date.h>
|
||||
#include <nrf_log.h>
|
||||
|
||||
using Pinetime::Applications::TouchEvents;
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
@ -11,7 +10,7 @@ using namespace Pinetime::Controllers;
|
|||
Agenda::Agenda(DisplayApp* app, AgendaService& agenda, Controllers::DateTime& dateTimeController) : Screen(app), agendaSvc(agenda), dateTimeController(dateTimeController) {
|
||||
lv_obj_t* alignNextTo = lv_scr_act();
|
||||
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
for (uint8_t i = 0; i < AGENDA_ONSCREEN; ++i) {
|
||||
lv_obj_t* agendaItem = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_label_set_text_static(agendaItem, ".\n.");
|
||||
//lv_label_set_align(agendaItem, LV_LABEL_ALIGN_CENTER);
|
||||
|
@ -25,26 +24,76 @@ Agenda::Agenda(DisplayApp* app, AgendaService& agenda, Controllers::DateTime& da
|
|||
|
||||
pagingOffset = 0;
|
||||
|
||||
Refresh();
|
||||
using namespace date;
|
||||
using namespace std::chrono;
|
||||
|
||||
std::chrono::system_clock::time_point nowTp = dateTimeController.CurrentDateTime();
|
||||
//sys_seconds now = nowTp;
|
||||
|
||||
// Find first entry that is just after the current time (- 5 min)!
|
||||
for (uint8_t i = 0; i < AgendaService::AGENDA_CAPACITY; ++i) {
|
||||
uint32_t time = agendaSvc.getAgendaTime(i);
|
||||
sys_seconds timestamp = sys_days{1970_y/1/1} + seconds{time};
|
||||
|
||||
if (timestamp > nowTp - minutes{5}) {
|
||||
uint8_t positionInPage = i % AGENDA_ONSCREEN;
|
||||
pagingOffset = i - positionInPage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||
Relabel();
|
||||
//Refresh();
|
||||
}
|
||||
|
||||
bool Agenda::OnTouchEvent(TouchEvents event) {
|
||||
// NRF_LOG_INFO("touch");
|
||||
switch (event) {
|
||||
case TouchEvents::SwipeDown:
|
||||
if (pagingOffset >= AGENDA_ONSCREEN) {
|
||||
// NRF_LOG_INFO("swdn");
|
||||
pagingOffset -= AGENDA_ONSCREEN;
|
||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Down);
|
||||
Relabel();
|
||||
}
|
||||
break;
|
||||
|
||||
case TouchEvents::SwipeUp:
|
||||
if (pagingOffset + 2*AGENDA_ONSCREEN <= AgendaService::AGENDA_CAPACITY) {
|
||||
// NRF_LOG_INFO("swup");
|
||||
pagingOffset += AGENDA_ONSCREEN;
|
||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up);
|
||||
Relabel();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Agenda::~Agenda() {
|
||||
lv_task_del(taskRefresh);
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
void Agenda::Refresh() {
|
||||
void Agenda::Relabel() {
|
||||
using namespace date;
|
||||
using namespace std::chrono;
|
||||
std::chrono::system_clock::time_point now = dateTimeController.CurrentDateTime();
|
||||
auto todayDate = floor<date::days>(now);
|
||||
auto nowTimePart = make_time(now - todayDate);
|
||||
//auto nowTimePart = make_time(now - todayDate);
|
||||
|
||||
auto todayYmd = year_month_day(todayDate);
|
||||
//auto todayYmd = year_month_day(todayDate);
|
||||
// NRF_LOG_INFO("date CURRENT %d-%u-%u %ldh%ldh%ld", (int) todayYmd.year(), (unsigned) todayYmd.month(), (unsigned) todayYmd.day(), nowTimePart.hours().count(), nowTimePart.minutes().count(), nowTimePart.seconds().count());
|
||||
|
||||
//std::cout << todayDate << ' ' << nowTimePart << '\n';
|
||||
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
for (uint8_t i = 0; i < AGENDA_ONSCREEN; ++i) {
|
||||
uint8_t itemIdx = i + pagingOffset;
|
||||
uint32_t time = agendaSvc.getAgendaTime(itemIdx);
|
||||
|
||||
|
@ -91,3 +140,8 @@ void Agenda::Refresh() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Refresh seems to refer to re-render, but changing any LVGL widgets triggers a refresh again! */
|
||||
void Agenda::Refresh() {
|
||||
//NRF_LOG_INFO("refr");
|
||||
}
|
||||
|
|
|
@ -1,30 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "components/ble/AgendaService.h"
|
||||
#include "displayapp/DisplayApp.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class AgendaService;
|
||||
class DateTime;
|
||||
}
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
class Agenda : public Screen {
|
||||
public:
|
||||
static const uint8_t AGENDA_ONSCREEN = 5;
|
||||
|
||||
Agenda(DisplayApp* app, Pinetime::Controllers::AgendaService& agendaSvc, Pinetime::Controllers::DateTime &dateTimeController);
|
||||
~Agenda() override;
|
||||
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
||||
void Refresh() override;
|
||||
|
||||
void Relabel();
|
||||
|
||||
private:
|
||||
Pinetime::Controllers::AgendaService& agendaSvc;
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
|
||||
lv_obj_t* agendaItems[4];
|
||||
lv_obj_t* agendaItems[AGENDA_ONSCREEN];
|
||||
uint8_t pagingOffset;
|
||||
|
||||
lv_task_t* taskRefresh;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ Clock::Clock(DisplayApp* app,
|
|||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController)
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::AgendaService& agendaService)
|
||||
: Screen(app),
|
||||
dateTimeController {dateTimeController},
|
||||
batteryController {batteryController},
|
||||
|
@ -31,6 +32,7 @@ Clock::Clock(DisplayApp* app,
|
|||
settingsController {settingsController},
|
||||
heartRateController {heartRateController},
|
||||
motionController {motionController},
|
||||
agendaService {agendaService},
|
||||
screen {[this, &settingsController]() {
|
||||
switch (settingsController.GetClockFace()) {
|
||||
case 0:
|
||||
|
@ -71,7 +73,8 @@ std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
|
|||
notificatioManager,
|
||||
settingsController,
|
||||
heartRateController,
|
||||
motionController);
|
||||
motionController,
|
||||
agendaService);
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Pinetime {
|
|||
class Ble;
|
||||
class NotificationManager;
|
||||
class MotionController;
|
||||
class AgendaService;
|
||||
}
|
||||
|
||||
namespace Applications {
|
||||
|
@ -28,7 +29,8 @@ namespace Pinetime {
|
|||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController);
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::AgendaService& agendaService);
|
||||
~Clock() override;
|
||||
|
||||
bool OnTouchEvent(TouchEvents event) override;
|
||||
|
@ -42,6 +44,7 @@ namespace Pinetime {
|
|||
Controllers::Settings& settingsController;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
Controllers::MotionController& motionController;
|
||||
Controllers::AgendaService& agendaService;
|
||||
|
||||
std::unique_ptr<Screen> screen;
|
||||
std::unique_ptr<Screen> WatchFaceDigitalScreen();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "displayapp/screens/WatchFaceDigital.h"
|
||||
|
||||
#include <nrf_log.h>
|
||||
#include <date/date.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <cstdio>
|
||||
|
@ -22,7 +23,8 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
|
|||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController)
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::AgendaService& agendaService)
|
||||
: Screen(app),
|
||||
currentDateTime {{}},
|
||||
dateTimeController {dateTimeController},
|
||||
|
@ -31,7 +33,8 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
|
|||
notificatioManager {notificatioManager},
|
||||
settingsController {settingsController},
|
||||
heartRateController {heartRateController},
|
||||
motionController {motionController} {
|
||||
motionController {motionController},
|
||||
agendaService {agendaService} {
|
||||
|
||||
batteryIcon.Create(lv_scr_act());
|
||||
lv_obj_align(batteryIcon.GetObject(), lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
||||
|
@ -84,6 +87,19 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
|
|||
lv_label_set_text_static(stepIcon, Symbols::shoe);
|
||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||
|
||||
|
||||
agendaEntries[0] = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(agendaEntries[0], lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||
lv_obj_set_style_local_text_color(agendaEntries[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x332222));
|
||||
lv_label_set_text_static(agendaEntries[0], ".\n.");
|
||||
|
||||
|
||||
agendaEntries[1] = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_align(agendaEntries[1], agendaEntries[0], LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
|
||||
lv_obj_set_style_local_text_color(agendaEntries[1], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x332222));
|
||||
lv_label_set_text_static(agendaEntries[1], ".\n.");
|
||||
|
||||
|
||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||
Refresh();
|
||||
}
|
||||
|
@ -93,6 +109,89 @@ WatchFaceDigital::~WatchFaceDigital() {
|
|||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
void WatchFaceDigital::RefreshMiniAgenda() {
|
||||
using namespace date;
|
||||
using namespace std::chrono;
|
||||
|
||||
// Set our offset to just before the newest event
|
||||
// We only show events destined for today.
|
||||
|
||||
bool found = false;
|
||||
uint8_t firstFutureEvent = 0;
|
||||
|
||||
std::chrono::system_clock::time_point now = dateTimeController.CurrentDateTime();
|
||||
auto today = floor<days>(now);
|
||||
|
||||
// Find first entry that is just after the current time (- 5 min)!
|
||||
for (uint8_t i = 0; i < Pinetime::Controllers::AgendaService::AGENDA_CAPACITY; ++i) {
|
||||
uint32_t time = agendaService.getAgendaTime(i);
|
||||
firstFutureEvent = i;
|
||||
if (time == 0) break;
|
||||
sys_seconds timestamp = sys_days{1970_y/1/1} + seconds{time};
|
||||
sys_days dayOfEvent = floor<days>(timestamp);
|
||||
|
||||
if (dayOfEvent > today) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (timestamp > now) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool suitable[2] = {false, found};
|
||||
|
||||
if (firstFutureEvent != 0) {
|
||||
uint32_t time = agendaService.getAgendaTime(firstFutureEvent - 1);
|
||||
if (time != 0) {
|
||||
sys_seconds timestamp = sys_days{1970_y/1/1} + seconds{time};
|
||||
|
||||
sys_days dayOfEvent = floor<days>(timestamp);
|
||||
|
||||
if (dayOfEvent == today) {
|
||||
suitable[0] = true;
|
||||
}
|
||||
|
||||
}
|
||||
// No earlier events in the day.
|
||||
lv_label_set_text_static(agendaEntries[0], "--h--\n .....");
|
||||
lv_obj_set_style_local_text_color(agendaEntries[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x332222));
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 2; ++i) {
|
||||
if (! suitable[i]) {
|
||||
lv_label_set_text_static(agendaEntries[i], "--h--\n .....");
|
||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x332222));
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t itemIdx = firstFutureEvent - (1 - i);
|
||||
|
||||
uint32_t time = agendaService.getAgendaTime(itemIdx);
|
||||
|
||||
sys_seconds timestamp = sys_days{1970_y/1/1} + seconds{time};
|
||||
//auto timestamp = std::chrono::system_clock::time_point{time * 1s};
|
||||
sys_days agendaDate = floor<days>(timestamp);
|
||||
time_of_day<seconds> agendaTimePart = make_time(timestamp - agendaDate);
|
||||
|
||||
lv_label_set_text_fmt(agendaEntries[i], "%02lldh%02lld\n %s", agendaTimePart.hours().count(), agendaTimePart.minutes().count(), agendaService.getAgendaPiece(itemIdx).data());
|
||||
|
||||
if (timestamp + 30min < now) {
|
||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x334433));
|
||||
} else if (timestamp + 5min < now) {
|
||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
||||
} else if (timestamp - 5min < now && now < timestamp + 5min) {
|
||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFA500));
|
||||
} else if (now + 5min < timestamp) {
|
||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFF00));
|
||||
} else if (now + 30min < timestamp) {
|
||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WatchFaceDigital::Refresh() {
|
||||
powerPresent = batteryController.IsPowerPresent();
|
||||
if (powerPresent.IsUpdated()) {
|
||||
|
@ -136,6 +235,8 @@ void WatchFaceDigital::Refresh() {
|
|||
uint8_t minute = time.minutes().count();
|
||||
|
||||
if (displayedHour != hour || displayedMinute != minute) {
|
||||
RefreshMiniAgenda();
|
||||
|
||||
displayedHour = hour;
|
||||
displayedMinute = minute;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Pinetime {
|
|||
class NotificationManager;
|
||||
class HeartRateController;
|
||||
class MotionController;
|
||||
class AgendaService;
|
||||
}
|
||||
|
||||
namespace Applications {
|
||||
|
@ -31,11 +32,14 @@ namespace Pinetime {
|
|||
Controllers::NotificationManager& notificatioManager,
|
||||
Controllers::Settings& settingsController,
|
||||
Controllers::HeartRateController& heartRateController,
|
||||
Controllers::MotionController& motionController);
|
||||
Controllers::MotionController& motionController,
|
||||
Controllers::AgendaService& agendaService);
|
||||
~WatchFaceDigital() override;
|
||||
|
||||
void Refresh() override;
|
||||
|
||||
void RefreshMiniAgenda();
|
||||
|
||||
private:
|
||||
uint8_t displayedHour = -1;
|
||||
uint8_t displayedMinute = -1;
|
||||
|
@ -67,6 +71,8 @@ namespace Pinetime {
|
|||
lv_obj_t* stepValue;
|
||||
lv_obj_t* notificationIcon;
|
||||
|
||||
lv_obj_t* agendaEntries[2];
|
||||
|
||||
BatteryIcon batteryIcon;
|
||||
|
||||
Controllers::DateTime& dateTimeController;
|
||||
|
@ -76,6 +82,7 @@ namespace Pinetime {
|
|||
Controllers::Settings& settingsController;
|
||||
Controllers::HeartRateController& heartRateController;
|
||||
Controllers::MotionController& motionController;
|
||||
Controllers::AgendaService& agendaService;
|
||||
|
||||
lv_task_t* taskRefresh;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue