diff --git a/src/components/ble/NotificationManager.cpp b/src/components/ble/NotificationManager.cpp index b1b0e6b262..cb2fad3258 100644 --- a/src/components/ble/NotificationManager.cpp +++ b/src/components/ble/NotificationManager.cpp @@ -6,22 +6,71 @@ using namespace Pinetime::Controllers; constexpr uint8_t NotificationManager::MessageSize; +void NotificationManager::Pop(Notification::Id id) { + // notifications is a circular buffer, the *valid* items in it are contiguous + // and sorted by id. + // Ex: + // 1, 2, 3, X, X (where X means invalid) + // 6, 2, 3, 4, 5 (oldest item got overwritten) + // + // When dismissing a notification, every valid item to the right (wrapping) + // that has a larger ID should be shifted to the left once + // and the newly-created "gap" is marked invalid + // + // 6, 2, 3, 4, 5 (dismissing 4) + // X, 2, 3, 5, 6 + + auto to_dismiss = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) { + return n.valid && n.id == id; + }); + auto idx = to_dismiss - notifications.begin(); + auto next = (idx + 1) % TotalNbNotifications; + notifications[idx].valid = false; + + while (notifications[next].valid and notifications[next].id > id) { + notifications[idx] = notifications[next]; + notifications[idx].index--; + notifications[next].valid = false; // just moved this + idx = (idx + 1) % TotalNbNotifications; + next = (idx + 1) % TotalNbNotifications; + } + + readIndex = readIndex == 0 ? TotalNbNotifications - 1 : readIndex - 1; + writeIndex = writeIndex == 0 ? TotalNbNotifications - 1 : writeIndex - 1; + + // popped last notification + if (NbNotifications() == 0) { + empty = true; + readIndex = 0; + writeIndex = 0; + ClearNewNotificationFlag(); + } +} + void NotificationManager::Push(NotificationManager::Notification&& notif) { notif.id = GetNextId(); notif.valid = true; - notifications[writeIndex] = std::move(notif); + auto prevWriteIndex = writeIndex; writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0; - if (!empty) + if (!empty) { + if (NbNotifications() == TotalNbNotifications) { + for(auto &n : notifications) { + n.index--; + } + } + notif.index = notifications[readIndex].index + 1; readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0; - else + } else { + notif.index = 1; empty = false; + } + notifications[prevWriteIndex] = std::move(notif); newNotification = true; } NotificationManager::Notification NotificationManager::GetLastNotification() { NotificationManager::Notification notification = notifications[readIndex]; - notification.index = 1; return notification; } @@ -36,8 +85,6 @@ NotificationManager::Notification NotificationManager::GetNext(NotificationManag if (currentIterator == notifications.end() || currentIterator->id != id) return Notification {}; - auto& lastNotification = notifications[readIndex]; - NotificationManager::Notification result; if (currentIterator == (notifications.end() - 1)) @@ -48,7 +95,6 @@ NotificationManager::Notification NotificationManager::GetNext(NotificationManag if (result.id <= id) return {}; - result.index = (lastNotification.id - result.id) + 1; return result; } @@ -59,8 +105,6 @@ NotificationManager::Notification NotificationManager::GetPrevious(NotificationM if (currentIterator == notifications.end() || currentIterator->id != id) return Notification {}; - auto& lastNotification = notifications[readIndex]; - NotificationManager::Notification result; if (currentIterator == notifications.begin()) @@ -71,7 +115,6 @@ NotificationManager::Notification NotificationManager::GetPrevious(NotificationM if (result.id >= id) return {}; - result.index = (lastNotification.id - result.id) + 1; return result; } @@ -113,3 +156,17 @@ const char* NotificationManager::Notification::Title() const { } return {}; } + +NotificationManager::Notification NotificationManager::Refresh(NotificationManager::Notification::Id id) { + auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) { + return n.valid && n.id == id; + }); + if (currentIterator == notifications.end() || currentIterator->id != id) { + return Notification {}; + } + NotificationManager::Notification result; + + result = notifications[currentIterator - notifications.begin()]; + + return result; +} diff --git a/src/components/ble/NotificationManager.h b/src/components/ble/NotificationManager.h index d4072cc2ed..65f0c89d19 100644 --- a/src/components/ble/NotificationManager.h +++ b/src/components/ble/NotificationManager.h @@ -38,10 +38,12 @@ namespace Pinetime { }; Notification::Id nextId {0}; + void Pop(Notification::Id id); void Push(Notification&& notif); Notification GetLastNotification(); Notification GetNext(Notification::Id id); Notification GetPrevious(Notification::Id id); + Notification Refresh(Notification::Id id); bool ClearNewNotificationFlag(); bool AreNewNotificationsAvailable(); bool IsVibrationEnabled(); @@ -63,4 +65,4 @@ namespace Pinetime { bool vibrationEnabled = true; }; } -} \ No newline at end of file +} diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index f0fd2f6636..5e0b9ca3ee 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -15,6 +15,7 @@ Notifications::Notifications(DisplayApp* app, : Screen(app), notificationManager {notificationManager}, alertNotificationService {alertNotificationService}, mode {mode} { notificationManager.ClearNewNotificationFlag(); auto notification = notificationManager.GetLastNotification(); + if (notification.valid) { currentId = notification.id; currentItem = std::make_unique(notification.Title(), @@ -95,6 +96,39 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { alertNotificationService); } return true; + case Pinetime::Applications::TouchEvents::DoubleTap: { + if (!validDisplay) + return false; + + Controllers::NotificationManager::Notification nextNotification; + nextNotification = notificationManager.GetPrevious(currentId); + if (nextNotification.valid) { + app->SetFullRefresh(DisplayApp::FullRefreshDirections::Down); + } else { + nextNotification = notificationManager.GetNext(currentId); + if (nextNotification.valid) + app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up); + } + + notificationManager.Pop(currentId); + nextNotification = notificationManager.Refresh(nextNotification.id); + + if (nextNotification.valid) { + currentId = nextNotification.id; + currentItem.reset(nullptr); + currentItem = std::make_unique(nextNotification.Title(), + nextNotification.Message(), + nextNotification.index, + nextNotification.category, + notificationManager.NbNotifications(), + mode, + alertNotificationService); + } else { + app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up); + running = false; + } + } + return false; case Pinetime::Applications::TouchEvents::SwipeUp: { Controllers::NotificationManager::Notification nextNotification; if (validDisplay) @@ -169,7 +203,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); lv_obj_t* alert_count = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(alert_count, "%i/%i", notifNr, notifNb); + lv_label_set_text_fmt(alert_count, "%i/%i", notifNb - notifNr + 1, notifNb); lv_obj_align(alert_count, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 16); lv_obj_t* alert_type = lv_label_create(lv_scr_act(), nullptr);