mirror of
https://github.com/status-im/status-app.git
synced 2026-08-27 15:11:20 +00:00
* perf: port mobile section extras onto the virtualized chat stack Ported from perf/section-loading-skeletons (the mobile mega-branch) onto perf/chat-list-virtualization, keeping the stack's reworked chat-list virtualization and section skeletons where the two overlapped: - message row diet: lazy tooltips, header slimming, async avatar, clock-free rows, lazy sender lookup - per-message mention resolution (MentionResolver) - context menus built on first use (chat list and message rows) - long-press opens the message context menu over text - deferred first chats build until the section transition settles (seaqt QTimer fallback + QML settle notification) - MessagesListHeader extracted and shared with the section skeleton - chat/community section skeleton composition in AppMain - StatusBaseButton emoji created on demand - emoji and stickers popups loaded asynchronously - day-granularity counter on StatusSharedUpdateTimer - icon badge count from section + activity-center notifications - QR capture, onboarding AOT-friendliness and misc row fixes revert(navbar): drop the async PrimaryNavSidebar content and its benchmark Back to the synchronous contentItem; the slideAnimationRunning alias stays for AppMain's transition-settled notification. chore(tests): drop tst_ChatListVirtualization, covered by the virtualization PR's suites fix(chat): hide incubating panels behind their skeletons - ChatView: left and center panel loaders stay invisible until Ready so the section skeleton isn't overdrawn by half-built panels. No gate on the right panel loader — it would hide the nested membersPanelSkeleton. - ChatContentView: the message-rows skeleton moves out of the gated loader (a child would inherit the invisibility) and the messages view is gated the same way. - tst_CommunityChatLoaderSection: gestures wait for a full render pass after the panels flip visible; drop the flaky empty-area right-click test. chore: update translations revert timestamp and long press fix: add StatusLazyToolTip to qrc undo DnD * fix(chat): restore first-channel fallback on the deferred section build If the persisted last-open chat no longer exists, buildChatSectionUI selects nothing and the deferred path had no repair step (the loaded path in onActiveSectionChange has one). Re-check after the build and fall back to the first channel, before completeActiveSectionChange so the active-chat notification carries the repaired id. Runs inside the deferred tick — the tap/skeleton/animation path is untouched. * fix(statusq): don't restyle detached subtrees through the Light fallback Unparenting an item re-links its Theme attached node to the engine-level fallback node, which is Light by default. attachedParentChange inherited that style immediately, so every LayoutItemProxy handoff (section switches hand panels between proxies) round-tripped the whole subtree through Light and back in a dark app, re-firing every Theme.palette binding — 224 message rich-text re-renders and a measured 2.3s GUI-thread freeze per section switch on device (light theme: 96ms). Defer the inherit while the item has no window; attachWindowReadySync already re-inherits at window landing, before anything renders, so the anti-flash intent of the previous order is preserved and first-attach of incubated panels still gets exactly one style application. * test: provide the hidden role in the ported chat-list mocks The chat list filters rows on the model-computed "hidden" role (PR #21943); rows without it are filtered out by design. The mocks introduced by the mobile port predate the role, so their lists rendered empty in CI (tst_ChatLoaderSection count 0/300, tst_ChatListContextMenu right-click found no row). Add the role to the row builders and mirror the backend recompute in CommunitySectionMock.setCategoryOpened. * fix(chat): tolerate optional/lazy dependencies in the chat views Cleans up the TypeErrors the loader test suites surfaced, three of which are real product races: - ChatLayout projected community stores off a null newCommunityStore — always null for the personal chat section and transiently while CommunityChatLoader swaps sections - MessageView dereferenced the emoji popup for the message context menu and the add-reaction path, but the popup loads lazily after startup and either can run first - ChatColumnView.restoreInputState is scheduled via Qt.callLater and can fire while the view tears down, after the dying context dropped its functions Plus the tst_ChatLoaderSection mock gaps (clearLinkPreviewCache, pinnedMessagesModel) behind the remaining warnings. * chore: update translations * test(chat): retry the synthesized drag gesture in the reorder tests The automatic drag's nested loop occasionally misses the synthesized press-move-release on a loaded machine (~1/35 locally, seen on CI's Xvfb), killing the gesture mid-flight and leaving no reorder to assert. Both reorder tests now share a dragRowVertically helper that re-runs the whole gesture up to three times, re-reading the row's live position and letting the rows settle between attempts. The correctness asserts are unchanged. * chore: update translations * perf: tweak the incubation controller boost mode will freeze until completion * fix(chat): don't raise the soft keyboard on first chat open The mention suggestion box restores focus to the composer whenever it becomes invisible. SuggestionBoxPanel is a Control, so `visible` starts true and the binding resolving it to false runs during construction — firing the handler once per StatusChatInput, before the chat is on screen, and raising the Android soft keyboard. That branch exists only to undo the `listView.forceActiveFocus()` grab three lines below it, which is already guarded desktop-only. On mobile it can therefore only ever be a no-op (the user was already typing) or this bug; the one mobile path that does need focus back — tapping a suggestion — restores it itself in selectItem(). Reachable because the centre panel now loads asynchronously: the existing guard in ChatColumnView only arms on a `visible -> false` edge, which no longer occurs now that the column is born effectively invisible. Device-verified on a Redmi A5: showSoftInput() calls during a cold start plus first chat open went from 4 to 1, the survivor being the login password field. * perf: don't build a Home page before the active section is known On cold start a complete HomePage was constructed synchronously on the GUI thread and immediately discarded. Two independent causes, both needed: SectionType's zero value is HomePage, so the default-initialised SectionDetails read as a real destination for the whole of Module.load() — from the moment mainModule is exposed to QML until setActiveSection resolves. Seed it with LoadingSection instead, which is already what load() falls back to when no section resolves. HomePageLoader keyed its `active` off appView.currentIndex, and StackLayout initialises currentIndex to 0 — the home page's own index — before its own binding first evaluates. Since that loader is synchronous, the transient was enough to build the whole page. Key it off the section type instead, which has no such default. Only this loader was affected; nothing else sits at index 0. Also restores the startup overlay's opaque backgrounds. The skeleton panels that superseded ChatLayoutLoading paint tiles only, so the overlay had become fully transparent and whatever the stack layout was showing underneath bled through — which is how the discarded Home page was visible in the first place. Device-verified: runtime HomePageLoader warnings went from 3 to 0, and no HomePage type is instantiated during startup. * perf(chat): release the section skeleton before the messages view builds Two fixes to what the centre panel waits for and what it builds. The section skeleton — the one that draws its own input bar — covered the entire message build instead of handing over to the per-chat skeleton. centerPanelReady is `centerPanelLoader.status === Loader.Ready`, and that loader did not resolve until the messages view had finished, even though chatMessagesLoader is asynchronous: incubated alongside the column, it is what the column's own Loader ends up waiting on. Gate chatMessagesLoader on the centre panel having reported Ready, so the shell appears first and the messages fill in behind the per-chat skeleton — the behaviour the surrounding comments already described. Measured on a Redmi A5, from the chat tap: the repeater's loader used to sit 2553ms after ChatContentView had already been created; it now takes 15ms. Section skeleton retires at ~950ms instead of 3546ms. Note this re-orders work rather than removing it — time to messages on screen is roughly unchanged; what changes is that the user gets real chrome and a usable composer about 2.5s earlier. Second, a chat was given a content view without ever having been shown. setActiveItem latches loaderActive, and the section build calls it for the restored last-open chat — which in portrait is never displayed, because the centre panel is lazy. Opening a different chat therefore built two content views, and the one nobody was looking at held the GUI thread for 2183ms after the tapped chat was already ready. Build on "has been the active chat while this column existed" instead; the backend latch still governs lifetime from there. Kept in QML rather than changing the Nim latch so desktop is unaffected: there the column exists from section load with the restored chat active, so it is marked shown immediately. * fix: match the startup overlay to the shape the section opens on In portrait the chat section lands on the left panel — the chat list — but the startup overlay drew the centre panel: chat header, message rows and an input bar. The layout therefore changed under the user the moment the real section arrived. Show the chat-list skeleton in portrait and keep the three-panel arrangement for landscape. Also corrects the panel colours. They were taken from the ChatLayoutLoading view this overlay replaced, which used secondaryMenuBackground; the chrome it now stands in for uses baseColor4 for the side panels and the section background for the centre (StatusSectionLayoutPortrait, Landscape). * fix: don't assert a section title in the startup overlay The startup overlay paints before the backend has said which section is active, but it drew MessagesListHeader — which hardcodes the title "Messages" and offers invite / start-chat / search. None of that is right for a section that may turn out to be a community, and in that mode the header's signals are not connected, so the two enabled buttons rendered as tappable and did nothing. Give MessagesListSkeleton a `sectionKnown` flag. When false it draws a placeholder row of the same shape — headline left, three round buttons right — sized from the same theme values so it follows the font-size setting. ChatLoader keeps the default and the real, working header. `createChatOpened` stops being an alias: the header now sits behind a Loader, and an alias into a deferred subtree does not work. * test(chat): pick channel rows the view has actually placed The reorder and click tests picked their rows by scanning the list's contentItem for StatusChatListItem and sorting by scene y. A ListView incubates its cache-buffer delegates asynchronously, and an incubating delegate is already parented, visible and sized but not yet positioned, so it sits at y 0 and ties with the real top row. Under load it won the sort, the upward drag then started on the real top row and dragged it out of the list into no drop target, and no reorder ever landed. Select rows through itemAtIndex instead, which only ever returns placed delegates, and settle on those too. The gesture retry added for the same red is gone: it was treating a symptom, and the drag lands first try in 90 loaded offscreen runs.