A Tab opened to display a downloaded file is no longer a browsing Tab.
`profileParams` gains an orthogonal `localPreview` flag; it selects a
profile of its own — always off the record, never named — with no
injected scripts, no web channel and no connector.
The local-URL policy splits along the same line: browsing profiles reach
no file:// at all (a local path in the address bar dead-ends), and only
the preview profile reaches the downloads and player-page directories.
The default profile, which backs views whose storage profile could not be
created, carries the browsing policy either way.
WebEngine views drop localContentCanAccessRemoteUrls everywhere and grant
localContentCanAccessFileUrls to previews alone, so the player page can
load the media beside it.
Stack-target: PR 21853
Retry correlation moves into DownloadsStore: armRetry mints the token and
attachDownload reattaches the Record the Backend echoed it with. That
replaces the URL match plus 10s expiry timer in the context — an unanswered
arm can no longer capture an unrelated Download of the same URL, so there
is nothing to expire.
The context no longer walks the Tab strip. It asks the host to re-issue on
a profile (downloadUrlFn) and reports who a Download belongs to
(downloadAttributed); BrowserLayout owns both platform answers. On desktop
the re-issue runs on a transient WebEngine page owned by the profile, so a
Retry now works with no matching Tab open at all — the Tab was only ever a
profile carrier there. Viewless re-issues reach QML through ProfileManager,
which needs no Tab either.
The pristine-popup close moves to BrowserLayout with the rest of the Tab
knowledge; its coverage went with it, and BrowserLayout has no test seam.
Stack-target: PR 21851
Three facts about opening a downloaded media file were baked in as one global
answer. All three belong to the Backend, so they join
BrowserBackendCapabilities beside inPageMediaPlaybackSupported.
proprietaryCodecsSupported. M4A/AAC and MP4/H.264 were excluded everywhere
because our Qt WebEngine build ships without the licensed codecs — a fact about
that build, not about WebKit or the Android WebView, which decode them through
the OS. On iOS a page's inline player played an mp4 while the same file, once
downloaded, went to the share sheet.
mediaPlayerPageRequired. The generated player page exists only because WebEngine
turns a top-level navigation to local media into a fresh Download. Keeping it
everywhere is what broke iOS playback: the page sits in TempLocation, the media
in the downloads directory, and a plain local load grants the web content
process only the file it was handed — so the page came up and the audio in it
never loaded.
loadFileUrl(fileUrl, readAccessUrl) joins the Web View seam beside loadUrl,
implemented by both adapters and proxied by LazyWebViewAdapter — the
seam member easiest to forget. The grant is left empty, so it resolves to the
file's own directory: the narrowest one that works.
Nothing is deleted — a Backend answering "yes" still gets the page, so falling
back is one line. Verified on an iOS device: mp3, mp4 and webm all open in a Tab
with a native player.
Introduce the downloads domain per ADR 0006 (added here):
- DownloadRecord is the one list identity. Live Backend downloads attach
to Records; UI reads Records only, never live download objects.
- DownloadsStore owns downloadModel / downloadStripModel (session-only
pills) / downloadsListModel (newest-first view) as JS arrays of
Records, behind a single injectable 'platform' seam. Download History
persists via the browser preferences mechanism (create + terminal
states only) — keys and raw accessors land in BrowserPreferenceKeys /
BrowserPreferencesStoreBase alongside the Tab Session ones.
- BrowserDownloadOpenContext is the extracted open seam: it decides the
open route per Record — direct navigation, a generated local player
page for media (player/media_player.html|js), or the platform opener —
and defines the only file:// URLs the browser may navigate to.
- DownloadFormatUtils.js centralizes the open-allowlist predicates and
file-name eliding; Record byte counts are doubles, so large (>2^31)
download sizes survive.
- Browser CONTEXT.md documents the finished downloads design.
Tested in tst_DownloadsStore (platform seam faked as one object) and
tst_BrowserDownloadOpenContext; the Storybook DownloadsStore stub stays
an empty QtObject — pages and tests mock inline.
Records two decisions that belong together, because caching only decides how
often the bytes cross the network while the CDN URL decides how many bytes
there are: HTTP caching for collectible media stays in the QNetworkDiskCache
that the QML engine's network access factory installs rather than moving behind
the status-go media server, and list-sized media is asked for by rewriting the
Cloudinary delivery URL where the render size is known.
Also records, as an accepted risk, that the factory gives every manager its own
QNetworkDiskCache pointed at one shared directory — which Qt documents as
unsupported. Measured with a probe in create(): two managers in Storybook's
remote mode, a third in the application where XHR from QML takes the engine's
own manager. The consequence is that the size cap is enforced against each
cache's partial view of the directory, and that the statistics screen has to
measure the directory itself rather than ask any one cache.
- SendModalHeader / StickySendModalHeader / SimpleSendModal: document the
roles the terminal picker model actually exposes
- CollectiblesSelectorModel: give filteredFlatModel a NOTIFY signal so the
QML binding that reads it stops warning
- assets_view module: tear the controller down like token_selector does
- ADR 0005: describe the float-at-UI contract and note BuyCryptoModal still
layers proxies above the terminal model
Add finishTyped/takeTyped: a worker parks a fully-built, exclusively-owned
object graph in a registry and delivers only an integer handle across the
queued-invoke bridge, so the GUI slot moves (not copies, not re-parses JSON)
the graph into place. ORC/ARC only; compile-guarded on -d:useMalloc. Includes
the cross-thread soak test and ADR-0004.
Document the umbrella platform sentinel in status-desktop, mobile
status-go delegation model, and the superseded iOS Nim-runtime symbol
localization workaround now fixed upstream in nim-sds v0.2.5.
Focuses mostly on documenting what to do before the RC cut.
Also removes mentions of the release board. It seems that working on the normal milestone board worked well.
- normalize notification id
- parse the status-go json for errors
- hook setUIVisible(false) on android app crash
- make sure setUIVisible doesn't block the main thread
- properly identify group chat notifications
Add an option to run status-go as a service on android using Androdi Binder as a transport.
See ADR for more details docs/adr/0001-android-status-go-as-a-service.md
* docs(epic-workflow): add epic delivery guide on how to manage epics
* docs(epic-workflow): add QA sub tasks to list
* chore: add a new point
* chore: update guide link
* docs(release): add release process guide for internal contributors
* docs(release): clarify who must cherry-pick
* docs(release): update critical bugs and how to version
Adapts the docs and different mentions of the repo from status-desktop to status-app
Also adapts the docs to talk about the Status App and not just Status Dekstop. Adds links to the Mobile build too.