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:
2026-10-13 13:30:20 -05:00
co-authored by Claude Opus 4.8
parent c5b325a752
commit 13989cf268
3 changed files with 56 additions and 15 deletions
+6 -6
View File
@@ -14,15 +14,15 @@ namespace ui {
void Notifications::render()
{
// Remove expired notifications
while (!notifications_.empty() && notifications_.front().isExpired()) {
notifications_.pop_front();
}
// Remove every expired notification; the newest remaining one is then both the last and a live one.
pruneExpired(notifications_, std::chrono::steady_clock::now());
if (notifications_.empty()) {
last_drawn_ = {}; // nothing painted: the trailing "clean frame" is this one
return;
}
last_drawn_ = std::chrono::steady_clock::now();
// Only show the most recent (last) notification as a compact status-bar pill
const auto& notif = notifications_.back();