Commit Graph

350 Commits

Author SHA1 Message Date
Peter Steinberger
e4d8a2a55b fix(android): preserve TLS hostname context (#105072)
* fix(android): preserve TLS hostname context

Co-authored-by: whisky0809 <32197959+whisky0809@users.noreply.github.com>

* style(android): order TLS test imports

* style(android): group TLS test imports

---------

Co-authored-by: whisky0809 <32197959+whisky0809@users.noreply.github.com>
2026-07-12 08:32:03 +01:00
Peter Steinberger
46355cbdcf fix(android): stop canceled work from surfacing failures (#105047)
* fix(android): propagate request cancellation

* chore: keep release notes in PR body
2026-07-12 07:22:27 +01:00
WhatsSkiLL
604c026409 fix(android): keep session search in context (#104792)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>
2026-07-12 06:27:07 +01:00
WhatsSkiLL
86b10ffb8e Android: polish workspace file navigation (#104873)
* fix(android): polish workspace file navigation

* fix(android): serialize workspace file requests

---------

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>
Co-authored-by: Colin Johnson <colin@solvely.net>
2026-07-12 00:03:46 -04:00
Vincent Koc
32631fdfac refactor(android): remove retired voice wake stack (#104914)
* refactor(android): remove retired voice wake stack

* chore(android): refresh native i18n inventory
2026-07-12 11:52:51 +08:00
Peter Steinberger
ac89350327 feat(apps): review durable approvals on mobile (#104913)
* feat(apps): Android, iPhone, and Watch approval clients

Squash-rebased #103912 segment onto the deep-links tip on current main.
Native approval surfaces: iOS approval presentation with gateway-switch
lease preservation and resolution fencing, watchOS inbox + approval
actions with shipped-shape payload codec, Android approval notices with
publication-tokened dismissal. Native i18n inventory regenerated.

(cherry picked from commit 428a76670ffeede54248b7bd7aa4438e2589851b)
(cherry picked from commit 80225d5707c3645eeea5435f266131037b50ede6)
(cherry picked from commit 2a23b714dc30d773a294aa45adc617e46b80732e)
(cherry picked from commit 9ff1153827769e2cbab7c11c153f0f8634662c28)
(cherry picked from commit 5b25723525bd562e5f97478af492f7b46ad30fd1)
(cherry picked from commit 8c80e8467b5fe89aad0d4c74a0573f1600ed3af9)
(cherry picked from commit ad4037bc9846bf6f082b41c129ee68aa344576c3)
(cherry picked from commit fdf767dd662cff3c8a5a6d571f38f153410651ca)
(cherry picked from commit 00c120376ffd992ea68ce29254a9bc0a25ed1740)
(cherry picked from commit f36a95213e)
(cherry picked from commit e2c25cbe2baacab44d21871d8cb6734704f065ac)
(cherry picked from commit 7c4fda519080486d341a9f4df36d63f9e24b1235)
(cherry picked from commit 1b3d4eda3dc5988012124597f9454ae21fb187a1)
(cherry picked from commit 2a60619722)
(cherry picked from commit 6f0c386567)
(cherry picked from commit 784a5857b7)
(cherry picked from commit cbf294e026841c9bc2799da0fc7db666a69c52db)

* fix(apps): harden approval reconciliation and watch states
2026-07-11 19:59:07 -07:00
snowzlmbot
be373ea516 improve(android): show provider-configured model details (#101912)
* feat(android): show provider model inventory

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>

* fix(gateway): project provider inventory routes

* style(android): satisfy provider inventory ktlint

* chore(android): sync provider inventory i18n

* style(android): finish provider inventory formatting

* fix(android): harden provider inventory refresh

* test(gateway): type provider inventory fixture

* chore(protocol): regenerate Swift model choice

* chore(android): sync provider inventory i18n

* test(gateway): pin provider inventory discovery mode

* chore(android): sync provider inventory landing

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
2026-07-11 17:22:16 -07:00
Igor Guarisma
4147345bcd feat(android): show agent avatar instead of first-letter badge (#103248)
* feat(android): render configured agent avatars

Co-authored-by: Igor Guarisma <igor.guarisma@gmail.com>

* style(android): satisfy avatar ktlint

* style(android): fix avatar test formatting

* style(android): align avatar test indentation

* fix(android): initialize safe image client first

* chore(android): sync avatar i18n inventory

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-11 17:07:46 -07:00
NianJiu
d1f614c9e6 feat(android): add system share target (#104571)
* feat(android): receive system shares safely

Co-authored-by: NianJiuZst <3235467914@qq.com>

* fix(android): preserve share FIFO in composer

* fix(android): serialize cross-task share imports

* chore(android): sync share import i18n

* fix(android): retry shares in resumed composer

* chore(android): sync resumed share i18n

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-11 16:44:34 -07:00
Josh Avant
793fe4bfc7 fix(android): require installed-apps disclosure consent (#97888)
* fix(android): require installed-apps disclosure consent

Co-authored-by: Josh Avant <830519+joshavant@users.noreply.github.com>

* chore(android): sync native i18n inventory

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-11 15:56:12 -07:00
NianJiu
b5bea9073d fix: recover Android permission request timeouts (#103011)
* fix(android): recover permission request timeouts

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>

* chore(android): sync native i18n inventory

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
2026-07-11 15:35:41 -07:00
NianJiu
d85e8a5f23 fix(android): restore sticky node service (#104226)
Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
2026-07-11 04:45:43 -07:00
NianJiu
26dc42aa37 fix(android): cancel expired node invokes (#104225)
Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
2026-07-11 04:43:00 -07:00
Peter Steinberger
1c08d96d8b feat(android): durable offline chat with attachments and history-proof retirement (#104089)
* feat(android): durable offline chat with attachments and history-proof retirement

Every chat send is journaled to the per-gateway Room outbox before any
network attempt, so process death always has one durable recovery owner.
Rows survive gateway ACKs as 'accepted' and retire only once the turn is
proven in canonical chat.history by idempotency key; ambiguous outcomes
(lost ACK, kill mid-send, gateway restart before the transcript write)
park as delivery-unconfirmed for explicit retry, per the fail-closed
model #103273 landed. An unproven accepted head briefly holds only its
own session's queue, and retrying a parked head re-orders still-queued
successors behind it. Offline sends now accept picked images and voice
notes; attachment bytes persist as chunked BLOBs (512 KB chunks, 8 MB
per message, 48 MB per gateway) admitted and retired atomically with
their row. Pre-hello 'main' rows pin to the canonical session at first
dispatch so later default-agent changes cannot retarget captured input;
slash commands are connection-gated by a persisted epoch (legacy queued
command rows migrate to a never-matching sentinel) and never auto-replay
across reconnects. The Room store moves to schema v4 on top of v3's
data-parking migration, adding the epoch column and attachment tables
while preserving queued rows. The queued->sending claim is an atomic
compare-and-set shared by the direct dispatch and the flush loop, the
direct path waits for the startup recovery sweep before claiming, and
failed reconnect attempts republish outbox rows so queued sends stay
visible on offline cold starts.

Proof: 1151 Android unit tests and :app:ktlintCheck green (new
migration, storage, and controller coverage for admission, restarts,
claims, pinning, gating, ordering, and byte round-trips); a live
emulator scenario on the pre-integration build queued text+image
offline, survived force-stop plus a device reboot, resent exactly once
on reconnect (single <rowId>:user turn in the gateway transcript), and
drained the outbox after canonical-history confirmation.

Closes #104087.

* fix(android): rearm outbox recovery when direct-send state persistence fails

* fix(android): keep direct dispatch alive across caller cancellation

The direct send's network phase now runs in the controller scope, so a
cancelled UI scope (leaving the chat screen mid-send) can no longer
strand a claimed row in 'sending' with no user action available; the
dispatch completes and settles the row exactly once. Direct-path state
persistence failures also re-arm the startup recovery sweep, mirroring
the flush path's fail-closed handling.

* fix(android): hand claim-persistence failures to the flush lane

A direct-send claim that fails to persist no longer reads as a lost race:
the admitted row is handed to the flush lane so a healthy connection still
delivers it, and the flush path's fail-closed handling owns any repeated
storage failure instead of the UI reporting success with no active owner.

* fix(android): enforce connection gating and fail-closed parking on every send path

The direct dispatch now rechecks a slash command's connection epoch after
its durable claim, so a reconnect between admission and dispatch parks the
command instead of replaying it on the new connection. Parking a stale
gated row only counts once the write persists; a storage failure drops
health, re-arms recovery, and halts the flush pass instead of spinning or
dispatching the stale row.

* fix(android): recognize gateway-acknowledged run ids in outbox ownership checks

A chat.send ACK can return a run id that differs from the row's
idempotency key (the direct path transfers local run ownership to it).
Ownership, in-flight, backlog, and timeout-park checks now consider both
ids, so reconciliation can no longer park — and Retry can no longer
duplicate — a turn that is still running on the gateway.

* fix(android): close remaining ack-ownership and persistence-failure gaps in the outbox

Flushed sends acked under a divergent run id now transfer local run
ownership like the direct path, so live runs cannot time out and surface
spurious errors for delivered turns. A session pin that cannot persist
stops the dispatch while the row is still safely queued. Reconcile and
timeout parking only report changes their writes actually persisted,
failing closed on storage errors.

* docs(android): record why acknowledged run ids stay in-memory
2026-07-10 22:12:25 -07:00
NianJiu
df36c821a4 fix(android): require explicit retry after interrupted sends (#103273)
* fix(android): require retry after interrupted outbox sends

* fix(android): fail ambiguous outbox sends closed

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>

* fix(android): preserve run-id-only acknowledgements

* style(android): format outbox assertion

* fix(android): fail outbox recovery closed

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>

* test(android): prove dropped ack is not replayed

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>

* fix(android): accept terminal outbox acknowledgements

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>

* fix(android): persist rejected outbox retries

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>

* fix(android): require manual retry after transmitted failures

* fix(android): migrate ambiguous outbox rows safely

* test(android): import outbox cancellation type

* fix(android): limit destructive chat cache migration

* fix(android): guard outbox retry transitions

* fix(android): reject malformed chat acknowledgements

* test(android): type migration bind arguments

* test(android): separate migration and replay proof

* fix(android): accept admitted outbox acknowledgements

* fix(android): preserve gateway health after acknowledged outbox failures

* fix(android): stop outbox flush on persistence failure

* fix(android): stop outbox flush when claims fail

* fix(android): enforce durable outbox barriers

* fix(android): coalesce outbox flush requests

* style(android): format outbox assertions

---------

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 19:41:40 -07:00
WhatsSkiLL
5c38f62b27 [AI-assisted] Make Android chat thinking selection explicit (#103893) 2026-07-10 22:27:56 -04:00
Peter Steinberger
7fe004d852 feat: show build identity in About screens (#103595)
* feat: show build identity in About screens

* chore: leave root changelog to release automation

* fix: translate Control UI About build details
2026-07-10 10:42:36 +01:00
Josh Avant
fc60a8e66b fix(android): show Canvas outside Settings (#103330)
* test(android): reproduce detached canvas lifecycle failures

* fix(android): restore shell-owned canvas presentation

* fix(android): avoid canvas renderer crash loops

* fix(android): keep canvas within safe drawing bounds

* fix(android): cover canvas inset gutters

* chore(android): refresh native i18n inventory

* fix(android): keep canvas host lint-clean

* style(android): format canvas host documentation
2026-07-10 04:20:53 -05:00
Peter Steinberger
1696366f88 feat(android): add safe cron job management (#102997)
* feat(android): add safe cron job management

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>

* fix(android): harden cron editor state

* fix(android): preserve cron state across lifecycle

* fix(android): satisfy cron release gates

* fix(android): retain cron drafts outside saved state

* fix(android): scope cron auto-delete to one-shot jobs

* fix(android): use Compose activity owner

* docs(changelog): note Android cron management

* fix(cron): harden Android job management

* chore(i18n): refresh Android cron inventory

* test(cron): cover enriched read views

* chore(changelog): defer Android cron note to release

---------

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
2026-07-10 04:12:18 +01:00
NianJiu
05d17289c9 fix(android): order disconnect after in-flight gateway work (#103068)
* fix(android): drain gateway events before disconnect callback

* chore(android): refresh native i18n inventory

* chore(android): refresh native i18n inventory

---------

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-10 01:51:51 +01:00
Peter Steinberger
c6d7088035 refactor(android): align talk levels and thinking state with iOS/macOS (#103130)
* refactor(android): align talk levels and thinking state with iOS/macOS

TalkAudioLevel.kt ports OpenClawKit's level scale exactly: PCM16 RMS
through the shared 50 dB window replaces mean-abs (mic/talk/playback)
and linear peak (voice notes), so Android waveforms read identically to
iOS/macOS at the same loudness. The waveform's Thinking phase now comes
from a typed awaitingAgent StateFlow set alongside every status change
in TalkModeManager instead of the UI matching status string literals;
forgetting the flag at a new status site fails safe to Listening/Idle.

* fix(android): keep awaiting-agent flag intact on no-op status republishes

* chore(i18n): resync native inventory
2026-07-09 23:59:12 +01:00
Peter Steinberger
af6a58a2ba refactor(android): remove orphaned sheet composer (#103094) 2026-07-09 21:25:22 +01:00
Ben.Li
1d4c17073c fix(android): keep link preview metadata UTF-16 safe (#102988)
* fix(android): keep link preview metadata UTF-16 safe

* refactor(android): share UTF-16-safe truncation

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 20:58:18 +01:00
Peter Steinberger
20816f676f feat(voice): universal talk waveform driven by real audio levels (#102901)
* feat(voice): universal talk waveform driven by real audio levels

One shared Siri-style talk animation across iOS, watchOS, macOS, and
Android (TalkWaveformView + exact Compose port), replacing per-platform
fakes: synthetic speaking pulses, constant speech-detected power, static
Android bar rows, flat realtime listening. Listening/recording follow
live mic levels on every route; agent speech follows the real playback
envelope (AVAudioPlayer metering + playback-aligned PCM envelope +
WebRTC stats); voice-note recording shows a live capture wave.

* fix(android): order waveform imports and sync native i18n inventory

* chore(i18n): resync native inventory after rebase
2026-07-09 16:33:25 +01:00
Peter Steinberger
d9f8fc6322 feat(android): add system app language selection (#102876)
Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
2026-07-09 15:27:36 +01:00
Vincent Koc
cb7468fc58 refactor(android): remove orphaned legacy screens (#102809) 2026-07-09 06:02:30 -07:00
Peter Steinberger
411bf2ad4b test(android): cover discovery and startup gates (#102758)
* test(android): cover discovery and startup gates

Co-authored-by: NianJiuZst <180004567+users.noreply.github.com>

* test(android): keep startup gate tests keystore-free
2026-07-09 13:25:40 +01:00
Peter Steinberger
66db3024bc test(android): cover main activity lifecycle gates (#102764) 2026-07-09 13:04:57 +01:00
snowzlmbot
6fef79a28d feat(android): add Skill Workshop settings panel (#101911)
* feat(android): add Skill Workshop settings

* fix(android): scope Skill Workshop state by agent

* fix(android): confirm Skill Workshop proposal actions

* fix(android): strengthen Skill Workshop action proof gates

* fix(android): satisfy Skill Workshop action ktlint

* fix(android): serialize Skill Workshop lifecycle actions

* chore(android): refresh native i18n inventory

---------

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 12:07:04 +01:00
NianJiu
67be0cda44 fix: cancel Android link preview calls (#101853)
* fix: cancel Android link preview calls

* test(android): cover response cancellation stage

* fix(android): preserve link preview deadline

* docs(android): clarify cancellation contract

---------

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 09:21:50 +01:00
Ben.Li
3e787f3187 fix(android): preserve UTF-16 boundaries in notification text (#102442)
* fix(android): keep notification text UTF-16 safe

* test(android): cover UTF-16 notification boundaries

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-09 08:11:32 +01:00
joshavant
f163f32f85 fix(android): make release screenshots deterministic 2026-07-09 01:32:13 -05:00
Josh Avant
6438c89f05 fix(mobile): clarify gateway connection security setup (#101325)
* fix(mobile): clarify gateway connection setup

* chore(i18n): sync native mobile strings

* fix(mobile): align manual gateway previews

* chore(i18n): refresh native source inventory

* chore(android): remove unused connect tab strings

* test(i18n): drop removed connect tab sentinel

* fix(ios): brand connection security picker labels

* fix(mobile): hide gateway endpoint previews

* chore(i18n): sync native source inventory

* fix(mobile): remove redundant TLS helper copy
2026-07-07 14:43:11 -05:00
Peter Steinberger
3d53ed7ed8 fix(android): keep cold-start gateway auto-connect from overriding explicit intents (#101799)
* fix(android): keep cold-start gateway auto-connect from overriding explicit intents

NodeRuntime's init-time auto-connect now atomically claims the first gateway
lifecycle intent (CAS 0->1) and stands down permanently when any explicit
connect/disconnect/switch intent already exists, so a late discovery emission
can no longer override a user decision. This was also the root cause of the
CI-only flakes in GatewayBootstrapAuthTest (refreshGatewayConnection_* at
:616/:627 and switchToUndiscoveredGateway* on PRs #101002/#101387/#101396).

GatewaySession.Connection.sendRequestFrame now starts its response watcher
with CoroutineStart.ATOMIC: disconnect teardown cancels connectionJob right
after failPending(), and a DEFAULT-start watcher still queued for dispatch was
cancelled without running, silently dropping the terminal UNAVAILABLE onError
owed to fire-and-forget callers (root cause of the flaky
GatewaySessionInvokeTest.disconnectReportsUnknownOutcomeForFireAndForgetRpc).

Tests neutralize runtime background work (cancel+join the runtime scope)
before arming the registry and scripting lifecycle steps, and add regression
coverage for the auto-connect intent claim.

Proof: refresh flake reproduced at iteration 1 under taskset -c 0,1 on a
Blacksmith Linux box; post-fix 3 pinned stress rounds (120/150 looped
iterations) plus full :app:testPlayDebugUnitTest (109 classes, 0 failures)
and :app:ktlintCheck green on the same box.

* chore(i18n): resync native inventory line positions after NodeRuntime edits
2026-07-07 18:51:46 +01:00
Peter Steinberger
16348ddec3 feat(android): render LaTeX display math in chat via bundled KaTeX (#101435)
* feat(android): render LaTeX display math in chat via bundled KaTeX

* fix(android): preserve fallback for invalid math

* docs(changelog): note Android display math

* Revert "docs(changelog): note Android display math"

This reverts commit 40356286a3.
2026-07-07 11:57:24 +01:00
Peter Steinberger
903a09ab85 fix(android): bound link preview image cache (#101560) 2026-07-07 11:22:52 +01:00
Peter Steinberger
6125dd95e6 feat(android): og:image thumbnails on link preview cards (#101396) 2026-07-07 10:42:03 +01:00
Peter Steinberger
9cd29dcb9a test(android): stabilize saved gateway reconnect proof (#101519) 2026-07-07 10:30:14 +01:00
Vincent Koc
6799b5b3d4 refactor(android): remove obsolete global cache cleanup (#101470) 2026-07-07 01:19:17 -07:00
Josh Avant
531c7a5f4c fix(android): preserve hardware Enter key sequences (#101360) 2026-07-07 00:25:33 -05:00
Peter Steinberger
b337164916 ci: fail Android PRs on ktlint formatting drift (#101275)
* style(android): fix ktlint drift in ShellScreen.kt

Formatting drift landed via #101161; :app:ktlintCheck fails on main
without this. Generated with ./gradlew :app:ktlintFormat.

* ci(android): add ktlint lane to the Android CI job

Android formatting drift kept landing on main because CI never ran
ktlintCheck (see the #100304 manual sweep). Adds an android-ktlint
matrix lane mirroring pnpm android:lint.

* chore(i18n): sync native inventory after ShellScreen.kt format

The ktlint format fix shifted line numbers tracked in
apps/.i18n/native-source.json; regenerated via pnpm native:i18n:sync.

* style(android): fix new ktlint drift in NodeRuntime and ChatHardwareKeyTest

Import-order/blank-line drift landed via the hardware-Enter changes
(#101321 and follow-up) while this PR was open — the exact recurrence
the new android-ktlint lane prevents. Generated with ktlintFormat;
native i18n inventory resynced for the shifted line numbers.
2026-07-07 05:01:26 +01:00
Peter Steinberger
780ca1d253 fix(android): send chat with hardware Enter (#101321) 2026-07-07 04:36:06 +01:00
Blaine Perry
06c18e232d feat(android): add chat agent selector (#80422)
* feat(android): add live chat agent selector

Co-authored-by: Blaine Perry <blainecperry@gmail.com>

* fix(android): keep agent selector on canonical session

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 04:14:55 +01:00
Peter Steinberger
b2cecd8ece feat(android): hide thinking control and gate sends for models without reasoning support (#101002) 2026-07-07 03:23:08 +01:00
Vincent Koc
7bbe75089a test(android): isolate gateway bootstrap prefs 2026-07-07 03:35:58 +02:00
Colin Johnson
82106a18b3 fix(android): stabilize recent sessions overview (#101161) 2026-07-06 21:20:06 -04:00
Peter Steinberger
4c97aa1311 feat(mobile): rename, delete, and create session groups on iOS and Android (#101234)
* feat(mobile): rename, delete, and create sidebar session groups on iOS and Android

Group section headers on the iOS Command Center sessions screen and the
Android sessions screen gain Rename/New/Delete group actions. Bulk ops
enumerate every member (active + archived, explicit high list limit since
the gateway caps an absent limit at 100 rows) and patch category per
session; delete keeps sessions and moves them to Ungrouped. Known custom
groups persist client-side (iOS UserDefaults, Android SharedPreferences)
so empty groups stay visible as move targets.

* chore(i18n): refresh native string inventory after rebase onto main
2026-07-07 01:09:57 +01:00
Peter Steinberger
93eaf5affb feat(android): server-backed session search with offline fallback (#101102)
The sessions screen gains a debounced search field under the filter pills,
wired to server-side sessions.list search in Recent and Archived scopes.
Results flow through the existing filter/sort/grouping pipeline so pinned
and grouped rendering stay intact while searching.

ChatController.fetchSessionList performs the one-shot search without touching
live list state, falls back to locally filtering the cached active list when
the gateway is unreachable (archived rows exist only server-side, so archived
search is empty offline), and rethrows CancellationException before the
fallback so a superseded search never repaints stale rows over a newer query.

Refs #100712
2026-07-07 00:03:28 +01:00
Peter Steinberger
ef1767baca feat(android): record and send voice notes from the chat composer (#101193)
* feat(android): record and send voice notes from the chat composer

Adds tap-to-record voice notes to both Android chat composers: MediaRecorder
AAC/m4a mono capture with a 3-minute cap, lazy RECORD_AUDIO permission,
cancel/finish controls, audio attachment chips with duration, and voice-note
transcript rows. Recording is mutually exclusive with MicCaptureManager voice
capture (no mic arbiter exists), and the MPEG-4 container brand is normalized
to M4A so gateway byte sniffing classifies the upload as audio, not video.
Attachments stay online-only per the outbox contract.

Related: #100709

* fix(android): coordinate voice note microphone ownership

* chore(android): refresh native localization inventory
2026-07-06 23:54:44 +01:00
Peter Steinberger
d931839e0c feat(android): multi-gateway registry, per-gateway credentials, and switching (#100947) 2026-07-06 23:31:49 +01:00