Skip to content

Commit 2c75e7a

Browse files
TiggilybooNeroBurner
authored andcommitted
Dismiss notifications by swiping right
Add a new interface `NotificationManager::Dismiss(id)` to delete a notification with the specified `id`. The animate the notification dismiss the `RightAnim` transition to a black screen is used. After the dismiss the new message is swiped in from below or above. If we dismiss the oldest message (when we are at 5/5, or 3/3), then the new message after a dismiss should appear to come from below. Otherwise (when we are at 2/3) the new message after a dismiss should appear to come from above. Rework the index code to show the index of the currently viewed notification. Instead of calculating the index relative to the oldest `id` introduce a new interface `NotificationManager::IndexOf(id)`. This is done because the `id` of the notifications in the buffer aren't continuous anymore (as some messages could have been dismissed). Rework notification ring buffer to have a beginIdx and a size internally to make the dismissal of notifications easier. Fixes: #176 Co-authored-by: Simon Willshire <me@simonwillshire.com> Co-authored-by: Reinhold Gschweicher <pyro4hell@gmail.com>
1 parent e77d47e commit 2c75e7a

4 files changed

Lines changed: 255 additions & 114 deletions

File tree

src/components/ble/NotificationManager.cpp

Lines changed: 94 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "components/ble/NotificationManager.h"
22
#include <cstring>
33
#include <algorithm>
4+
#include <cassert>
45

56
using namespace Pinetime::Controllers;
67

@@ -9,73 +10,117 @@ constexpr uint8_t NotificationManager::MessageSize;
910
void NotificationManager::Push(NotificationManager::Notification&& notif) {
1011
notif.id = GetNextId();
1112
notif.valid = true;
12-
notifications[writeIndex] = std::move(notif);
13-
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
14-
if (!empty)
15-
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
16-
else
17-
empty = false;
18-
1913
newNotification = true;
20-
}
21-
22-
NotificationManager::Notification NotificationManager::GetLastNotification() {
23-
NotificationManager::Notification notification = notifications[readIndex];
24-
notification.index = 1;
25-
return notification;
14+
if (beginIdx > 0) {
15+
--beginIdx;
16+
} else {
17+
beginIdx = notifications.size() - 1;
18+
}
19+
notifications[beginIdx] = std::move(notif);
20+
if (size < notifications.size()) {
21+
size++;
22+
}
2623
}
2724

2825
NotificationManager::Notification::Id NotificationManager::GetNextId() {
2926
return nextId++;
3027
}
3128

32-
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) {
33-
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
34-
return n.valid && n.id == id;
35-
});
36-
if (currentIterator == notifications.end() || currentIterator->id != id)
37-
return Notification {};
38-
39-
auto& lastNotification = notifications[readIndex];
40-
41-
NotificationManager::Notification result;
42-
43-
if (currentIterator == (notifications.end() - 1))
44-
result = *(notifications.begin());
45-
else
46-
result = *(currentIterator + 1);
47-
48-
if (result.id <= id)
29+
NotificationManager::Notification NotificationManager::GetLastNotification() const {
30+
if (this->IsEmpty()) {
4931
return {};
32+
}
33+
return this->At(0);
34+
}
5035

51-
result.index = (lastNotification.id - result.id) + 1;
52-
return result;
36+
const NotificationManager::Notification& NotificationManager::At(NotificationManager::Notification::Idx idx) const {
37+
if (idx >= notifications.size()) {
38+
assert(false);
39+
return notifications.at(beginIdx); // this should not happen
40+
}
41+
size_t read_idx = (beginIdx + idx) % notifications.size();
42+
return notifications.at(read_idx);
5343
}
5444

55-
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) {
56-
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
57-
return n.valid && n.id == id;
58-
});
59-
if (currentIterator == notifications.end() || currentIterator->id != id)
60-
return Notification {};
45+
NotificationManager::Notification& NotificationManager::At(NotificationManager::Notification::Idx idx) {
46+
if (idx >= notifications.size()) {
47+
assert(false);
48+
return notifications.at(beginIdx); // this should not happen
49+
}
50+
size_t read_idx = (beginIdx + idx) % notifications.size();
51+
return notifications.at(read_idx);
52+
}
6153

62-
auto& lastNotification = notifications[readIndex];
54+
NotificationManager::Notification::Idx NotificationManager::IndexOf(NotificationManager::Notification::Id id) const {
55+
for (NotificationManager::Notification::Idx idx = 0; idx < this->size; idx++) {
56+
const NotificationManager::Notification& notification = this->At(idx);
57+
if (notification.id == id) {
58+
return idx;
59+
}
60+
}
61+
return size;
62+
}
6363

64-
NotificationManager::Notification result;
64+
NotificationManager::Notification NotificationManager::Get(NotificationManager::Notification::Id id) const {
65+
NotificationManager::Notification::Idx idx = this->IndexOf(id);
66+
if (idx == this->size) {
67+
return {};
68+
}
69+
return this->At(idx);
70+
}
6571

