diff --git a/loader/include/Geode/ui/Notification.hpp b/loader/include/Geode/ui/Notification.hpp index 0ee9ad62f..4e780afe0 100644 --- a/loader/include/Geode/ui/Notification.hpp +++ b/loader/include/Geode/ui/Notification.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace geode { constexpr auto NOTIFICATION_DEFAULT_TIME = 1.8f; @@ -32,6 +33,7 @@ namespace geode { void showNextNotification(); void waitThenHide(); + void maybeSkipForQueuedNotification(); NineSlice* getBG(); cocos2d::CCLabelBMFont* getLabel(); @@ -66,6 +68,36 @@ namespace geode { cocos2d::CCNode* icon, float time = NOTIFICATION_DEFAULT_TIME ); + /** + * Create a low-priority notification that is shown for at most + * maxTime seconds, but can be skipped early if another notification + * enters the queue. + * @param text Notification text + * @param icon Icon to show in the notification + * @param maxTime Maximum time to show the notification on screen + * @returns The new notification. Make sure to call show() to show the + * notification + */ + static Notification* createSkippable( + ZStringView text, + NotificationIcon icon = NotificationIcon::None, + float maxTime = NOTIFICATION_DEFAULT_TIME + ); + /** + * Create a low-priority notification with a custom icon that is shown + * for at most maxTime seconds, but can be skipped early if another + * notification enters the queue. + * @param text Notification text + * @param icon Icon to show in the notification + * @param maxTime Maximum time to show the notification on screen + * @returns The new notification. Make sure to call show() to show the + * notification + */ + static Notification* createSkippable( + ZStringView text, + cocos2d::CCNode* icon, + float maxTime = NOTIFICATION_DEFAULT_TIME + ); void setString(ZStringView text); void setIcon(NotificationIcon icon); diff --git a/loader/src/ui/nodes/Notification.cpp b/loader/src/ui/nodes/Notification.cpp index 305cdec64..78f1fa0a0 100644 --- a/loader/src/ui/nodes/Notification.cpp +++ b/loader/src/ui/nodes/Notification.cpp @@ -2,6 +2,7 @@ #include #include #include +#include using namespace geode::prelude; @@ -18,6 +19,7 @@ class Notification::Impl final { CCNode* icon = nullptr; float time; bool showing = false; + bool skippableOnQueue = false; }; Notification::Notification() : m_impl(std::make_unique()) { } @@ -75,10 +77,12 @@ void Notification::showNextNotification() { this->removeFromParent(); // remove self from front of queue and show next popup if it exists - s_queue.pop_front(); + if (!s_queue.empty()) { + s_queue.pop_front(); + } - if (s_queue.size() != 0) { - s_queue.at(0)->show(); + if (!s_queue.empty()) { + s_queue.front()->show(); } } @@ -127,6 +131,18 @@ Notification* Notification::create(ZStringView text, CCNode* icon, float time) { return nullptr; } +Notification* Notification::createSkippable(ZStringView text, NotificationIcon icon, float maxTime) { + return Notification::createSkippable(text, createIcon(icon), maxTime); +} + +Notification* Notification::createSkippable(ZStringView text, CCNode* icon, float maxTime) { + if (auto ret = Notification::create(text, icon, maxTime)) { + ret->m_impl->skippableOnQueue = true; + return ret; + } + return nullptr; +} + void Notification::setString(ZStringView text) { m_impl->label->setString(text.c_str()); this->updateLayout(); @@ -186,8 +202,13 @@ void Notification::show() { s_queue.push_back(this); } + if (s_queue.empty()) return; + // if we're not the current notification, return - if (s_queue.at(0) != this) { + if (s_queue.front() != this) { + if (auto current = s_queue.front().data()) { + current->maybeSkipForQueuedNotification(); + } return; } @@ -234,6 +255,12 @@ void Notification::waitThenHide() { } } +void Notification::maybeSkipForQueuedNotification() { + if (m_impl->showing && m_impl->skippableOnQueue) { + this->hide(); + } +} + void Notification::hide() { this->stopAllActions();