Skip to content

Unread tracking: mark-all-read on tab hide erases unread for rooms the user never saw (mobile app-switch) #446

Description

@sanity

Found during adversarial review of #445 (mobile hamburger unread badge). Pre-existing behavior, affects three surfaces: the document-title count, the room-list badges, and (since #445) the hamburger badge.

Behavior

mark_all_rooms_as_read() (ui/src/components/app/document_title.rs) fires on every visible→hidden visibilitychange and marks every room read up to its latest message. Rationale in the code: "the user had the chance to see anything already in state."

That premise is desktop-title-centric. On mobile, switching apps fires visible→hidden, and rooms other than the current one were never on screen — yet their unread state is wiped. Scenario:

  1. User is deep in room A on mobile; a message lands in room B → hamburger badge / rail badge show 1.
  2. User switches to another app (visibilitychange → hidden) → all rooms marked read.
  3. User returns → badges gone, though the room-B message was never seen.

So the unread indicators only hold within a single uninterrupted foreground session. On desktop the same wipe zeroes rail badges for rooms whose messages were arguably never "seen" either (a rail badge count is not the message).

Options

  • Only mark the current room read on hide (other rooms keep unread until actually opened). Changes title semantics: the hidden-tab "(N)" would then show total accumulated unread, not just new-since-hide — arguably more useful, but a deliberate change.
  • Keep mark-all on desktop, restrict to current-room-only on touch/mobile (no reliable signal; user-agent sniffing is ugly).
  • Keep as-is and accept the reset (status quo).

Needs a product call since it changes long-standing title behavior. cc @sanity

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions