Initial focus went to the unnamed Dialogs::Widget container, so NVDA
announced the raw Qt class chain. Focus the accessible chat list instead
so the list and its selected chat are announced.
The invisible hit-area stacked under the main menu toggle duplicates the
toggle's action but has no label, so in screen reader mode it became a
second, unnamed Tab stop that read out the raw Qt class chain. Give it no
accessible role so it is skipped by keyboard/screen-reader navigation,
while mouse clicks still open the menu.
Factor the floating cloud bubble's painting and scroll-mount wiring into shared helpers so the bubble content can be mounted standalone over any scrollable surface.
ChatFilters::applyRemove() emptied the filter in the list and only then
detached its chats. Unpinning a chat re-caches its siblings' pinned
indices, which runs Session::refreshChatListEntry(); seeing the filter
still listed but emptied, it re-entered removeFromChatList() ->
setChatPinned() -> PinnedList::setPinned() on the same pinned list while
its re-cache loop iterated with a cached size, reading past the end of
the vector. This aborted on closing the Folders editor after removing
two or more folders that had pinned chats.
Detach the filter from the list before applyChange() tears down its
chats, so the re-entrant refresh no longer touches it. Also harden the
setPinned() re-cache loop to re-check the container size each iteration
as defense in depth.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Home/End jumped to the first/last chat until InnerWidget's key handling
was rewritten from a switch into an if/else chain (in 'Extract chats list
accessibility, fix build'), which carried over only Up/Down and Page
Up/Down and dropped the Home/End cases.
Re-add them, skipping by the actual total row count (which selectSkip()
clamps) instead of the previous 1<<20 constant, so it lands on the first
or last row in both the default list and the filtered/search results.
In screen reader mode, focusing the dialogs search field no longer opens
the suggestions panel or shows the cancel-search button. Search engages
only when the user types, stays engaged after clearing the query, and
disengages only on explicit Escape or the cancel-search button. Tab and
Backspace on an empty query no longer exit search in this mode.
Non-screen-reader behavior is unchanged.