feat: event-driven UI updates for instant channel switching (#15)

* chore: regenerate Cargo.lock after rebase

* fix(ui): add 1s cool-down to prevent double-tap channel join

voiceJoin returns instantly (fire-and-forget protocol), so the
pending-join guard clears before a second tap lands. The cool-down
prevents the rapid channel oscillation and ClientIsFlooding (524)
that results from double-tapping.

* fix(ui): handle ChannelAlreadyIn as success, ClientIsFlooding with backoff

- ChannelAlreadyIn (0x0302): treat as silent success, update UI state
- ClientIsFlooding (0x020c): show localized snackbar, extend cooldown 5s
- Add l10n strings for flooding error (en + zh)

* fix(proto): use Windows TS3 client version for broadest compatibility

Matches Qint's default (Windows_3_X_X__1). Avoids server-side
behavioral differences with TS5 version strings.

* fix(proto): patch tsproto-types to handle short P-256 coordinates

BigInt::to_bytes_be() strips leading zeros, causing WrongPublicKeyLength
when a server's ephemeral key coordinate starts with 0x00. Patch from
EdisonJwa/tsclientlib fix/p256-short-coordinate-pad branch left-pads
coordinates to the P-256 field size instead of rejecting them.

* refactor(core): stop watchdog from emitting SnapshotChanged

The watchdog now serves only as a liveness probe (miss counting for
reconnection). UI updates are handled entirely by the event-driven
delta path (ProtocolDelta → SessionEvent → BridgeEvent → Flutter).

Removes signature tracking and SnapshotChanged emission from the
supervisor loop. The initial snapshot is still fetched via the
Connected event handler in Flutter.

* refactor(ui): remove channel-join cooldown guard

With event-driven deltas the UI updates instantly on channel moves,
so the 1-second cooldown is no longer needed. Double-taps are handled
by the server (ChannelAlreadyIn → success) and the pending-channel-id
guard prevents overlapping requests.

Also removes the _lastJoinCompletedAt field entirely.

* fix(core): reattach event forwarders after reconnect

The reconnect path swapped in a new ProtocolClient but never took
chat_rx, activity_rx, or delta_rx from it. After the first reconnect,
the event-driven UI pipeline was dead.

Fix by extracting spawn_event_forwarders() helper called on both
initial connect and reconnect. Also replaces lossy try_recv+sleep
polling with proper recv().await for push-based delivery.

* feat(protocol): enrich delta schema with all snapshot-visible fields

ClientJoined now carries input_muted, output_muted, is_server_query,
talk_power, talk_power_granted. ChannelAdded/ChannelUpdated now carry
has_password and needed_talk_power. ClientUpdated also carries
is_server_query, talk_power, talk_power_granted.

This prevents local snapshot drift where fabricated defaults could
hide password requirements, talk-power restrictions, or client type.

* refactor: remove dead SnapshotChanged variant end-to-end

SnapshotChanged is no longer emitted since the watchdog was refactored
to liveness-only. Removes the variant from SessionEvent, BridgeEvent,
and the Flutter switch statement. FRB bindings regenerated.

* fix(ci): regenerate license inventory and fix iOS submodule fetch

- Regenerate docs/security/license-inventory.md to match current lockfile
- Remove submodules: true from checkout (causes hard fail on private submodule)
- Add explicit git submodule update --init --depth=1 with || true fallback
- Check silero-coreml/Package.swift instead of directory existence
This commit is contained in:
Edison Jwa
2026-06-03 18:20:33 +09:00
committed by GitHub
parent 2c3c3873dc
commit 808324f374
14 changed files with 1781 additions and 434 deletions
+24 -23
View File
@@ -16,7 +16,7 @@ those terms.
| License | Crate count |
|---------|-------------|
| `Apache License 2.0` | 330 |
| `Apache License 2.0` | 331 |
| `MIT License` | 74 |
| `Unicode License v3` | 19 |
| `BSD 3-Clause "New" or "Revised" License` | 14 |
@@ -67,7 +67,7 @@ those terms.
| windows_x86_64_msvc | 0.53.1 | `Apache License 2.0` | <https://github.com/microsoft/windows-rs> |
| moka | 0.12.15 | `Apache License 2.0` | <https://github.com/moka-rs/moka> |
| tinyvec_macros | 0.1.1 | `Apache License 2.0` | <https://github.com/Soveu/tinyvec_macros> |
| zerocopy | 0.8.48 | `Apache License 2.0` | <https://github.com/google/zerocopy> |
| zerocopy | 0.8.50 | `Apache License 2.0` | <https://github.com/google/zerocopy> |
| allo-isolate | 0.1.27 | `Apache License 2.0` | <https://github.com/sunshine-protocol/allo-isolate> |
| cpal | 0.17.3 | `Apache License 2.0` | <https://github.com/RustAudio/cpal> |
| rustls-platform-verifier | 0.7.0 | `Apache License 2.0` | <https://github.com/rustls/rustls-platform-verifier> |
@@ -90,7 +90,7 @@ those terms.
| serde_spanned | 1.1.1 | `Apache License 2.0` | <https://github.com/toml-rs/toml> |
| toml | 1.1.2+spec-1.1.0 | `Apache License 2.0` | <https://github.com/toml-rs/toml> |
| toml_datetime | 1.1.1+spec-1.1.0 | `Apache License 2.0` | <https://github.com/toml-rs/toml> |
| toml_edit | 0.25.11+spec-1.1.0 | `Apache License 2.0` | <https://github.com/toml-rs/toml> |
| toml_edit | 0.25.12+spec-1.1.0 | `Apache License 2.0` | <https://github.com/toml-rs/toml> |
| toml_parser | 1.1.2+spec-1.1.0 | `Apache License 2.0` | <https://github.com/toml-rs/toml> |
| toml_writer | 1.1.1+spec-1.1.0 | `Apache License 2.0` | <https://github.com/toml-rs/toml> |
| omnom | 3.0.0 | `Apache License 2.0` | <https://github.com/yoshuawuyts/omnom> |
@@ -109,10 +109,10 @@ those terms.
| futures-task | 0.3.32 | `Apache License 2.0` | <https://github.com/rust-lang/futures-rs> |
| futures-util | 0.3.32 | `Apache License 2.0` | <https://github.com/rust-lang/futures-rs> |
| futures | 0.3.32 | `Apache License 2.0` | <https://github.com/rust-lang/futures-rs> |
| typenum | 1.20.0 | `Apache License 2.0` | <https://github.com/paholg/typenum> |
| typenum | 1.20.1 | `Apache License 2.0` | <https://github.com/paholg/typenum> |
| reqwest | 0.12.28 | `Apache License 2.0` | <https://github.com/seanmonstar/reqwest> |
| reqwest | 0.13.3 | `Apache License 2.0` | <https://github.com/seanmonstar/reqwest> |
| http | 1.4.0 | `Apache License 2.0` | <https://github.com/hyperium/http> |
| reqwest | 0.13.4 | `Apache License 2.0` | <https://github.com/seanmonstar/reqwest> |
| http | 1.4.1 | `Apache License 2.0` | <https://github.com/hyperium/http> |
| tokio-rustls | 0.26.4 | `Apache License 2.0` | <https://github.com/rustls/tokio-rustls> |
| pin-utils | 0.1.0 | `Apache License 2.0` | <https://github.com/rust-lang-nursery/pin-utils> |
| ecdsa | 0.16.9 | `Apache License 2.0` | <https://github.com/RustCrypto/signatures/tree/master/ecdsa> |
@@ -123,6 +123,7 @@ those terms.
| async-recursion | 1.1.1 | `Apache License 2.0` | <https://github.com/dcchut/async-recursion> |
| t4rust-derive | 0.3.1 | `Apache License 2.0` | <https://github.com/ReSpeak/t4rust> |
| tsproto-structs | 0.2.0 | `Apache License 2.0` | <https://github.com/ReSpeak/tsclientlib/tree/master/utils/tsproto-structs> |
| tsproto-structs | 0.2.0 | `Apache License 2.0` | <https://github.com/ReSpeak/tsclientlib/tree/master/utils/tsproto-structs> |
| cmake | 0.1.54 | `Apache License 2.0` | <https://github.com/rust-lang/cmake-rs> |
| addr2line | 0.25.1 | `Apache License 2.0` | <https://github.com/gimli-rs/addr2line> |
| ahash | 0.8.12 | `Apache License 2.0` | <https://github.com/tkaitchuck/ahash> |
@@ -132,8 +133,8 @@ those terms.
| backtrace | 0.3.76 | `Apache License 2.0` | <https://github.com/rust-lang/backtrace-rs> |
| base64 | 0.22.1 | `Apache License 2.0` | <https://github.com/marshallpierce/rust-base64> |
| bitflags | 1.3.2 | `Apache License 2.0` | <https://github.com/bitflags/bitflags> |
| bitflags | 2.11.1 | `Apache License 2.0` | <https://github.com/bitflags/bitflags> |
| cc | 1.2.62 | `Apache License 2.0` | <https://github.com/rust-lang/cc-rs> |
| bitflags | 2.12.1 | `Apache License 2.0` | <https://github.com/bitflags/bitflags> |
| cc | 1.2.63 | `Apache License 2.0` | <https://github.com/rust-lang/cc-rs> |
| cfg-if | 1.0.4 | `Apache License 2.0` | <https://github.com/rust-lang/cfg-if> |
| concurrent-queue | 2.5.0 | `Apache License 2.0` | <https://github.com/smol-rs/concurrent-queue> |
| core-foundation-sys | 0.8.7 | `Apache License 2.0` | <https://github.com/servo/core-foundation-rs> |
@@ -145,7 +146,7 @@ those terms.
| crossbeam-epoch | 0.9.18 | `Apache License 2.0` | <https://github.com/crossbeam-rs/crossbeam> |
| crossbeam-utils | 0.8.21 | `Apache License 2.0` | <https://github.com/crossbeam-rs/crossbeam> |
| dbus-secret-service | 4.1.0 | `Apache License 2.0` | <https://github.com/brotskydotcom/dbus-secret-service.git> |
| displaydoc | 0.2.5 | `Apache License 2.0` | <https://github.com/yaahc/displaydoc> |
| displaydoc | 0.2.6 | `Apache License 2.0` | <https://github.com/yaahc/displaydoc> |
| either | 1.16.0 | `Apache License 2.0` | <https://github.com/rayon-rs/either> |
| equivalent | 1.0.2 | `Apache License 2.0` | <https://github.com/indexmap-rs/equivalent> |
| errno | 0.3.14 | `Apache License 2.0` | <https://github.com/lambda-fairy/rust-errno> |
@@ -174,7 +175,7 @@ those terms.
| lazy_static | 1.5.0 | `Apache License 2.0` | <https://github.com/rust-lang-nursery/lazy-static.rs> |
| linux-raw-sys | 0.12.1 | `Apache License 2.0` | <https://github.com/sunfishcode/linux-raw-sys> |
| lock_api | 0.4.14 | `Apache License 2.0` | <https://github.com/Amanieu/parking_lot> |
| log | 0.4.29 | `Apache License 2.0` | <https://github.com/rust-lang/log> |
| log | 0.4.31 | `Apache License 2.0` | <https://github.com/rust-lang/log> |
| matrixmultiply | 0.3.10 | `Apache License 2.0` | <https://github.com/bluss/matrixmultiply/> |
| mime | 0.3.17 | `Apache License 2.0` | <https://github.com/hyperium/mime> |
| ndarray | 0.17.2 | `Apache License 2.0` | <https://github.com/rust-ndarray/ndarray> |
@@ -202,7 +203,7 @@ those terms.
| rustc-demangle | 0.1.27 | `Apache License 2.0` | <https://github.com/rust-lang/rustc-demangle> |
| rustc_version | 0.4.1 | `Apache License 2.0` | <https://github.com/djc/rustc-version-rs> |
| rustix | 1.1.4 | `Apache License 2.0` | <https://github.com/bytecodealliance/rustix> |
| rustls-native-certs | 0.8.3 | `Apache License 2.0` | <https://github.com/rustls/rustls-native-certs> |
| rustls-native-certs | 0.8.4 | `Apache License 2.0` | <https://github.com/rustls/rustls-native-certs> |
| rustls | 0.23.40 | `Apache License 2.0` | <https://github.com/rustls/rustls> |
| scopeguard | 1.2.0 | `Apache License 2.0` | <https://github.com/bluss/scopeguard> |
| security-framework-sys | 2.17.0 | `Apache License 2.0` | <https://github.com/kornelski/rust-security-framework> |
@@ -211,7 +212,7 @@ those terms.
| signal-hook-registry | 1.4.8 | `Apache License 2.0` | <https://github.com/vorner/signal-hook> |
| simd_cesu8 | 1.1.1 | `Apache License 2.0` | <https://github.com/seancroach/simd_cesu8> |
| smallvec | 1.15.1 | `Apache License 2.0` | <https://github.com/servo/rust-smallvec> |
| socket2 | 0.6.3 | `Apache License 2.0` | <https://github.com/rust-lang/socket2> |
| socket2 | 0.6.4 | `Apache License 2.0` | <https://github.com/rust-lang/socket2> |
| stable_deref_trait | 1.2.1 | `Apache License 2.0` | <https://github.com/storyyeller/stable_deref_trait> |
| system-configuration-sys | 0.6.0 | `Apache License 2.0` | <https://github.com/mullvad/system-configuration-rs> |
| system-configuration | 0.7.0 | `Apache License 2.0` | <https://github.com/mullvad/system-configuration-rs> |
@@ -220,7 +221,7 @@ those terms.
| threadpool | 1.8.1 | `Apache License 2.0` | <https://github.com/rust-threadpool/rust-threadpool> |
| unicode-xid | 0.2.6 | `Apache License 2.0` | <https://github.com/unicode-rs/unicode-xid> |
| url | 2.5.8 | `Apache License 2.0` | <https://github.com/servo/rust-url> |
| uuid | 1.23.1 | `Apache License 2.0` | <https://github.com/uuid-rs/uuid> |
| uuid | 1.23.2 | `Apache License 2.0` | <https://github.com/uuid-rs/uuid> |
| version_check | 0.9.5 | `Apache License 2.0` | <https://github.com/SergioBenitez/version_check> |
| ff | 0.13.1 | `Apache License 2.0` | <https://github.com/zkcrypto/ff> |
| hashlink | 0.9.1 | `Apache License 2.0` | <https://github.com/kyren/hashlink> |
@@ -283,10 +284,10 @@ those terms.
| android_log-sys | 0.2.0 | `Apache License 2.0` | <https://github.com/nercury/android_log-sys-rs> |
| android_log-sys | 0.3.2 | `Apache License 2.0` | <https://github.com/rust-mobile/android_log-sys-rs> |
| android_logger | 0.15.1 | `Apache License 2.0` | <https://github.com/rust-mobile/android_logger-rs> |
| tsproto-types | 0.1.0 | `Apache License 2.0` | <https://github.com/ReSpeak/tsclientlib/tree/master/utils/tsproto-types> |
| ts-bookkeeping | 0.1.0 | `Apache License 2.0` | <https://github.com/ReSpeak/tsclientlib/tree/master/utils/ts-bookkeeping> |
| tsclientlib | 0.2.0 | `Apache License 2.0` | <https://github.com/ReSpeak/tsclientlib> |
| tsproto-packets | 0.1.0 | `Apache License 2.0` | <https://github.com/ReSpeak/tsclientlib/tree/master/utils/tsproto-packets> |
| tsproto-types | 0.1.0 | `Apache License 2.0` | <https://github.com/ReSpeak/tsclientlib/tree/master/utils/tsproto-types> |
| tsproto | 0.2.0 | `Apache License 2.0` | <https://github.com/ReSpeak/tsclientlib> |
| chanora_core | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> |
| chanora_audio | 0.2.0-beta.1 | `Apache License 2.0` | <https://github.com/anomalyco/opencode> |
@@ -344,7 +345,7 @@ those terms.
| serde_json | 1.0.150 | `Apache License 2.0` | <https://github.com/serde-rs/json> |
| serde_repr | 0.1.20 | `Apache License 2.0` | <https://github.com/dtolnay/serde-repr> |
| serde_urlencoded | 0.7.1 | `Apache License 2.0` | <https://github.com/nox/serde_urlencoded> |
| shlex | 1.3.0 | `Apache License 2.0` | <https://github.com/comex/rust-shlex> |
| shlex | 2.0.1 | `Apache License 2.0` | <https://github.com/comex/rust-shlex> |
| simdutf8 | 0.1.5 | `Apache License 2.0` | <https://github.com/rusticstuff/simdutf8> |
| syn | 2.0.117 | `Apache License 2.0` | <https://github.com/dtolnay/syn> |
| sync_wrapper | 1.0.2 | `Apache License 2.0` | <https://github.com/Actyx/sync_wrapper> |
@@ -385,11 +386,11 @@ those terms.
| uds_windows | 1.2.1 | `MIT License` | <https://github.com/haraldh/rust_uds_windows> |
| sdl2-sys | 0.37.0 | `MIT License` | <https://github.com/rust-sdl2/rust-sdl2> |
| openssl-sys | 0.9.116 | `MIT License` | <https://github.com/rust-openssl/rust-openssl> |
| mio | 1.2.0 | `MIT License` | <https://github.com/tokio-rs/mio> |
| mio | 1.2.1 | `MIT License` | <https://github.com/tokio-rs/mio> |
| nom | 7.1.3 | `MIT License` | <https://github.com/Geal/nom> |
| libsqlite3-sys | 0.30.1 | `MIT License` | <https://github.com/rusqlite/rusqlite> |
| rusqlite | 0.32.1 | `MIT License` | <https://github.com/rusqlite/rusqlite> |
| hyper | 1.9.0 | `MIT License` | <https://github.com/hyperium/hyper> |
| hyper | 1.10.1 | `MIT License` | <https://github.com/hyperium/hyper> |
| schannel | 0.1.29 | `MIT License` | <https://github.com/steffengy/schannel-rs> |
| memoffset | 0.9.1 | `MIT License` | <https://github.com/Gilnaa/memoffset> |
| version-compare | 0.1.1 | `MIT License` | <https://gitlab.com/timvisee/version-compare> |
@@ -414,11 +415,11 @@ those terms.
| http-body-util | 0.1.3 | `MIT License` | <https://github.com/hyperium/http-body> |
| delegate-attr | 0.3.0 | `MIT License` | <https://github.com/upsuper/delegate-attr> |
| hyper-util | 0.1.20 | `MIT License` | <https://github.com/hyperium/hyper-util> |
| zbus | 5.15.0 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| zbus_macros | 5.15.0 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| zbus | 5.16.0 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| zbus_macros | 5.16.0 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| zbus_names | 4.3.2 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| zvariant | 5.11.0 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| zvariant_derive | 5.11.0 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| zvariant | 5.12.0 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| zvariant_derive | 5.12.0 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| synstructure | 0.13.2 | `MIT License` | <https://github.com/mystor/synstructure> |
| fs_extra | 1.3.0 | `MIT License` | <https://github.com/webdesus/fs_extra> |
| alsa-sys | 0.4.0 | `MIT License` | <https://github.com/diwic/alsa-sys> |
@@ -438,14 +439,14 @@ those terms.
| tokio | 1.52.3 | `MIT License` | <https://github.com/tokio-rs/tokio> |
| endi | 1.1.1 | `MIT License` | <https://github.com/zeenix/endi> |
| zmij | 1.0.21 | `MIT License` | <https://github.com/dtolnay/zmij> |
| zvariant_utils | 3.3.1 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| zvariant_utils | 3.4.0 | `MIT License` | <https://github.com/z-galaxy/zbus/> |
| winnow | 1.0.3 | `MIT License` | <https://github.com/winnow-rs/winnow> |
| sdl2 | 0.37.0 | `MIT License` | <https://github.com/Rust-SDL2/rust-sdl2> |
| aho-corasick | 1.1.4 | `MIT License` | <https://github.com/BurntSushi/aho-corasick> |
| byteorder | 1.5.0 | `MIT License` | <https://github.com/BurntSushi/byteorder> |
| csv-core | 0.1.13 | `MIT License` | <https://github.com/BurntSushi/rust-csv> |
| csv | 1.4.0 | `MIT License` | <https://github.com/BurntSushi/rust-csv> |
| memchr | 2.8.0 | `MIT License` | <https://github.com/BurntSushi/memchr> |
| memchr | 2.8.1 | `MIT License` | <https://github.com/BurntSushi/memchr> |
| walkdir | 2.5.0 | `MIT License` | <https://github.com/BurntSushi/walkdir> |
| combine | 4.6.7 | `MIT License` | <https://github.com/Marwes/combine> |
| data-encoding | 2.11.0 | `MIT License` | <https://github.com/ia0/data-encoding> |