fix(audio,storage,ui): allow PTT binding before audio is running
Save-binding before joining a voice channel used to return BridgeError.invalidCommand(audio not started) because the PttController only exists after start_audio runs and set_ptt_binding required a live controller. Users naturally want to bind their PTT key once on first launch, not every time they join a channel — fix: * chanora_storage::IdentityFileStore::set_ptt_binding / get_ptt_binding persist the privacy-safe binding triple (input_class, platform_key, key_label) into audio_meta.json next to transmit_mode and release_tail_ms. * ChanoraSession holds pending_binding: Arc<Mutex<Option<PttBinding>>>. set_ptt_binding now (1) persists to storage best-effort, (2) stashes into pending_binding, (3) forwards live to the controller only if one exists. No more AudioNotStarted. * init_storage loads the persisted binding into pending_binding so it survives app restarts. * start_audio applies pending_binding immediately after constructing the PttController so the first key-press after join already works. * supervisor_loop carries pending_binding and re-applies it after any reconnect-driven audio engine restart, so reconnects don't silently drop the hotkey. * New bridge call get_ptt_binding() -> (input_class, key_label) plus a matching Flutter _hydratePttBinding() in initState lets the Voice Bar show the user's saved hotkey label on launch (e.g. 'PTT: Space') before any voice channel is joined. cargo test --workspace --lib: 72 passed / 0 failed / 1 ignored. flutter analyze: clean (6 pre-existing Radio.groupValue infos). FRB bindings regenerated.
This commit is contained in:
@@ -105,6 +105,14 @@ Future<void> setPttBinding({
|
||||
Future<(String, String, String)> pttDescriptor() =>
|
||||
RustLib.instance.api.crateApiPttDescriptor();
|
||||
|
||||
/// Return the persisted PTT binding as a
|
||||
/// `(input_class, platform_key)` pair so the UI can hydrate its
|
||||
/// display state at launch (e.g. show "PTT: Space" next to the
|
||||
/// badge before the user re-opens the binding dialog). Empty
|
||||
/// strings mean no binding has been persisted yet.
|
||||
Future<(String, String)> getPttBinding() =>
|
||||
RustLib.instance.api.crateApiGetPttBinding();
|
||||
|
||||
/// Move our own client to `channel_id`. Optional channel password
|
||||
/// for password-protected channels — pass an empty string when not
|
||||
/// required.
|
||||
|
||||
Reference in New Issue
Block a user