66-
if (currentIterator == notifications.begin())
67-
result = *(notifications.end() - 1);
68-
else
69-
result = *(currentIterator - 1);
72+
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) const {
73+
NotificationManager::Notification::Idx idx = this->IndexOf(id);
74+
if (idx == this->size) {
75+
return {};
76+
}
77+
if (idx == 0 || idx > notifications.size()) {
78+
return {};
79+
}
80+
return this->At(idx - 1);
81+
}
7082

71-
if (result.id >= id)
83+
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) const {
84+
NotificationManager::Notification::Idx idx = this->IndexOf(id);
85+
if (idx == this->size) {
86+
return {};
87+
}
88+
if (static_cast<size_t>(idx + 1) >= notifications.size()) {
7289
return {};
90+
}
91+
return this->At(idx + 1);
92+
}
93+
94+
void NotificationManager::DismissIdx(NotificationManager::Notification::Idx idx) {
95+
if (this->IsEmpty()) {
96+
return;
97+
}
98+
if (idx >= size) {
99+
assert(false);
100+
return; // this should not happen
101+
}
102+
if (idx == 0) { // just remove the first element, don't need to change the other elements
103+
notifications.at(beginIdx).valid = false;
104+
beginIdx = (beginIdx + 1) % notifications.size();
105+
} else {
106+
// overwrite the specified entry by moving all later messages one index to the front
107+
for (size_t i = idx; i < size - 1; ++i) {
108+
this->At(i) = this->At(i + 1);
109+
}
110+
this->At(size - 1).valid = false;
111+
}
112+
--size;
113+
}
73114

74-
result.index = (lastNotification.id - result.id) + 1;
75-
return result;
115+
void NotificationManager::Dismiss(NotificationManager::Notification::Id id) {
116+
NotificationManager::Notification::Idx idx = this->IndexOf(id);
117+
if (idx == this->size) {
118+
return;
119+
}
120+
this->DismissIdx(idx);
76121
}
77122

78-
bool NotificationManager::AreNewNotificationsAvailable() {
123+
bool NotificationManager::AreNewNotificationsAvailable() const {
79124
return newNotification;
80125
}
81126

@@ -84,9 +129,7 @@ bool NotificationManager::ClearNewNotificationFlag() {
84129
}
85130

86131
size_t NotificationManager::NbNotifications() const {
87-
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n) {
88-
return n.valid;
89-
});
132+
return size;
90133
}
91134

92135
const char* NotificationManager::Notification::Message() const {

src/components/ble/NotificationManager.h

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,37 +26,48 @@ namespace Pinetime {
2626

2727
struct Notification {
2828
using Id = uint8_t;
29-
Id id;
29+
using Idx = uint8_t;
30+
Id id = 0;
3031
bool valid = false;
31-
uint8_t index;
3232
uint8_t size;
3333
std::array<char, MessageSize + 1> message;
3434
Categories category = Categories::Unknown;
3535

3636
const char* Message() const;
3737
const char* Title() const;
3838
};
39-
Notification::Id nextId {0};
4039

4140
void Push(Notification&& notif);
42-
Notification GetLastNotification();
43-
Notification GetNext(Notification::Id id);
44-
Notification GetPrevious(Notification::Id id);
41+
Notification GetLastNotification() const;
42+
Notification Get(Notification::Id id) const;
43+
Notification GetNext(Notification::Id id) const;
44+
Notification GetPrevious(Notification::Id id) const;
45+
// Return the index of the notification with the specified id, if not found return NbNotifications()
46+
Notification::Idx IndexOf(Notification::Id id) const;
4547
bool ClearNewNotificationFlag();
46-
bool AreNewNotificationsAvailable();
48+
bool AreNewNotificationsAvailable() const;
49+
void Dismiss(Notification::Id id);
4750

4851
static constexpr size_t MaximumMessageSize() {
4952
return MessageSize;
5053
};
54+
bool IsEmpty() const {
55+
return size == 0;
56+
}
5157
size_t NbNotifications() const;
5258

5359
private:
60+
Notification::Id nextId {0};
5461
Notification::Id GetNextId();
62+
const Notification& At(Notification::Idx idx) const;
63+
Notification& At(Notification::Idx idx);
64+
void DismissIdx(Notification::Idx idx);
65+
5566
static constexpr uint8_t TotalNbNotifications = 5;
5667
std::array<Notification, TotalNbNotifications> notifications;
57-
uint8_t readIndex = 0;
58-
uint8_t writeIndex = 0;
59-
bool empty = true;
68+
size_t beginIdx = TotalNbNotifications - 1; // index of the newest notification
69+
size_t size = 0; // number of valid notifications in buffer
70+
6071
std::atomic<bool> newNotification {false};
6172
};
6273
}

0 commit comments

Comments
 (0)