fix(notifications): prune expired toasts and skip invisible draws
The status-bar notifications only expired the front of the queue, so an expired newer toast could sit in front of a still-live older one and hide it from view. The liveness check that drives continuous repaints also disagreed with what render() actually showed. - Expired toasts are now pruned wherever they sit in the queue, not just at the front, so the newest remaining toast is always a live one. - The visible toast is the newest live entry, skipping an expired newer one. The liveness check reports active while a toast is visible plus one trailing frame, so the final faded-out state is painted once and then repaints stop; it self-expires if render() is skipped. Tests: pruning removes expired entries from anywhere in the queue, the visible toast skips an expired newest entry, and liveness tracks it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3515,6 +3515,30 @@ void testStalenessBadge()
|
||||
}
|
||||
}
|
||||
|
||||
void testNotificationLiveness() {
|
||||
using namespace dragonx::ui;
|
||||
using clk = std::chrono::steady_clock;
|
||||
// prune removes expired entries anywhere in the queue, not just the front
|
||||
std::deque<Notification> q;
|
||||
q.emplace_back("long", NotificationType::Error, 30.0f);
|
||||
q.emplace_back("short", NotificationType::Info, 1.0f);
|
||||
q.back().created_at = clk::now() - std::chrono::seconds(2); // expired
|
||||
q.emplace_back("mid", NotificationType::Info, 5.0f);
|
||||
q[2].created_at = clk::now() - std::chrono::seconds(10); // expired
|
||||
Notifications::pruneExpired(q, clk::now());
|
||||
EXPECT_EQ((int)q.size(), 1);
|
||||
EXPECT_EQ(q.back().message, std::string("long"));
|
||||
// visibleToast skips an expired newest entry and hasActive tracks visibility
|
||||
auto& n = Notifications::instance(); n.clear();
|
||||
n.push("a", NotificationType::Warning, 30.0f);
|
||||
n.push("b", NotificationType::Info, 0.001f);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
EXPECT_TRUE(n.visibleToast() != nullptr && n.visibleToast()->message == "a");
|
||||
EXPECT_TRUE(n.hasActive());
|
||||
n.clear();
|
||||
EXPECT_TRUE(!n.hasActive());
|
||||
}
|
||||
|
||||
void testNotificationHistory()
|
||||
{
|
||||
using dragonx::ui::Notifications;
|
||||
@@ -18185,6 +18209,7 @@ int main()
|
||||
testNodeStatusBanner();
|
||||
testStalenessBadge();
|
||||
testNotificationHistory();
|
||||
testNotificationLiveness();
|
||||
testSeedMigrationResume();
|
||||
testLoggerFileSink();
|
||||
testDaemonLifecycleExecution();
|
||||
|
||||
Reference in New Issue
Block a user