Commit Graph
243 Commits
Author SHA1 Message Date
Jonathan Rainville 93a204cb92 refactor(emoji): move ascii emoji map to C++ to increase performance 2026-08-24 09:14:04 -04:00
Jonathan Rainville 1a6d3b376c fix(chat): convert plaintext emoticons to emojis again
Fixes #22037

The StatusChatInput refactor dropped the ASCII emoticon conversion that
used to run off the old text area's onTextChanged handler, so typing
":)" stayed ":)" instead of becoming 🙂.

Restore it at the layer that owns caret and text structure. ChatTextArea
gains an opt-in asciiEmojiConversion property and a convertAsciiEmoji()
function: it matches the word ending at the caret against the emoticon
table, longest alias first, and requires a whole word at text/line start
or after whitespace. Conversion is triggered from Keys.onPressed on
space and enter, before the key's own insertion, and from the existing
InputMethodEventFilter for on-screen keyboard commits.

Emoji gains a lazily-built alias_ascii lookup, replacing the old linear
scan over the whole emoji list on every keystroke, and the highlighter
gains replaceTextWithEmojis() so a conversion is a single undo step.
StatusChatInput enables the property and force-converts in
tryFinalizeMessage(), so "hello :)" sent without a trailing space is
converted too.

Unlike the previous implementation, emoticons inside code spans and code
blocks are now left verbatim.
2026-08-24 09:14:04 -04:00
Alex Jbanca 98b70ae653 perf(statusq): event-loop-driven QML incubation controller (#21921)
* perf(statusq): event-loop-driven QML incubation controller

The QQuickWindow default incubation controller collapses its time budget
when frames are slow, starving async Loaders exactly when load is
heaviest — on low-end devices this stretches section incubation into
multi-second skeletons. Drive incubation from a permanently armed timer
instead: 20ms slices per event-loop tick, a 12ms gentle phase during the
first 300ms of a burst so section-switch animations keep their frame
budget, and a 128ms idle backstop so a missed count callback can never
wedge incubation. Input stays responsive between ticks.

A/B on the community section page (STORYBOOK_INCUBATION_MS=20, gentle
phase off): idle machine 857 -> 441ms for a 210-channel load; CPU-
contended machine (the low-end condition) 5.4-8.1s with the default
controller vs a flat 400-490ms with this one.

* fixup! perf(statusq): event-loop-driven QML incubation controller

Without it the QML test engine runs async Loaders on Qt's render-loop
budget — the configuration the benchmark measured at tens of seconds per
section load, and the one nothing in the app ever uses. Tests were pinning
a configuration that does not ship, and paying for it with 120 s waits.

externc casts to QQmlEngine now: the test harness owns a plain one, not a
QQmlApplicationEngine. The HomePage grid lookup waits for its delegate
instead of assuming it exists on the same tick.

* fixup! perf(statusq): event-loop-driven QML incubation controller

* chore(statusq): env-gated incubation debug HUD

STATUS_INCUBATION_HUD=1 shows a top-right overlay with the live incubator
count (16ms refresh + 1s peak) and the controller pacing phase
(idle/gentle/boost, plus held gentle hints). Debug-only; drop before merge
if unwanted.
2026-08-22 08:13:53 +03:00
Lukáš Tinkl e348b4caa8 feat: display restart prompt when the base screen DPR changes
- move the `nativeWindowDpr` handling up to AppMain, initialize it with
a small delay when the appMain is ready; also track the current `screen`
in order not to restart when the user just moves the window between
screens
- on Android, add a dedicated DensityListener to emit the needed signal
for us; the Android QPlatformScreen/QPlatformWindow doesn't
(re)implement the needed `devicePixelRatio()` methods
- add a simple ConfirmationDialog (with bottom sheet) asking for restart
when the native/base DPR changes
- adjust SB page, update TS files

Fixes #21915
2026-08-18 00:59:53 +02:00
Michał Cieślak e897132bb1 StatusQ: compilation warnings (QQmlPropertyMap, QMouseEvent) fixed 2026-08-14 21:30:49 +02:00
Lukáš Tinkl 44621ab17c fix(Notifications): use a real DBUS backend on Linux
- using the standard `org.freedesktop.Notifications` DBUS backend/API;
see https://specifications.freedesktop.org/notification/latest-single/
for details
- allows tracking the OS Notifications, including being clicked/closed
by the user and navigating Status to the respective section/chat/channel
like other OSs
- fully async using DBUS pending call/watcher paradigm, no more fire and
forget using a cmd line wrapper (`notify-send`)

Iterates #2520
Iterates #21292
2026-08-14 14:20:41 +02:00
Andrey Bocharnikov 50ef59a117 feat(browser): isolate the Tabs that show a downloaded file
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
2026-08-13 09:42:17 +04:00
Andrey Bocharnikov 2ddf84ae5f feat(browser): carry a correlation token through the Download seam
downloadUrl takes an opaque token and downloadRequested hands it back, on
both Backends and through every adapter. Nothing between the two reads it —
it exists so the caller of a host-side re-issue can recognise its own
Download by identity instead of by URL plus a timing window. Downloads the
host did not re-issue carry an empty token.

BrowserProfileUtils keeps the token beside the initiating view in its
per-page map, and that view may now be null: a re-issue no longer needs a
live Web View to start from.

Stack-target: PR 21849
2026-08-13 09:42:17 +04:00
Andrey Bocharnikov 524a6a5b76 feat(browser): make the media open route a set of Backend Capabilities
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.
2026-08-13 09:42:17 +04:00
Andrey Bocharnikov 85383de2ae feat(browser): platform download plumbing and the web view download seam
Extend the cross-platform web view seam with the download vocabulary the
Downloads feature builds on (ADR 0006):

- AbstractWebView: DownloadState gains DownloadPaused (WebEngine-shaped
  numbering, Paused = 5 matches MobileWebViewDownload), a host-side
  downloadUrl() re-issue used for Retry, a linkLongPressed(link, image,
  position) signal for mobile Backends, supportsPdfViewer, and a
  'retained' flag for Web Views kept alive after their tab closes.
  The downloadsStore / isDownloadView coupling is gone: adapters map
  Backend downloads into the seam and the UI never branches on Backend.
- WebViewAdapter / MobileWebViewAdapter / LazyWebViewAdapter implement
  the seam; the desktop path gains an injectable isBrowsableLocalUrlFn
  local-URL guard exception, and LazyWebViewAdapter forwards Retry
  through ensureLoaded().
- ProfileManager survives a WebEngine profile data-path collision.
- StatusQ C++: BrowserProfileUtils (QWebEnginePage::download re-issue,
  profile plumbing) and SystemUtilsInternal additions, iOS share-sheet
  support via NSItemProvider in ios_utils.mm, Android accept path in
  StatusQtActivity, mobilewebview pin bump, and Common.mk tracks
  CMakeLists.txt so the pin invalidates mobile builds.
2026-08-13 09:42:17 +04:00
Lukáš Tinkl 8fddc0c46e feat: close popups on clicking a push notification
- add a signal `closePopupsRequested()` to NIM, and add a helper
function that walks over the potentially closeable Popups, and tries to
close them
- small fix for the Linux OS Notification impl to match the actual
appName now

Fixes #21292
2026-08-12 22:41:01 +02: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
Andrey Bocharnikov fee211d783 feat(StatusQ): account for the QML layer's HTTP traffic and cache it to disk
The QML engine gets a network access factory that hands out managers with a
disk cache and per-host accounting, so every image, animation and XHR the QML
layer issues can be seen and capped.

HttpStats is a GUI-thread singleton recording per-host totals split by whether
the bytes came from the network or from the cache. Bytes are taken from
downloadProgress rather than Content-Length, which is absent on some responses
and wrong on chunked ones. It is constructed on the GUI thread before any
factory worker can first-touch it with the wrong QObject affinity, and it
reports a finished cache clear on its own cacheCleared() signal — separate from
changed(), which fires on every reply and so cannot be what a reader hangs an
expensive re-measurement on.

The cache takes an explicit budget instead of Qt's 50 MB default, which a
single collectibles page can evict on its own.

The factory also sends Accept: image/webp,image/png,image/jpeg on Cloudinary
delivery URLs, so the f_auto in the rewritten media URLs has something to
resolve against. The list is narrow on purpose: f_auto returns AVIF or JPEG XL
to a client that claims them and Qt decodes neither. It is a statement about
this client's decoders, which is why it lives here and not in QML — see
docs/adr/0006-qt-http-cache.md.

All of it lives in networkaccessfactory.{h,cpp} rather than in externc.cpp,
which exists to be a thin C-ABI shim for Nim: the shim now casts the engine
pointer and delegates. That also lets Storybook install the same factory, so
media traffic measured on a Storybook page is the traffic the application
produces — and it lets the Accept policy be tested, which as a static function
in a .cpp with no header it could not be.

TestHttpStats and TestNetworkAccessFactory cover the thread affinity, both
clear paths, and the Accept policy as a table.
2026-08-06 14:26:30 +04:00
Michał Cieślak e990f9610f Chat input: outdated StatusSyntaxHighlighter removed 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
Michał Cieślak dbaae91ff3 MarkdownUtils: add mention(txt) method to extract mention keys form a raw message 2026-08-05 08:40:31 +02:00
Michał Cieślak 86411f5213 ChatTextArea: code format button handling both 2026-08-05 08:40:31 +02:00
Michał Cieślak 8c70dab159 InputMethodEventFilter introduced 2026-08-05 08:40:31 +02:00
Michał Cieślak 09b790950b ChatTextArea/ChatTextView: labeld links support added
Closes: #21548
2026-08-05 08:40:31 +02:00
Michał Cieślak 3bfddd054f ChatTextArea: removeFormatting aligned 2026-08-05 08:40:31 +02:00
Michał Cieślak 571164ed14 ChatTextArea: emphasisAtInsertion removed 2026-08-05 08:40:31 +02:00
Michał Cieślak 40c4a236f9 ChatTextArea: adding formatting for selection 2026-08-05 08:40:31 +02:00
Michał Cieślak 4ea9ca77e3 ChatTextArea: removeDelimitersAtSelection inroduced 2026-08-05 08:40:31 +02:00
Michał Cieślak ccb14b285e ChatTextArea: delimitersAtSelection introduced 2026-08-05 08:40:31 +02:00
Michał Cieślak c157148995 ChatTextArea: introduce removeDelimitersAt removing delimiters around given position 2026-08-05 08:40:31 +02:00
Michał Cieślak f112a673a0 ChatTextArea: introduce delimitersAt detecting delimiters around given position 2026-08-05 08:40:31 +02:00
Michał Cieślak fe285186c3 ChatTextArea: removeFormatting(...) introduced 2026-08-05 08:40:31 +02:00
Michał Cieślak 04e8e7cea7 ChatTextArea: nodeAt(pos) exposed 2026-08-05 08:40:31 +02:00
Michał Cieślak 1779f1c953 ChatTextView: image-based emojis support 2026-08-05 08:40:31 +02:00
Michał Cieślak 20e0c8a2c5 ChatTextArea: image-based emojis support 2026-08-05 08:40:31 +02:00
Michał Cieślak 6252b928d5 Chat edit/view: support for wallet links added 2026-08-05 08:40:31 +02:00
Michał Cieślak 024dad97c0 Markdown: conversion to plainText added (for accessibility) 2026-08-05 08:40:31 +02:00
Michał Cieślak d4ac23d82b Chat: ChatSingleLineTextView introduced 2026-08-05 08:40:31 +02:00
Michał Cieślak 6ba89c8ab4 ChatTextView: enlarged emojis when text is only emojis + whitespaces 2026-08-05 08:40:31 +02:00
Michał Cieślak 92ebc07268 Chat: enlargeEmojis renamed to fullLineHeightEmojis 2026-08-05 08:40:31 +02:00
Michał Cieślak d0b8dfb665 ChatTextView/ChatEditView: dimmed quote block text color 2026-08-05 08:40:31 +02:00
Lukáš Tinkl 4321f4b88e fix(ScreenZoom): unbreak baseline DPR on Android
- use a native JNI call to get the base (native) DPR of the underlying
window/screen, as the Android QPA doesn't implement/overrride the
`QPlatformScreen::devicePixelRatio()` and always returns `1.0f`
- reduce the min/max range to `[0.75,1.5]` of the baseline

Fixes #21543
2026-07-28 10:03:53 +02:00
Lukáš Tinkl a6db0bddc7 fix(StatusEmojiPopup): fix incorrect/duplicate recent emojis
- move the settings to the popup/model, simplifying and centralizing the
responsibilities when saving/loading the recent emojis
- wrap the `MessageReactionsRow` quick actions bar into a `Loader`,
delaying its construction for after the model and recent emojis have
been fully loaded; there was a race condition between the 2 sides
because the StatusEmojiModel lives inside a QML singleton, and hence
being constructed at startup before anything else
- adapt the Storybook page

Fixes #21490
2026-07-23 01:22:51 +02:00
Lukáš Tinkl f71e0573d5 feat(Notifications): implement the badge notification count
- tied to the global AC notifications count
- use the `QGuiApplication::setBadgeNumber(int num)` everywhere to set
the actual value
- fixup and move the qApp static initialization to NIM, simplify the
global signal code path/propagation
- bump `vendor/nim-seaqt` to the Qt 6.8 branch

Fixes #20872
2026-07-21 12:16:39 +02:00
Andrey Bocharnikov 81e79ddcb7 refactor(browser): simplify clear-site sync with sentinel cookie callback
Replace the QML clear state machine and addressed signal with a QJSValue
callback and a Mojo-ordered sentinel cookie barrier in C++, so completion
is per-caller without pending-name counters or navigation guards.
2026-07-17 17:00:51 +04:00
Andrey Bocharnikov b33751c46e fix(browser): isolate clear-site completion per tab
Address clearSiteDataCompleted to the initiating adapter, run site and
profile clears through one state machine with navigation/origin guards,
and settle cookieRemoved only for host-matching names.
2026-07-17 17:00:51 +04:00
Andrey Bocharnikov 79b60e2ea1 fix(browser): clear site HttpOnly cookies via live name index
Qt 6 loadAllCookies no longer re-emits existing cookies, and overwrites
arrive as cookieRemoved only — track cookie names from cookieAdded and
delete by name+URL. After clear, navigate with GET so POST Set-Cookie
is not replayed.
2026-07-17 17:00:51 +04:00
Andrey Bocharnikov 4039e987a8 feat(browser): clear site cookies via BrowserProfileUtils and DOM via site_utils
Desktop clear site/browsing data now deletes host cookies (incl. HttpOnly) in
C++, then wipes current-origin DOM storage through injected site_utils.js.
2026-07-17 17:00:51 +04:00
Andrey Bocharnikov d38dfef5cd fix(browser): clear browsing data via BrowserProfileUtils
Desktop clearBrowsingData was stuck because QML WebEngineProfile has no
cookie API and the old clearCache path threw before the fallback timer.
Add BrowserProfileUtils (QtWebEngine-only) to clear HTTP cache + cookies,
and align the QML API with the UI (clearBrowsingData / clearSiteData).
2026-07-17 17:00:51 +04:00
Michał Cieślak 3171502963 ChatTextArea/ChatTextView: colors exposed, Theme colors used 2026-07-10 01:20:38 +02:00
Michał Cieślak 960de25505 MarkdownParser: mentions support added 2026-07-10 01:20:38 +02:00
Michał Cieślak ac0bc90b53 ChatTextView: enlarge emojis to fill whole line height 2026-07-10 01:20:38 +02:00
Michał Cieślak 3b06d68a7c ChatTextArea: custom copy/paste preserving mentions and custom external paste 2026-07-10 01:20:38 +02:00
Michał Cieślak eaef436c40 ChatTextArea: expose info related to mention input 2026-07-10 01:20:38 +02:00
Michał Cieślak 4a8a83a510 ChatTextArea: quote block auto-continue and fine-tuned delete behavior 2026-07-10 01:20:38 +02:00