Skip to content

Commit cb9e881

Browse files
authored
Merge pull request #108 from JF002/notification-ui
Improved notification UI
2 parents c5bf09d + 7de43a1 commit cb9e881

16 files changed

Lines changed: 423 additions & 74 deletions

src/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ set(LVGL_SRC
289289
libs/lvgl/src/lv_objx/lv_slider.c
290290
libs/lvgl/src/lv_objx/lv_ddlist.c
291291
libs/lvgl/src/lv_objx/lv_ddlist.h
292+
libs/lvgl/src/lv_objx/lv_line.c
293+
libs/lvgl/src/lv_objx/lv_line.h
292294
)
293295

294296
list(APPEND IMAGE_FILES
@@ -335,13 +337,15 @@ list(APPEND SOURCE_FILES
335337
displayapp/screens/Modal.cpp
336338
displayapp/screens/BatteryIcon.cpp
337339
displayapp/screens/BleIcon.cpp
340+
displayapp/screens/NotificationIcon.cpp
338341
displayapp/screens/Brightness.cpp
339342
displayapp/screens/SystemInfo.cpp
340343
displayapp/screens/Label.cpp
341344
displayapp/screens/FirmwareUpdate.cpp
342345
displayapp/screens/Music.cpp
343346
displayapp/screens/FirmwareValidation.cpp
344347
displayapp/screens/ApplicationList.cpp
348+
displayapp/screens/Notifications.cpp
345349
main.cpp
346350
drivers/St7789.cpp
347351
drivers/SpiNorFlash.cpp
@@ -412,7 +416,8 @@ set(INCLUDE_FILES
412416
displayapp/screens/DropDownDemo.h
413417
displayapp/screens/Modal.h
414418
displayapp/screens/BatteryIcon.h
415-
displayapp/screens/BleIcon.cpp
419+
displayapp/screens/BleIcon.h
420+
displayapp/screens/NotificationIcon.h
416421
displayapp/screens/Brightness.h
417422
displayapp/screens/SystemInfo.h
418423
displayapp/screens/ScreenList.h
@@ -421,6 +426,7 @@ set(INCLUDE_FILES
421426
displayapp/screens/FirmwareValidation.h
422427
displayapp/screens/ApplicationList.h
423428
displayapp/Apps.h
429+
displayapp/screens/Notifications.h
424430
drivers/St7789.h
425431
drivers/SpiNorFlash.h
426432
drivers/SpiMaster.h

src/components/ble/AlertNotificationClient.cpp

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -105,25 +105,21 @@ int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connect
105105

106106
void AlertNotificationClient::OnNotification(ble_gap_event *event) {
107107
if(event->notify_rx.attr_handle == newAlertHandle) {
108-
// TODO implement this with more memory safety (and constexpr)
109-
static const size_t maxBufferSize{21};
110-
static const size_t maxMessageSize{18};
111-
size_t bufferSize = min(OS_MBUF_PKTLEN(event->notify_rx.om), maxBufferSize);
108+
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
109+
constexpr size_t headerSize = 3;
110+
const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
111+
const auto maxBufferSize{maxMessageSize + headerSize};
112112

113-
uint8_t data[bufferSize];
114-
os_mbuf_copydata(event->notify_rx.om, 0, bufferSize, data);
113+
const auto dbgPacketLen = OS_MBUF_PKTLEN(event->notify_rx.om);
114+
size_t bufferSize = min(dbgPacketLen + stringTerminatorSize, maxBufferSize);
115+
auto messageSize = min(maxMessageSize, (bufferSize-headerSize));
115116

116-
char *s = (char *) &data[3];
117-
auto messageSize = min(maxMessageSize, (bufferSize-3));
117+
NotificationManager::Notification notif;
118+
os_mbuf_copydata(event->notify_rx.om, headerSize, messageSize-1, notif.message.data());
119+
notif.message[messageSize-1] = '\0';
120+
notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert;
121+
notificationManager.Push(std::move(notif));
118122

119-
for (uint i = 0; i < messageSize-1; i++) {
120-
if (s[i] == 0x00) {
121-
s[i] = 0x0A;
122-
}
123-
}
124-
s[messageSize-1] = '\0';
125-
126-
notificationManager.Push(Pinetime::Controllers::NotificationManager::Categories::SimpleAlert, s, messageSize);
127123
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
128124
}
129125
}

src/components/ble/AlertNotificationService.cpp

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ AlertNotificationService::AlertNotificationService ( System::SystemTask& systemT
3838
0
3939
}
4040
},
41-
serviceDefinition{
41+
serviceDefinition{
4242
{
4343
/* Device Information Service */
4444
.type = BLE_GATT_SVC_TYPE_PRIMARY,
@@ -48,33 +48,28 @@ AlertNotificationService::AlertNotificationService ( System::SystemTask& systemT
4848
{
4949
0
5050
},
51-
}, m_systemTask{systemTask}, m_notificationManager{notificationManager} {
51+
}, systemTask{systemTask}, notificationManager{notificationManager} {
5252
}
5353

5454
int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle,
5555
struct ble_gatt_access_ctxt *ctxt) {
56-
5756
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
58-
// TODO implement this with more memory safety (and constexpr)
59-
static const size_t maxBufferSize{21};
60-
static const size_t maxMessageSize{18};
61-
size_t bufferSize = min(OS_MBUF_PKTLEN(ctxt->om), maxBufferSize);
62-
63-
uint8_t data[bufferSize];
64-
os_mbuf_copydata(ctxt->om, 0, bufferSize, data);
57+
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
58+
constexpr size_t headerSize = 3;
59+
const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
60+
const auto maxBufferSize{maxMessageSize + headerSize};
6561

66-
char *s = (char *) &data[3];
67-
auto messageSize = min(maxMessageSize, (bufferSize-3));
62+
const auto dbgPacketLen = OS_MBUF_PKTLEN(ctxt->om);
63+
size_t bufferSize = min(dbgPacketLen + stringTerminatorSize, maxBufferSize);
64+
auto messageSize = min(maxMessageSize, (bufferSize-headerSize));
6865

69-
for (uint i = 0; i < messageSize-1; i++) {
70-
if (s[i] == 0x00) {
71-
s[i] = 0x0A;
72-
}
73-
}
74-
s[messageSize-1] = '\0';
66+
NotificationManager::Notification notif;
67+
os_mbuf_copydata(ctxt->om, headerSize, messageSize-1, notif.message.data());
68+
notif.message[messageSize-1] = '\0';
69+
notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert;
70+
notificationManager.Push(std::move(notif));
7571

76-
m_notificationManager.Push(Pinetime::Controllers::NotificationManager::Categories::SimpleAlert, s, messageSize);
77-
m_systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
72+
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
7873
}
7974
return 0;
8075
}

src/components/ble/AlertNotificationService.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ namespace Pinetime {
3232
struct ble_gatt_chr_def characteristicDefinition[2];
3333
struct ble_gatt_svc_def serviceDefinition[2];
3434

35-
Pinetime::System::SystemTask &m_systemTask;
36-
NotificationManager &m_notificationManager;
35+
Pinetime::System::SystemTask &systemTask;
36+
NotificationManager &notificationManager;
3737
};
3838
}
3939
}

src/components/ble/ImmediateAlertService.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <systemtask/SystemTask.h>
2+
#include <cstring>
23
#include "ImmediateAlertService.h"
34
#include "AlertNotificationService.h"
45

@@ -67,7 +68,12 @@ int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16
6768
if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
6869
auto alertLevel = static_cast<Levels>(context->om->om_data[0]);
6970
auto* alertString = ToString(alertLevel);
70-
notificationManager.Push(Pinetime::Controllers::NotificationManager::Categories::SimpleAlert, alertString, strlen(alertString));
71+
72+
NotificationManager::Notification notif;
73+
std::memcpy(notif.message.data(), alertString, strlen(alertString));
74+
notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert;
75+
notificationManager.Push(std::move(notif));
76+
7177
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
7278
}
7379
}
Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,81 @@
11
#include <cstring>
2+
#include <algorithm>
23
#include "NotificationManager.h"
34

