Commit Graph
1466 Commits
Author SHA1 Message Date
Anastasiya a6728b41f3 chore(@e2e): update requirements.txt 2026-08-24 09:38:15 +03:00
Anastasiya 03eedba8f0 chore(@e2e): fix eth-accounts 2026-08-24 09:38:15 +03:00
Alex Jbanca 27a1e20c6b perf(chat): virtualize the chat and contacts channel lists (#21943)
* perf(chat): virtualize the chat and contacts channel lists

StatusChatList's ListView now owns its viewport instead of expanding to
contentHeight inside an outer ScrollView, which built every delegate up
front (~2.4ms per chat, no ceiling). Row heights are fixed constants so
the list never needs to build a delegate to know its geometry.

- StatusChatList: hardcoded chat/category row heights; hosts size the
  list; drag-and-drop is untouched and keeps working in the interactive
  list (preventStealing, reorder within the viewport)
- CommunityColumnView: ScrollView dropped; the admin banners move into
  the list footer so they still scroll below the channels
- ContactsColumnView: ScrollView dropped, list fills the column

Verified by tst_ContactsColumnVirtualization and the reworked
tst_CommunityChatLoaderSection (member and admin lists virtualized,
drag reorder, banner footer).

* perf(chat): incubate the contacts column and center panel asynchronously

The two panels are now built off the critical path, so the loader-owned
chrome paints its skeletons immediately and each slot swaps in as its own
panel finishes. This is only safe here: the channel and contact lists are
virtualized by this branch, and the message view attaches its model on
first show (lazy-load-messages), so async incubation no longer walks the
whole chat history or builds a delegate per channel.

* fixup! perf(chat): incubate the contacts column and center panel asynchronously

The 120 s ceilings were sized for a test engine running async Loaders on
Qt's render-loop budget; the boosted controller now installed in the test
harness makes them a way for a wedged suite to look like a slow one. The
whole suite runs in ~6 s.

Also spells out that contactColumnLoader's explicit size covers the
parentless incubation phase and the anchors take over afterwards.

* fixup! perf(chat): virtualize the chat and contacts channel lists

Harden the drag-reorder tests: wait for every panel's ready flag and
for row geometry to settle before the gesture (rows materialize under
async incubation and shift mid-drag), drop the irrelevant 2000-message
payload, and give the drop target a rendered frame between the final
move and the release. Failure rate goes from ~2-in-3 to ~1-in-12 on a
fast machine; the residual escape is still open (task tracking).

* refactor(chat): drop ChatsLoadingPanel, superseded by the section skeletons

The section skeleton chrome shows skeleton rows for the chat and community
columns while the section loads, so the "Loading chats..." strip below the
search box is a second, competing loading affordance.

Both call sites go with it. `chatsLoaded` has no remaining QML consumer, and
neither view uses anything else from shared.panels, so those imports are
dropped too.

* chore: update translations

* perf(chat): filter collapsed-category rows out of the chat list

Zero-height delegates were still instantiated by the ListView, so a
large collapsed category cost hundreds of delegates despite the
viewport bound. The visibility predicate now lives in the backend as a
cached per-row "hidden" role (recomputed on dependent-field writes,
never in data()), and StatusChatList drops hidden rows with a plain
ValueFilter so they never reach the view. Covered by chat_section
model tests and a large-collapsed-category virtualization test.

* fix(chat): chat list review fixes — scrollbar geometry, handler captures

- StatusChatList owns the scrollbar space: the list reserves it via its
  own rightMargin and delegates/footer size to availableWidth, so the
  overlaid scrollbar sits at the column edge instead of covering row
  controls; hosts drop their external right margins
- context-menu handlers capture signal params explicitly instead of
  relying on deprecated injected parameters
- guard contactColumnLoader.item deref while the panel incubates
- restore the master menu pattern: onClosed destroy() belongs to
  adminPopupMenuComp itself

* test(chat): drop timing-fragile instant row-count assertions

The skeleton tests asserted how many delegate rows existed at the exact
instant a skeleton cleared, racing delegate incubation against the
Loader.Ready swap — deterministic-fail under the offscreen platform and
flaky under CI's Xvfb. The skeleton coverage checks stay; row population
is now awaited with tryVerify instead of sampled at the swap instant.

* chore: update translations
2026-08-22 08:13:54 +03:00
Alex Jbanca 68eb973c84 perf(chat): lazy, async member loading for user list and mention suggstions (#21920)
* perf(chat): lazy, async member loading for user list and mention suggestions

The members panel builds on first show only (latched), asynchronously
behind MembersListSkeleton — it must never delay a chat switch. Once
built, UserListPanel binds its users model only while the right panel is
actually visible, and it adopts the shared MembersPanelHeader introduced
with the skeletons. The mention suggestions adaptor stays detached from
the members model until the first mention entry (short wire delay,
loading skeleton in the suggestion box meanwhile; the latch drops on
usersModel swap so chat switches never pay for sorting the members
model). Together these were ~1.5s of the chat-switch freeze on large
communities.

* fixup! perf(chat): lazy, async member loading for user list and mention suggestions

The members panel is shared across the section's chats, so once built it
stayed visible through a chat switch: it showed the previous chat's
members while sorting the incoming model on the switch frame. A latch
drops it back behind MembersListSkeleton on every active-chat change and
re-arms on a short delay, the same shape as the mention suggestions
wiring. rightPanelReady now follows the loader it was named after.

* fixup! perf(chat): lazy, async member loading for user list and mention suggestions

Keying the latch on the active chat id dropped it on every switch, but a
community channel without permissions hands the view the *same* members
model object — so the panel was torn down and fully re-sorted for nothing,
on the dominant path. Key it on the model identity instead: same object,
same members, no work; different object, the protection the latch is for.

rightPanelReady must fold the latch in, or the chrome retires its members
skeleton exactly while the panel is showing one. membersWireDelay moves
into `d` (tests reach it through the view's private object), and the
panel's own skeleton is released like the others rather than kept alive
and hidden.

The switch test now targets the permissioned channel, whose model really
differs, and a new test pins that the shared-model switch costs nothing.

* fixup! perf(chat): lazy, async member loading for user list and mention suggestions

Extract the fully-wired CommunityChatLoader test harness (mock stack,
loader wiring, type-prefix finders) into a shared helpers component.
The members-skeleton suite is the first consumer; the community section
suite above adopts it at the next stack rebase, removing ~90 duplicated
lines per suite.

* chore: update translations

* perf: sorted users_model and PR comments

* perf: Avoid swapping skeleton for the real view when swipeview animations are running

* chore: update translations

* chore: update translations
2026-08-22 08:13:52 +03:00
Alex JbancaandAnastasiya bd3fccc449 perf: load the chat and community sections asynchronously with skeletons (#21917)
* perf: load chat and community sections asynchronously with skeletons

The section loaders own the chrome (StatusSectionLayout) and show the
matching skeleton — with the real, functional header — while the actual
section incubates behind an asynchronous Loader; the section's panels
are proxied back into the loader-owned chrome once ready (full-page
community views hide it). The communities portal loader turns
asynchronous too. The pre-ready startup overlay recomposes from the
skeleton panels, replacing the ChatLayoutLoading placeholder view (whose
AppMain reference had been left dangling).

* fixup! perf: load chat and community sections asynchronously with skeletons

Each skeleton slot was gated on the whole section loader reaching Ready, so
the header, chat list, message column and member list all swapped in at once,
paced by the slowest panel. ChatView now publishes per-panel readiness and
ChatLayout forwards it, letting each slot retire on its own. `root.item` is
null until the section itself loads, so the old whole-loader behaviour remains
the floor.

The right panel is not deferred at this point in the stack, so its flag is
constant; it becomes meaningful once the members panel moves behind a loader.

Also drops `signal ready()` from both section loaders: `mainReady` is fed to
AppMain by AppMainLoader and nothing has ever connected to `ready`, so the
signal and the comment claiming AppMain owns the spinner toggle are both dead.

* fixup! perf: load chat and community sections asynchronously with skeletons

The startup overlay predates the loader-owned chrome. ChatLoader and
CommunityChatLoader declare their skeleton panels as plain children, which Qt
instantiates and paints even while the loader is inactive, so for the chat
section the overlay now covers an already-correct skeleton with a duplicate of
itself.

Scoped to the two cases where nothing else paints yet: the communities portal
(CommunitiesPortalLoader is gated on mainReady and owns no skeleton), and a
community section during the window where activeSectionType is already
`community` but the repeater has not produced any delegate — the same window
the currentIndex fallback below already accounts for.

* fixup! perf: load chat and community sections asynchronously with skeletons

Release the chrome skeletons instead of hiding them: permanent
visible:-gated skeletons re-evaluate their tile geometry bindings on
every resize for the lifetime of the section (same class as the
ChatContentView messages skeleton, caught in a resize profile). Each
skeleton now lives behind a Loader gated on its slot's readiness.

* fixup! perf: load chat and community sections asynchronously with skeletons

The slots fell through to the real panel as soon as `root.item` existed.
ChatView's panels are non-null Loader objects from the moment the section
loads, so `?? skeleton` never saw the readiness flags: the LayoutItemProxy
retargeted to an empty Loader, released the skeleton with
setParentItem(null)/setVisible(false), and the slot painted nothing until
the panel incubated. Gate each slot on its own flag instead.

The skeletons collapse to bare Loaders keyed on `!ready`, dropping the
wrapper Item whose `visible` the proxy also writes.

tst_SectionLoaderChrome drives both loaders with a stub section whose
flags are writable, so the contract is pinned as a binding rather than as
a race against incubation.

* fixup! perf: load chat and community sections asynchronously with skeletons

The startup overlay's only remaining case was a community section with no
repeater delegate yet, and it painted the chat-list skeleton there — wrong
shape, replaced a frame later by CommunityChannelsSkeleton. Keep the
overlay for the communities portal, which has nothing else painting, and
let a missing community delegate fall back to the currentIndex loader,
which already shows the right shape.

* fixup! perf: load chat and community sections asynchronously with skeletons

* chore(@e2e): fix tests according to the changes

* fixup! perf: load chat and community sections asynchronously with skeletons

* fixup! perf: load chat and community sections asynchronously with skeletons

---------

Co-authored-by: Anastasiya <anastasija.ig@gmail.com>
2026-08-22 08:13:51 +03:00
Anastasiya d2e639a549 tests(@e2e): fix password change tests and reduce timeout to 5 seconds 2026-08-21 23:22:58 +02:00
Sale Djenic 64ca2fb8ca feat: fast password change with optional rekey
Profiles on the DEK encryption scheme change their password by re-wrapping the profile key file
means no database re-encryption, no restart.

The change-password modal has options:
- do fast password change re-wrap the DEK
- do deep password change in case of legacy profiles (one-time migration), or the new profiles for
  which "also re-encrypt my data" (rekey) checkbox is checked

Closes #21877
2026-08-21 23:22:58 +02:00
Andrey Bocharnikov 8415c54eee fix(contract): point wakuext gate at pkg/services after the status-go move
The gate still read services/wakuv2ext, so CI treated a present submodule
as missing. Skip .claude so nested worktrees are not scanned as call sites.
2026-08-21 20:27:38 +04:00
Andrey Bocharnikov 391969226f feat(settings): add a Storage stats section to Advanced
A bug reporter can now export a quantitative profile of their own account -
message counts, per-chat distribution, sync gap, wallet and per-table sizes -
and paste it into a ticket. Reproducing status-im/status-app#21605 cost days
precisely because that shape had to be guessed.

Pressing Collect data starts the status-go walk and returns; the section then
shows a real "N of M" (status-go enumerates the table list before counting
anything), a small histogram of chats by message count, a few headline
numbers, and a Copy to clipboard button carrying the profile as JSON. The
same JSON is written into the log directory, so the existing "collect logs"
flow bundles it with no extra wiring - and the timestamp in its name is what
makes its age visible once bundled.

Nothing is collected until the button is pressed: COUNT(*) on a sqlcipher
table is a full decrypting scan, and the whole point of this feature is to
describe an account's performance, not to degrade it. The result is kept by
the service for the session, because this page is built by a Loader and would
otherwise throw away minutes of scanning every time the user navigates away.

The section is gated on non-production builds. Turning it on in production is
a separate change with its own privacy review.
2026-08-21 16:21:35 +04:00
Anastasiya 3a17fec992 chore(@e2e): document generating the local Waku fleets JSON 2026-08-21 13:59:35 +03:00
Anastasiya 233fa7d065 chore(@e2e): remove keypair renaming test in favor of QML 2026-08-20 17:17:44 +03:00
Anastasiya df11b74877 test(@e2e): import recover phrase onto keycard from settings 2026-08-20 17:17:44 +03:00
Anastasiya cfa05c2a14 chore(@e2e): fix object types 2026-08-20 15:56:15 +02:00
Anastasiya 1f8f216215 chore(@e2e): update macOS script for Squish setup 2026-08-20 15:16:15 +03:00
vedran 50e12af8b5 ci(@e2e): dynamic waku fleet ports with scanner
Replace static port mapping with ephemeral Docker ports and a
scanner script that discovers host-mapped ports at runtime,
generating the fleet config dynamically. This removes the need
for a lock on Linux (parallel E2E runs per agent). Windows
keeps the lock due to GUI/Squish constraints.
2026-08-19 10:33:35 +02:00
Lukáš Tinkl 6d4aa0faf8 chore: optimize img file sizes
- using `optipng` for lossless recompression and optimization

Fixes #22023
2026-08-19 00:44:24 +02:00
Anastasiya 02a2c944b8 test(e2e): run transaction tests on Sepolia and L2 testnets 2026-08-18 19:02:31 +03:00
Anastasiya f278df2da1 chore(@e2e): update readme 2026-08-18 18:14:30 +03:00
Sale Djenic a552d09a50 fix: logs scattered across the local data folder and never cleaned up
- redirect all logs into logs/ dir
- pass logDir (InitializeApplication), logFilePath (CreateAccount) and the new Login.logFilePath
to status-go, so pre_login.log, api.log and the per-profile 0x….log land in logs/
- one-time startup migration moves closed log files from data/ into logs/ dir
- make the Advanced setting default 10, range 1..50
- "Old logs" shows the total log size in MB with a refresh button

Fixes #22016
2026-08-18 17:03:50 +02:00
Anastasiya e5d1e7b413 chore(@e2e): wait for port for simulator 2026-08-18 15:49:29 +03:00
Mag. e0085abd7c test(e2e_appium): dismiss introduce-yourself sheet (#22004)
* test(e2e_appium): dismiss introduce-yourself sheet

Since #21947 the sheet opens on first entry to Messages when the profile
has no display name, which e2e profiles never set, and it blocks all
navigation lookups. Add a dismissal guard in the nav rescue path, same
pattern as the backup-modal guard. Verified on device: navigation
returns in ~66s on a fresh profile vs a 15.5-minute timeout before.

Assisted-by: Claude Fable 5 (Anthropic)

* test(e2e_appium): reuse ChatLocators skip locators in screen_identity

Point INTRODUCE_MODAL_SKIP and BACKUP_MODAL_SKIP at the ChatLocators
constants instead of redeclaring the same test-ids, so each objectName has
one home.
2026-08-17 19:16:57 +01:00
Sale Djenic 0a249131e6 chore: reduce account and keypair name minimum length to 1 char
Closes #20715
2026-08-17 08:44:00 +02:00
Mag. f887e8442f fix(e2e_appium): detect edited-message indicator, un-xfail test_edit (#21377)
#21368 exposed the "(edited)" indicator to accessibility, so match it with a
chatMessageViewDelegate-scoped locator (the bubble is a TextView) and un-xfail
test_edit. The edited text is now " v2", so its content-desc reads "v2 (edited)".

Assisted-by: Claude Opus 4.8 (Anthropic)
2026-08-15 15:57:53 +01:00
Anastasiya 0f49c7a9da feat(@ci): extend benchmarks job to support PRs and releases 2026-08-15 09:47:22 +03:00
Andrey Bocharnikov d3113837aa test(wallet): kept collectibles entries must expose refreshed ownership
Covers the diff-update path of the collectibles Model through its public
surface: when updateItems receives an entry whose ID is already in the
model but whose ownership submodel data changed (balance bumped, extra
owning account), the kept entry must expose the NEW balances and emit
itemsDataUpdated so the views re-read it. A byte-identical refresh must
report no change at all, so the grid does not re-render on every poll.

RED on the parent commit: the kept entry is left untouched, so ownership
still reads the old balance/account and no signal is emitted. GREEN with
the follow-up fix that refreshes kept entries through the role diff.
2026-08-15 10:45:29 +04:00
Anastasiya 4e9d03c4f2 chore(@e2e): check if biometrics popup is displayed when devices are synced (on Mac) 2026-08-14 15:03:32 +03:00
Anastasiya dafe67bf2a tests(@e2e): drop ephemeral toast asserts 2026-08-13 21:00:54 +03:00
Anastasiya 5efb81423f chore(@e2e): make clicking community link cross platform 2026-08-13 14:07:51 +03:00
Anastasiya 5d1dd6ad38 fix(@e2e): stop orphaned AUT processes on teardown 2026-08-13 13:53:04 +03:00
Anastasiya b99af5c386 fix(keycard): make packaged simulator work on Linux and Windows 2026-08-13 10:41:26 +03:00
Alex Jbanca 20c41f73d9 fix(ios): paste without triggering the system paste permission prompt (#21799)
* fix(ios): paste without triggering the system paste permission prompt

On iOS any programmatic read of UIPasteboard shows the "Allow Paste?"
alert. Our Paste buttons read the clipboard directly, so they prompted
every time. Replace them with UIPasteControl, where the system performs
the read and hands over the contents, making the tap itself the consent.

- add NativePasteButtonItem, hosting a native UIPasteControl, and the
  StatusPasteButton wrapper (native on iOS, StatusButton elsewhere)
- use it for every Paste button: sync code, WalletConnect URI,
  watch-only address, private key, chat key and both send recipient
  inputs
- disable AppMain's passive clipboard watcher on iOS: it read the
  clipboard with no user action at all, which is what prompted on launch
- drop the now-dead iOS guards left over from #21365

A native view composites above the whole Qt scene, so the control is
clipped to its visible viewport and hidden whenever something is stacked
above it - a popup over the page, or another popup over the one holding
it. That state is recomputed per frame from afterAnimating and pushed to
UIKit only when it changes; it must not call polish(), which requests a
new frame and would keep the window rendering forever.

The paste completion captures the target view rather than a raw C++
pointer, so a control destroyed while the item provider loads - closing
the modal it lives in - cannot deliver into freed memory.

Desktop keeps its existing Paste button styling: the wrapper forwards
size, border, font weight and focus policy, and each site passes what it
used before. Desktop buttons are now disabled rather than always enabled
when the clipboard has no text.

Also track *.mm in STATUS_Q_FILES: the mobile build only watched .cpp
and .h, so no Objective-C++ change in StatusQ ever triggered a rebuild
and stale binaries were shipped to the simulator.

Text editors are unaffected: StatusTextArea is a Controls TextArea, so
long-press gives the OS edit menu, whose Paste the system authorises.

Closes #21438

* fix(StatusPasteButton): apply review feedback

- base the wrapper on Control and forward the font group, so a site can
  set the label's family, weight or pixelSize. They are forwarded one by
  one on purpose: StatusBaseButton binds each of them itself, and a
  whole-group `font:` assignment is silently ignored - verified by
  checking that a bigger pixelSize actually widens the button.
- keep the wrapper out of the tab chain. Control brings its own
  focusPolicy, so the button's is `buttonFocusPolicy`; otherwise the
  composite would add a tab stop in front of the button.
- derive the Qt -> UIKit scale from the window's devicePixelRatio over
  the view's contentScaleFactor rather than parsing QT_SCALE_FACTOR. The
  ratio is exactly the extra Qt scaling, whatever asked for it.
- mark foregroundColor/backgroundColor REQUIRED: UIKit picks each tint's
  default on its own, so setting only one can leave the glyph unreadable
  against the fill.

* fix(NativePasteButtonItem): make the zero-scale guard obvious

contentScaleFactor was already checked before the division, but far
enough above it to read like an unguarded divide. Bail out on the null
view and window first, then guard the divisor right where it is used.
2026-08-12 17:29:55 +03:00
Anastasiya 4acdfba962 tests(@e2e): import known seed onto card and create profile with keycard simulator 2026-08-12 12:46:00 +03:00
Jonathan Rainville 7f5842eee1 feat: add asynchronous old log cleanup
Fixes #21151

Add a Clear old logs action to Advanced settings that deletes closed log files
while preserving logs from the active session.

Run asynchronous startup retention to remove closed log files older than 14 days
from the application log and data directories.
2026-08-11 13:16:20 -04:00
Anastasiya 8e4b6e0650 tests(@e2e): send stickers in chat 2026-08-10 18:53:33 +03:00
Jonathan Rainville 8aa4a98ee2 perf(ac): move AC counting to an async task and use events for display
Make activity center notification counts asynchronous, coalesce concurrent refreshes, and update cached UI counters through a resolved event. Add focused tests for aggregation and stale-result handling.
2026-08-10 11:44:47 -04:00
Jonathan Rainville 9f6c889b4f fix(badge): update app badge to count all notifications
Fixes #20872

Updates the app badge to be the sum of section notification counts with non-messaging Activity Center notifications, excluding mentions and replies to avoid double counting.
2026-08-10 11:44:47 -04:00
Anastasiya e285fde4a6 chore(@e2e): changes reflecting updated implementation 2026-08-09 00:10:11 +02:00
Anastasiya a25bf3aa89 chore(@e2e): wait for geometry of button in onboarding screen 2026-08-06 18:31:56 +03:00
Andrey Bocharnikov db89a19793 fix(wallet): send picker renders previews, not full-size originals
The picker's top-level delegate bound model.thumbnailUrl and the Nim model
behind it has no such role — CollectibleItem never carried a thumbnail url at
all. QML tolerates that: the binding read undefined and fell through to
model.imageUrl, the provider's full-size asset, into a 32pt icon. D8 named this
leak; the rewrite closed it on the QML side only, and the production path is the
Nim model.

Two more renders in the same path were reading originals outright. The sublist
delegate rendered `icon` (imageUrl || mediaUrl) with no delivery rewrite at all,
so not even the width cap reached it, and the send modal's selected-token header
took imageUrl || mediaUrl into a 24pt icon while the doc comment beside it
already promised a thumbnail.

The contract now falls along the seam it belongs on. The model picks WHICH asset
a small render gets — thumbnail, else image, else animation — and hands it over
unsized; the delegate, the only place that knows its own render size, asks the
CDN for that width. thumbnailUrl travels from the producer through the DTOs to
both views' roles, and is diffed like the other media roles because it arrives
after the row is already on screen. imageUrl and mediaUrl were missing from the
flat model's diff for the same reason and are added.

The builder test asserted the old pick, so it was protecting the bug. The role
contract is covered where it broke: the model test checks the thumbnailUrl role
exists on both views, and the host integration scene stringifies every role it
reads, so one that goes missing arrives as "undefined" instead of silently
falling through to the original.
2026-08-06 14:26:30 +04:00
Anastasiya fd90ae1f5f chore(@e2e): fix for nightly failures 2026-08-06 10:08:13 +03:00
Jonathan Rainville 4403471726 feat(settings): implement Logos Network settings design
Fixes #21711

Implements the Figma design. Creates a storybook page for the Logos Network settings. Extracts the CountdownProgressIndicator to a shared component.
2026-08-05 15:04:12 -04:00
Jonathan Rainville 54a660a132 fix(communities): fix members not populating airdrop list when they join
Fixes #21584

Fixes an issue where newly joined community members could be missing from the Airdrop recipient selector. Revealed Airdrop addresses are now retained when received before the member model is updated, then applied automatically once the member is added. This relies on existing signals and does not trigger additional refetches.
2026-08-05 13:54:07 -04:00
Michał Cieślak 09770ce633 Chat: StatusChatInputNew -> StatusChatInput rename 2026-08-05 14:44:03 +02:00
Alex Jbanca 4483d7eb2d fix(ios): pause/resume services with the app lifecycle and re-point media URLs on rebind (#21687)
* fix(media): re-point cached media URLs when the media server restarts (#47)

iOS suspends the app and kills status-go's local media server; on resume
it rebinds on a NEW ephemeral port and emits mediaserver.started, which
the Nim side never handled — every cached https://localhost:<oldport>/
image URL (chat images, avatars, stickers, link previews, community
icons) went permanently stale.

Key decisions:
- New MediaServerStartedSignal decoded in signals_manager (the enum
  member already existed, so the cheap-triage scan needs no change);
  null-event envelopes decode to port 0 and every rewrite helper treats
  port <= 0 as a no-op.
- One shared helper, withMediaServerPort (app_service/common/
  media_server_url.nim): rewrites the port ONLY for http(s)://
  localhost|127.0.0.1|0.0.0.0:<port> URLs, splicing around the authority
  so path/query stay byte-identical; everything else (remote URLs, data
  URIs, qrc/file paths, port-less URLs) passes through untouched, so
  callers apply it blindly. Desktop stays a no-op: the signal never
  fires there, and an unchanged port rewrites nothing.
- Subscribers rewrite in place + notify: message models (chat + pinned)
  re-emit image-carrying roles via dataChanged; link-preview thumbnails
  are QObjects and emit urlChanged directly; section model refreshes
  community image/banner/icon; contacts service rewrites its
  ContactDetails cache and re-emits SIGNAL_CONTACT_UPDATED per changed
  contact, plus the user-profile singleton's own avatar (its setters
  already no-op on equal values).
- Dropped the contacts service's imageServerUrl field: it was write-only
  dead code (fetched once, never read).

Files: src/app/core/signals/{signals_manager,types}.nim,
src/app/core/signals/remote_signals/mediaserver.nim (new),
src/app_service/common/media_server_url.nim (new),
src/app_service/service/contacts/service.nim,
src/app_service/service/message/dto/{link_preview,link_preview_thumbnail}.nim,
src/app/modules/shared_models/{message_item,message_model,link_preview_model,section_model}.nim,
chat_section chat_content + messages + main module/controller/io_interface
wiring, test/nim/{media_server_url_test (new),message_model_test,
signals_manager_test}.nim

Verified: media_server_url_test 9/9 OK, signals_manager_test 6/6 OK
(incl. 2 new mediaserver.started tests) via make nim-test-run USE_SYSTEM_NIM=1.
message_model_test does NOT link in this arm64 container — pre-existing
nimqml/LTO link failure, reproduced identically on clean HEAD with a
fresh nimcache; the 3 new model tests compile but need CI/another host
to run. Device repro (background 10+ min, resume, images reload) remains
for the human pass.

* fix(build): normalize two 'import Nimqml' casings to the module's real name

discord_message_item and message_transaction_parameters_item imported
Nimqml (capital N) while the vendored module file is nimqml.nim. On a
case-insensitive checkout (Docker-on-Mac bind mount) Nim treats the two
spellings as distinct modules whose nimcache artifacts collide on one
file, so any test pulling in these items (e.g. message_model_test) fails
to link with undefined nimqml symbols. Found while verifying #47.

* refactor(media): deduplicate the media-URL refresh template and drop dead code

Review follow-up to ca5e5c92c, no behavior change:
- Extract the thrice-duplicated compare-rewrite-flag template into
  refreshMediaServerUrl in media_server_url.nim; message_item,
  section_model and contacts/service now share one definition.
- Drop the why-comment copy-pasted verbatim into three controllers;
  the explanation lives on MediaServerStartedSignal and the helper module.
- Remove backend getImageServerURL, dead since its only caller
  (setImageServerUrl) was deleted on this branch.
- Whitespace: trailing newline in signals/types.nim, blank line before
  the appended suite in message_model_test.nim.

Verified: media_server_url_test, message_model_test and
signals_manager_test all pass (nim-test-run recipe); app wiring
compile-checked via app/modules/main/module + contacts service +
section_model with --compileOnly.

* fix(ios): drive PauseServices/ResumeServices from the app lifecycle (#51)

On iOS status-go runs in-process and nothing drove the pausable-services
lifecycle: services never paused on backgrounding (battery cost) and never
resumed on foregrounding, so the media server's listening socket iOS kills
during suspension stayed dead and every cached localhost media URL failed
until app restart (device-confirmed: post-resume image loads get Connection
refused while in-process RPC still works). Resuming now re-runs the full
recovery chain: ResumeServices -> ServiceRegistry -> mediaserver
ToForeground() rebind -> mediaserver.started -> #47/#49's URL refresh.

Key decisions:
- Lifecycle source is StatusQ's UrlSchemeEvent applicationStateChanged
  watcher (already the iOS foreground seam): new appBackgrounded signal
  emitted ONLY on Qt::ApplicationSuspended — Inactive dips from share
  sheets/system alerts never pause; appForegrounded fires on every return
  to Active, so ServicesPauseBridge latches (`paused`) and resumes only
  when it actually paused. Connections are synchronous (AutoConnection,
  same thread): iOS freezes the process right after the state change, a
  queued pause slot might never run.
- Bridge wired only under `when defined(ios)`: Android's service process
  already drives pause/resume from binder visibility (UI process must not
  double-drive), desktop is never suspended.
- Same contract as StatusGoService.java: fetch the service list from
  PausableServices() at each transition (late-registered services picked
  up; empty list — node not running, e.g. login screen — drives nothing),
  then PauseServices/ResumeServices with the JSON name array. The three
  libstatus C exports are bound in new backend/pausable_services.nim
  (vendor/nim-status-go doesn't cover them); errors logged, not fatal.
- Backend calls injected into the bridge as a seam
  (PausableServicesCalls), so the Nim test drives the real StatusQ
  signal emitters against recorders.

Files: src/app/core/services_pause_bridge.nim (new),
src/backend/pausable_services.nim (new), src/nim_status_client.nim,
src/statusq_bridge.nim, ui/StatusQ/{include/StatusQ/urlschemeevent.h,
src/{urlschemeevent,externc}.cpp}, Makefile (test target),
test/nim/services_pause_bridge_test.nim (new)

Verified: services_pause_bridge_test 15/15 OK; full tests-nim-linux 464
OK / 0 failed (chat_section_model_test fails to compile identically on
the clean base — pre-existing, unrelated); nim_status_client Linux path
compile-checked (--compileOnly, exit 0); StatusQ recompiles clean;
libstatus.so exports PausableServices/PauseServices/ResumeServices
(linked by the test). Device criteria (iPhone: photo -> background 10+
min -> resume -> images recover; Android S21: exactly one service-driven
pause/resume, no duplicates) remain for the human pass — iOS paths can't
run in this container.

* fix(tests): reset the fetch counter per case in services_pause_bridge

unittest setup vars are module-scope globals; the int's constant
initializer runs once, so fetches leaked across cases and the two
absolute-count assertions saw the running total.

* fix: Potential fix for pull request finding

* fix(statusq): handle the full application-state enum in watchApplicationState

Inactive is an expected transient dip and stays a no-op; anything else
unhandled now logs a qWarning.

* fix(tests): empty pausable set no longer latches paused, so foregrounding skips the fetch
2026-08-05 14:18:26 +03:00
Anastasiya 555b7d8c14 chore(@e2e): fix locators for messaging tests 2026-08-05 08:40:31 +02:00
Anastasiya 7c415c5b94 chore(@e2e): fix locator due to changes made in QML 2026-08-04 19:07:13 +02:00
Jonathan Rainville 5967953715 feat(sending): update message sending status to use publishing and delivered to use SDS
Fixes https://github.com/status-im/status-app/issues/21598

Updates status-go to get the new logic of how to mark messages as sending and delivered. See status-go commits for more details.

Also, status-app now buffers early sent/delivered/expired status signals until their message DTO is inserted, making message status updates order-independent and preventing messages from getting stuck in `sending` when the signal arrives before the send response.
2026-08-04 11:55:19 -04:00
Anastasiya 90d720e7b6 fix(@e2e): check if wallet address is checksummed in settings 2026-08-04 17:50:17 +03:00
Jonathan Rainville b53180ff9e fix(chat): remove temporary clipboard images after upload
Fixes #21601

Pasted clipboard images were decoded and written to the user's Pictures
directory before being uploaded, leaving orphaned files behind.

Stage these images in the OS temporary directory instead and remove each
generated file after the send RPC completes, including failure paths.

Add coverage to ensure clipboard images are staged outside Pictures.
2026-08-04 09:14:01 -04:00
Anastasiya eb4679d7f2 chore(@e2e): fix tests with auth popup changes 2026-08-04 13:51:03 +02:00