Skip to content

Commit 3318736

Browse files
committed
v3.16.8: clear phantom unread badge when window regains focus (#phantom-badge-on-focus-return)
1 parent a9fc427 commit 3318736

2 files changed

Lines changed: 29 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ Format follows [Keep a Changelog](https://keepachangelog.com/). Haven uses [Sema
1111
1212
---
1313

14+
## [3.16.8] — 2026-05-15
15+
16+
### Fixed
17+
- **Phantom unread badge on current channel after returning from background.** When the app was backgrounded (alt-tabbed, minimised, or the BrowserView was hidden in Desktop's multi-server switcher) while the user was already at the bottom of a channel, incoming messages bumped the sidebar unread badge even though the user was actively reading that channel. The badge-clearing code only fires when a *new* message arrives while the page is visible, so if no further messages arrived the stale badge was stuck permanently. The fix clears the badge (and syncs `mark-read` to the server) immediately when the window/tab regains visibility and the user is still coupled to the bottom of the current channel.
18+
19+
---
20+
1421
## [3.16.7] — 2026-05-15
1522

1623
### Fixed

public/js/modules/app-channels.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2640,6 +2640,28 @@ _resyncDesktopBadgeOnFocus() {
26402640
this._desktopBadgeFocusBound = true;
26412641
const resync = () => {
26422642
if (document.hidden) return;
2643+
// Clear stale unread badge on the channel the user is actively viewing.
2644+
// When the page is hidden (backgrounded BrowserView, alt-tab, minimise)
2645+
// incoming messages bump unreadCounts even though the user was already
2646+
// at the bottom — because isActivelyViewing = false in the new-message
2647+
// handler. The badge-clearing path inside that handler only fires when
2648+
// a *new* message arrives while visible, so if no message arrives after
2649+
// the user returns the "N unread" badge is stuck until someone else
2650+
// types. Fix: as soon as the window becomes visible again, if the user
2651+
// is still coupled to the bottom of the current channel, treat those
2652+
// messages as read immediately. (#phantom-badge-on-focus-return)
2653+
if (this.currentChannel && this._coupledToBottom && this.unreadCounts?.[this.currentChannel]) {
2654+
const code = this.currentChannel;
2655+
const ch = this.channels?.find(c => c.code === code);
2656+
const latestId = ch?.latestMessageId || this._newestMsgId;
2657+
this.unreadCounts[code] = 0;
2658+
try { this._updateBadge?.(code); } catch {}
2659+
try { this._updateDmSectionBadge?.(); } catch {}
2660+
try { this._updateTabTitle?.(); } catch {}
2661+
if (latestId) {
2662+
try { this.socket.emit('mark-read', { code, messageId: latestId }); } catch {}
2663+
}
2664+
}
26432665
try { this._updateDesktopBadge(); } catch {}
26442666
};
26452667
window.addEventListener('focus', resync);

0 commit comments

Comments
 (0)