45
using namespace Pinetime::Controllers;
56

6-
void NotificationManager::Push(Pinetime::Controllers::NotificationManager::Categories category,
7-
const char *message, uint8_t currentMessageSize) {
8-
// TODO handle edge cases on read/write index
9-
auto checkedSize = std::min(currentMessageSize, uint8_t{18});
10-
auto& notif = notifications[writeIndex];
11-
std::memcpy(notif.message.data(), message, checkedSize);
12-
notif.message[checkedSize] = '\0';
13-
notif.category = category;
7+
constexpr uint8_t NotificationManager::MessageSize;
148

9+
10+
void NotificationManager::Push(NotificationManager::Notification &&notif) {
11+
notif.id = GetNextId();
12+
notif.valid = true;
13+
notifications[writeIndex] = std::move(notif);
1514
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
16-
if(!empty && writeIndex == readIndex)
17-
readIndex = writeIndex + 1;
15+
if(!empty)
16+
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
17+
else empty = false;
18+
19+
newNotification = true;
1820
}
1921

20-
NotificationManager::Notification Pinetime::Controllers::NotificationManager::Pop() {
21-
// TODO handle edge cases on read/write index
22+
NotificationManager::Notification NotificationManager::GetLastNotification() {
2223
NotificationManager::Notification notification = notifications[readIndex];
24+
notification.index = 1;
25+
return notification;
26+
}
2327

24-
if(readIndex != writeIndex) {
25-
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
26-
}
28+
NotificationManager::Notification::Id NotificationManager::GetNextId() {
29+
return nextId++;
30+
}
2731

28-
// TODO Check move optimization on return
29-
return notification;
32+
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) {
33+
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;});
34+
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
35+
36+
auto& lastNotification = notifications[readIndex];
37+
38+
NotificationManager::Notification result;
39+
40+
if(currentIterator == (notifications.end()-1))
41+
result = *(notifications.begin());
42+
else
43+
result = *(currentIterator+1);
44+
45+
if(result.id <= id) return {};
46+
47+
result.index = (lastNotification.id - result.id)+1;
48+
return result;
3049
}
50+
51+
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) {
52+
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;});
53+
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
54+
55+
auto& lastNotification = notifications[readIndex];
56+
57+
NotificationManager::Notification result;
58+
59+
if(currentIterator == notifications.begin())
60+
result = *(notifications.end()-1);
61+
else
62+
result = *(currentIterator-1);
63+
64+
if(result.id >= id) return {};
65+
66+
result.index = (lastNotification.id - result.id)+1;
67+
return result;
68+
}
69+
70+
bool NotificationManager::AreNewNotificationsAvailable() {
71+
return newNotification;
72+
}
73+
74+
bool NotificationManager::ClearNewNotificationFlag() {
75+
return newNotification.exchange(false);
76+
}
77+
78+
size_t NotificationManager::NbNotifications() const {
79+
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n){ return n.valid;});
80+
}
81+
Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,43 @@
11
#pragma once
22

