From 46e46b522f17d5062ab22205f173d6574687e0cc Mon Sep 17 00:00:00 2001 From: david Date: Sun, 2 May 2021 12:39:22 +0200 Subject: [PATCH 1/6] Implement Swipe-to-dismiss on notifications --- src/components/ble/NotificationManager.cpp | 42 ++++++++++++++++++++ src/components/ble/NotificationManager.h | 3 +- src/displayapp/screens/Notifications.cpp | 45 ++++++++++++++++++++++ src/displayapp/screens/Notifications.h | 2 + 4 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/components/ble/NotificationManager.cpp b/src/components/ble/NotificationManager.cpp index b1b0e6b262..1e6daa0043 100644 --- a/src/components/ble/NotificationManager.cpp +++ b/src/components/ble/NotificationManager.cpp @@ -6,6 +6,48 @@ 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 : readIndex - 1; + writeIndex = writeIndex == 0 ? TotalNbNotifications : writeIndex - 1; + + // popped last notification + if (NbNotifications() == 0) { + empty = true; + readIndex = 0; + writeIndex = 0; + ClearNewNotificationFlag(); + return; + } +} + void NotificationManager::Push(NotificationManager::Notification&& notif) { notif.id = GetNextId(); notif.valid = true; diff --git a/src/components/ble/NotificationManager.h b/src/components/ble/NotificationManager.h index d4072cc2ed..2366946b80 100644 --- a/src/components/ble/NotificationManager.h +++ b/src/components/ble/NotificationManager.h @@ -38,6 +38,7 @@ namespace Pinetime { }; Notification::Id nextId {0}; + void Pop(Notification::Id id); void Push(Notification&& notif); Notification GetLastNotification(); Notification GetNext(Notification::Id id); @@ -63,4 +64,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..5deb503606 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -15,6 +15,8 @@ Notifications::Notifications(DisplayApp* app, : Screen(app), notificationManager {notificationManager}, alertNotificationService {alertNotificationService}, mode {mode} { notificationManager.ClearNewNotificationFlag(); auto notification = notificationManager.GetLastNotification(); + + last_gesture = 0; if (notification.valid) { currentId = notification.id; currentItem = std::make_unique(notification.Title(), @@ -95,6 +97,49 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { alertNotificationService); } return true; + case Pinetime::Applications::TouchEvents::SwipeLeft: { + // FIXME: SwipeLeft only because otherwise settings pop up on the main screen + // I'd rather this be SwipeRight + if (!validDisplay) + return false; + + // FIXME: this is a hack, without it the event triggers repeatedly + // causing all notifications to be dismissed in a single swipe + auto timeElapsed = xTaskGetTickCount() - last_gesture; // TODO wrapping + const int timeElapsedMillis = (static_cast(timeElapsed) / static_cast(configTICK_RATE_HZ)) * 1000; + if (timeElapsedMillis < 200) { + return true; + } + last_gesture = xTaskGetTickCount(); + + 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); + + 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) diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h index 51ca81da9b..9bfc40771b 100644 --- a/src/displayapp/screens/Notifications.h +++ b/src/displayapp/screens/Notifications.h @@ -5,6 +5,7 @@ #include #include "Screen.h" #include "components/ble/NotificationManager.h" +#include "FreeRTOS.h" namespace Pinetime { namespace Controllers { @@ -78,6 +79,7 @@ namespace Pinetime { lv_obj_t* timeoutLine; uint32_t timeoutTickCountStart; uint32_t timeoutTickCountEnd; + uint32_t last_gesture; }; } } From cb81a9b77882c40409dd6905df58b0041cc447a6 Mon Sep 17 00:00:00 2001 From: david Date: Sun, 2 May 2021 18:19:02 +0200 Subject: [PATCH 2/6] Fix indexing issue --- src/components/ble/NotificationManager.cpp | 32 ++++++++++++++-------- src/components/ble/NotificationManager.h | 1 + src/displayapp/screens/Notifications.cpp | 3 +- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/components/ble/NotificationManager.cpp b/src/components/ble/NotificationManager.cpp index 1e6daa0043..31340d4dfd 100644 --- a/src/components/ble/NotificationManager.cpp +++ b/src/components/ble/NotificationManager.cpp @@ -44,26 +44,28 @@ void NotificationManager::Pop(Notification::Id id) { readIndex = 0; writeIndex = 0; ClearNewNotificationFlag(); - return; } } 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) { + 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; } @@ -78,8 +80,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)) @@ -90,7 +90,6 @@ NotificationManager::Notification NotificationManager::GetNext(NotificationManag if (result.id <= id) return {}; - result.index = (lastNotification.id - result.id) + 1; return result; } @@ -101,8 +100,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()) @@ -113,7 +110,6 @@ NotificationManager::Notification NotificationManager::GetPrevious(NotificationM if (result.id >= id) return {}; - result.index = (lastNotification.id - result.id) + 1; return result; } @@ -155,3 +151,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 2366946b80..65f0c89d19 100644 --- a/src/components/ble/NotificationManager.h +++ b/src/components/ble/NotificationManager.h @@ -43,6 +43,7 @@ namespace Pinetime { Notification GetLastNotification(); Notification GetNext(Notification::Id id); Notification GetPrevious(Notification::Id id); + Notification Refresh(Notification::Id id); bool ClearNewNotificationFlag(); bool AreNewNotificationsAvailable(); bool IsVibrationEnabled(); diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 5deb503606..bb62546be2 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -123,6 +123,7 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { } notificationManager.Pop(currentId); + nextNotification = notificationManager.Refresh(nextNotification.id); if (nextNotification.valid) { currentId = nextNotification.id; @@ -214,7 +215,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); From 7c9f9490ef5f8d950f6b6b6848160b826263f98c Mon Sep 17 00:00:00 2001 From: david Date: Sun, 2 May 2021 21:26:06 +0200 Subject: [PATCH 3/6] fix index when pushing more than max notifications --- src/components/ble/NotificationManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/ble/NotificationManager.cpp b/src/components/ble/NotificationManager.cpp index 31340d4dfd..a8197fa979 100644 --- a/src/components/ble/NotificationManager.cpp +++ b/src/components/ble/NotificationManager.cpp @@ -53,6 +53,11 @@ void NotificationManager::Push(NotificationManager::Notification&& notif) { auto prevWriteIndex = writeIndex; writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0; 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 { From 88a889ea9831537511768cb36102cb5d89bfa152 Mon Sep 17 00:00:00 2001 From: david Date: Mon, 3 May 2021 23:30:48 +0200 Subject: [PATCH 4/6] Double-tap instead of swiping --- src/displayapp/screens/Notifications.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index bb62546be2..5e0b9ca3ee 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -16,7 +16,6 @@ Notifications::Notifications(DisplayApp* app, notificationManager.ClearNewNotificationFlag(); auto notification = notificationManager.GetLastNotification(); - last_gesture = 0; if (notification.valid) { currentId = notification.id; currentItem = std::make_unique(notification.Title(), @@ -97,21 +96,10 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { alertNotificationService); } return true; - case Pinetime::Applications::TouchEvents::SwipeLeft: { - // FIXME: SwipeLeft only because otherwise settings pop up on the main screen - // I'd rather this be SwipeRight + case Pinetime::Applications::TouchEvents::DoubleTap: { if (!validDisplay) return false; - // FIXME: this is a hack, without it the event triggers repeatedly - // causing all notifications to be dismissed in a single swipe - auto timeElapsed = xTaskGetTickCount() - last_gesture; // TODO wrapping - const int timeElapsedMillis = (static_cast(timeElapsed) / static_cast(configTICK_RATE_HZ)) * 1000; - if (timeElapsedMillis < 200) { - return true; - } - last_gesture = xTaskGetTickCount(); - Controllers::NotificationManager::Notification nextNotification; nextNotification = notificationManager.GetPrevious(currentId); if (nextNotification.valid) { From 98d885c9017e1e9a669d1117504be2e6ead73c00 Mon Sep 17 00:00:00 2001 From: david Date: Mon, 3 May 2021 23:36:09 +0200 Subject: [PATCH 5/6] remove last_gesture leftovers --- src/displayapp/screens/Notifications.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h index 9bfc40771b..51ca81da9b 100644 --- a/src/displayapp/screens/Notifications.h +++ b/src/displayapp/screens/Notifications.h @@ -5,7 +5,6 @@ #include #include "Screen.h" #include "components/ble/NotificationManager.h" -#include "FreeRTOS.h" namespace Pinetime { namespace Controllers { @@ -79,7 +78,6 @@ namespace Pinetime { lv_obj_t* timeoutLine; uint32_t timeoutTickCountStart; uint32_t timeoutTickCountEnd; - uint32_t last_gesture; }; } } From 47e5ca09ba59ce66817500da58a576d6980ed19a Mon Sep 17 00:00:00 2001 From: david Date: Tue, 4 May 2021 14:06:29 +0200 Subject: [PATCH 6/6] fix off by one error --- src/components/ble/NotificationManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ble/NotificationManager.cpp b/src/components/ble/NotificationManager.cpp index a8197fa979..cb2fad3258 100644 --- a/src/components/ble/NotificationManager.cpp +++ b/src/components/ble/NotificationManager.cpp @@ -35,8 +35,8 @@ void NotificationManager::Pop(Notification::Id id) { next = (idx + 1) % TotalNbNotifications; } - readIndex = readIndex == 0 ? TotalNbNotifications : readIndex - 1; - writeIndex = writeIndex == 0 ? TotalNbNotifications : writeIndex - 1; + readIndex = readIndex == 0 ? TotalNbNotifications - 1 : readIndex - 1; + writeIndex = writeIndex == 0 ? TotalNbNotifications - 1 : writeIndex - 1; // popped last notification if (NbNotifications() == 0) {