33
#include <array>
4+
#include <atomic>
45

56
namespace Pinetime {
67
namespace Controllers {
78
class NotificationManager {
89
public:
910
enum class Categories {Unknown, SimpleAlert, Email, News, IncomingCall, MissedCall, Sms, VoiceMail, Schedule, HighProriotyAlert, InstantMessage };
10-
static constexpr uint8_t MessageSize{18};
11+
static constexpr uint8_t MessageSize{100};
1112

1213
struct Notification {
14+
using Id = uint8_t;
15+
Id id;
16+
bool valid = false;
17+
uint8_t index;
1318
std::array<char, MessageSize+1> message;
1419
Categories category = Categories::Unknown;
1520
};
21+
Notification::Id nextId {0};
1622

17-
void Push(Categories category, const char* message, uint8_t messageSize);
18-
Notification Pop();
23+
void Push(Notification&& notif);
24+
Notification GetLastNotification();
25+
Notification GetNext(Notification::Id id);
26+
Notification GetPrevious(Notification::Id id);
27+
bool ClearNewNotificationFlag();
28+
bool AreNewNotificationsAvailable();
1929

30+
static constexpr uint8_t MaximumMessageSize() { return MessageSize; };
31+
size_t NbNotifications() const;
2032

2133
private:
34+
Notification::Id GetNextId();
2235
static constexpr uint8_t TotalNbNotifications = 5;
2336
std::array<Notification, TotalNbNotifications> notifications;
2437
uint8_t readIndex = 0;
2538
uint8_t writeIndex = 0;
2639
bool empty = true;
40+
std::atomic<bool> newNotification{false};
2741
};
2842
}
2943
}

src/displayapp/Apps.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
namespace Pinetime {
44
namespace Applications {
5-
enum class Apps {None, Launcher, Clock, SysInfo, Meter, Gauge, Brightness, Music, FirmwareValidation, Paint};
5+
enum class Apps {None, Launcher, Clock, SysInfo, Meter, Gauge, Brightness, Music, FirmwareValidation, Paint, Notifications};
66
}
77
}

src/displayapp/DisplayApp.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <queue.h>
99
#include "components/datetime/DateTimeController.h"
1010
#include <drivers/Cst816s.h>
11+
#include "displayapp/screens/Notifications.h"
1112
#include "displayapp/screens/Tile.h"
1213
#include "displayapp/screens/Meter.h"
1314
#include "displayapp/screens/Gauge.h"
@@ -35,7 +36,7 @@ DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Driver
3536
dateTimeController{dateTimeController},
3637
watchdog{watchdog},
3738
touchPanel{touchPanel},
38-
currentScreen{new Screens::Clock(this, dateTimeController, batteryController, bleController) },
39+
currentScreen{new Screens::Clock(this, dateTimeController, batteryController, bleController, notificationManager) },
3940
systemTask{systemTask},
4041
notificationManager{notificationManager} {
4142
msgQueue = xQueueCreate(queueSize, itemSize);
@@ -114,8 +115,12 @@ void DisplayApp::Refresh() {
114115
// clockScreen.SetBatteryPercentRemaining(batteryController.PercentRemaining());
115116
break;
116117
case Messages::NewNotification: {
117-
auto notification = notificationManager.Pop();
118-
modal->Show(notification.message.data());
118+
if(onClockApp) {
119+
currentScreen.reset(nullptr);
120+
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Up);
121+
onClockApp = false;
122+
currentScreen.reset(new Screens::Notifications(this, notificationManager, Screens::Notifications::Modes::Preview));
123+
}
119124
}
120125
break;
121126
case Messages::TouchEvent: {
@@ -191,7 +196,7 @@ void DisplayApp::RunningState() {
191196
case Apps::None:
192197
case Apps::Launcher: currentScreen.reset(new Screens::ApplicationList(this)); break;
193198
case Apps::Clock:
194-
currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController));
199+
currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController, notificationManager));
195200
onClockApp = true;
196201
break;
197202
// case Apps::Test: currentScreen.reset(new Screens::Message(this)); break;
@@ -202,6 +207,7 @@ void DisplayApp::RunningState() {
202207
case Apps::Brightness : currentScreen.reset(new Screens::Brightness(this, brightnessController)); break;
203208
case Apps::Music : currentScreen.reset(new Screens::Music(this, systemTask.nimble().music())); break;
204209
case Apps::FirmwareValidation: currentScreen.reset(new Screens::FirmwareValidation(this, validator)); break;
210+
case Apps::Notifications: currentScreen.reset(new Screens::Notifications(this, notificationManager, Screens::Notifications::Modes::Normal)); break;
205211
}
206212
nextApp = Apps::None;
207213
}

src/displayapp/screens/ApplicationList.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
5858
{{Symbols::tachometer, Apps::Gauge},
5959
{Symbols::asterisk, Apps::Meter},
6060
{Symbols::paintbrush, Apps::Paint},
61-
{Symbols::none, Apps::None},
62-
{Symbols::none, Apps::None},
63-
{Symbols::none, Apps::None}
61+
{Symbols::info, Apps::Notifications},
62+
{Symbols::none, Apps::None},
63+
{Symbols::none, Apps::None}
6464
}
6565
};
6666

0 commit comments

Comments
 (0)