feat(ptt): code-side initial split — transmit_active / capability badge / sanitizer

Implements the gen2 v0.9.3 doc baseline's first slice of code work:

  * SRS-201: split the audio engine's `ptt` AtomicBool into the
    authoritative `transmit_active` flag. The legacy `set_ptt` /
    `ptt` accessors are retained as `#[doc(hidden)]` thin wrappers
    so the existing bridge command and the existing Flutter
    hold-to-talk UI keep compiling.
  * SAD-075 / SDD-089 acknowledged at the type level: only
    `AudioEngine::set_transmit_active` (or its legacy alias)
    mutates the flag; the encoder feed reads it once per outbound
    frame and never writes.
  * SDD-082: new `chanora_audio::ptt` module ships the
    `PttCapabilityLevel` enum (`L0Focused`, `L1GlobalShortcut`,
    `L2GlobalHoldToTalk`, `L3GlobalWithMouseButtons`,
    `L4DeviceAware` reserved) with a stable `as_str` mapping and
    an `is_global` classifier.
  * SDD-087: `PttBackendDescriptor::focused()` constant value for
    the universal Focused-PTT fallback. The struct shape carries
    only privacy-safe fields (`level`, `backend_id`,
    `bound_input_class`) — a key code cannot fit through this
    surface by construction (DEC-027).
  * SAD-077 / SDD-090: `RedactingLogLayer` now hosts the
    `PttBanCheckVisitor` and the `PTT_BANNED_FIELDS` constant
    (`key_code`, `scan_code`, `virtual_key`, `vk`, `keysym`,
    `keysym_string`, `key_sequence`, `key_press_history`,
    `key_timing`). Any record whose field set names a banned key
    is dropped before reaching the in-memory log sink or the
    user-initiated diagnostic export. The check is structural and
    runs ahead of formatting / redaction.
  * `SessionEvent::PttCapability` carries the diagnostics-safe
    descriptor through the broadcast event stream;
    `chanora_core::ChanoraSession::start_audio` publishes the
    Focused-PTT descriptor when the audio engine starts (SRS-196
    / SDD-091).
  * `BridgeEvent::PttCapability` mirrors the event across the
    FFI boundary. flutter_rust_bridge codegen regenerated.
  * Flutter `_AudioControls` renders a capability badge above the
    PTT button: a globe icon for Global levels, a focus-frame
    icon for `L0Focused`, plus a Tooltip exposing the bound input
    class. New ARB key `pttCapabilityBadge(level, backend)` in
    `app_en.arb` and `app_zh.arb`.

Per-platform global PTT backends (`WindowsRawInputBackend`,
`MacOSEventTapBackend`, `LinuxGnomeWaylandBackend`) and the
`MissedKeyUpWatchdog` task land in a separate follow-up commit;
this milestone ships only PTT-L0 universally so the application's
runtime capability reporting is honest from day one.

Tests
-----

* `chanora_audio` rises from 1 to 4 unit tests covering
  `PttCapabilityLevel::as_str`, `is_global`, and the
  `PttBackendDescriptor::focused()` shape contract.
* `chanora_diagnostics` rises from 9 to 11 unit tests covering
  the new `PttBanCheckVisitor` over every banned field name and
  the `PTT_BANNED_FIELDS` stability assertion.
* Workspace total: 53 unit + integration tests, all green with
  `CHANORA_DISABLE_KEYRING=1` (was 49 at v1.0.0-rc.2).
* `flutter analyze`: clean.
* `cargo deny check`: advisories ok, bans ok, licenses ok,
  sources ok.
* `cargo about generate`: zero warnings (license inventory
  regenerated).
* `tools/dump_flutter_licenses.sh`: 94 packages, zero without
  LICENSE.
* Linux x86_64 release bundle builds clean.

No Android live verification in this commit per the user's note
that the test device was removed. Android arm64-v8a continues to
build via the same `cargo ndk` path; runtime reporting on Android
is `L0Focused` for the foreseeable future.
This commit is contained in:
EdisonJwa
2026-05-15 15:02:03 +08:00
parent 02ffadfa52
commit 7b21916049
16 changed files with 642 additions and 31 deletions
+7
View File
@@ -32,6 +32,13 @@
"startAudioAction": "Start audio",
"pttHoldToTalk": "Hold to talk",
"pttTransmitting": "Transmitting…",
"pttCapabilityBadge": "PTT: {level} ({backend})",
"@pttCapabilityBadge": {
"placeholders": {
"level": { "type": "String" },
"backend": { "type": "String" }
}
},
"inputMuteAction": "Mute mic",
"inputUnmuteAction": "Unmute mic",
"outputMuteAction": "Mute speaker",
+1
View File
@@ -28,6 +28,7 @@
"startAudioAction": "启动语音",
"pttHoldToTalk": "按住说话",
"pttTransmitting": "正在发送…",
"pttCapabilityBadge": "对讲能力:{level}{backend}",
"inputMuteAction": "静音麦克风",
"inputUnmuteAction": "取消麦克风静音",
"outputMuteAction": "静音扬声器",
@@ -241,6 +241,12 @@ abstract class AppL10n {
/// **'Transmitting…'**
String get pttTransmitting;
/// No description provided for @pttCapabilityBadge.
///
/// In en, this message translates to:
/// **'PTT: {level} ({backend})'**
String pttCapabilityBadge(String level, String backend);
/// No description provided for @inputMuteAction.
///
/// In en, this message translates to:
@@ -87,6 +87,11 @@ class AppL10nEn extends AppL10n {
@override
String get pttTransmitting => 'Transmitting…';
@override
String pttCapabilityBadge(String level, String backend) {
return 'PTT: $level ($backend)';
}
@override
String get inputMuteAction => 'Mute mic';
@@ -85,6 +85,11 @@ class AppL10nZh extends AppL10n {
@override
String get pttTransmitting => '正在发送…';
@override
String pttCapabilityBadge(String level, String backend) {
return '对讲能力:$level$backend';
}
@override
String get inputMuteAction => '静音麦克风';
+62
View File
@@ -107,6 +107,14 @@ class _BetaHomeState extends State<_BetaHome> {
bool _outputMuted = false;
double _outputGain = 1.0;
// Desktop PTT capability badge state (gen2 v0.9.3 / SDD-091).
// Populated by `BridgeEvent.PttCapability`. Defaults match the
// universal `FocusedPttBackend::focused()` descriptor so the UI
// shows an honest baseline even before the first event arrives.
String _pttLevel = 'L0Focused';
String _pttBackendId = 'focused';
String _pttBoundInputClass = 'keyboard';
List<rust.BridgeBookmark> _bookmarks = const [];
@override
@@ -160,6 +168,16 @@ class _BetaHomeState extends State<_BetaHome> {
setState(() => _audioStarted = false);
case rust.BridgeEvent_SnapshotChanged():
unawaited(_onRefresh());
case rust.BridgeEvent_PttCapability(
:final level,
:final backendId,
:final boundInputClass,
):
setState(() {
_pttLevel = level;
_pttBackendId = backendId;
_pttBoundInputClass = boundInputClass;
});
}
}
@@ -644,6 +662,9 @@ class _BetaHomeState extends State<_BetaHome> {
inputMuted: _inputMuted,
outputMuted: _outputMuted,
outputGain: _outputGain,
pttLevel: _pttLevel,
pttBackendId: _pttBackendId,
pttBoundInputClass: _pttBoundInputClass,
onPttDown: () => _setPtt(true),
onPttUp: () => _setPtt(false),
onToggleInputMute: _toggleInputMute,
@@ -798,6 +819,9 @@ class _AudioControls extends StatefulWidget {
required this.inputMuted,
required this.outputMuted,
required this.outputGain,
required this.pttLevel,
required this.pttBackendId,
required this.pttBoundInputClass,
required this.onPttDown,
required this.onPttUp,
required this.onToggleInputMute,
@@ -809,6 +833,9 @@ class _AudioControls extends StatefulWidget {
final bool inputMuted;
final bool outputMuted;
final double outputGain;
final String pttLevel;
final String pttBackendId;
final String pttBoundInputClass;
final VoidCallback onPttDown;
final VoidCallback onPttUp;
final VoidCallback onToggleInputMute;
@@ -835,9 +862,44 @@ class _AudioControlsState extends State<_AudioControls> {
stats.pttActive ? 'on' : 'off',
);
final isGlobal = widget.pttLevel != 'L0Focused';
final badgeLabel = l10n.pttCapabilityBadge(
widget.pttLevel,
widget.pttBackendId,
);
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Capability badge (gen2 v0.9.3 / SDD-091). Renders the
// active PTT level + backend so the user understands when
// Global PTT has fallen back to Focused PTT.
Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Tooltip(
message: widget.pttBoundInputClass.isEmpty
? badgeLabel
: '$badgeLabel\n(${widget.pttBoundInputClass})',
child: Row(
children: [
Icon(
isGlobal ? Icons.public : Icons.crop_free,
size: 14,
color: theme.colorScheme.onSurfaceVariant,
),
const SizedBox(width: 4),
Expanded(
child: Text(
badgeLabel,
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
),
],
),
),
),
Listener(
onPointerDown: (_) {
setState(() => _pressed = true);
@@ -323,6 +323,25 @@ sealed class BridgeEvent with _$BridgeEvent {
/// Latest client count.
required int clients,
}) = BridgeEvent_SnapshotChanged;
/// Detected desktop Push-to-Talk capability (gen2 v0.9.3,
/// DEC-023..028). The fields carry only privacy-safe values per
/// DEC-027: the capability level, a stable backend identifier,
/// and the bound input class. No key codes, scan codes, or
/// virtual-key values cross this boundary.
const factory BridgeEvent.pttCapability({
/// Stable capability identifier (`"L0Focused"`,
/// `"L1GlobalShortcut"`, `"L2GlobalHoldToTalk"`,
/// `"L3GlobalWithMouseButtons"`, or `"L4DeviceAware"`).
required String level,
/// Stable backend identifier (e.g. `"focused"`).
required String backendId,
/// Coarse bound input class (e.g. `"keyboard"`,
/// `"mouse-side-button"`); empty when no binding is active.
required String boundInputClass,
}) = BridgeEvent_PttCapability;
}
/// Coarse OS-reported network state. Mirrors
@@ -55,7 +55,7 @@ extension BridgeEventPatterns on BridgeEvent {
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( BridgeEvent_Connected value)? connected,TResult Function( BridgeEvent_Lost value)? lost,TResult Function( BridgeEvent_Reconnecting value)? reconnecting,TResult Function( BridgeEvent_Disconnected value)? disconnected,TResult Function( BridgeEvent_AudioStarted value)? audioStarted,TResult Function( BridgeEvent_AudioStopped value)? audioStopped,TResult Function( BridgeEvent_SnapshotChanged value)? snapshotChanged,required TResult orElse(),}){
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( BridgeEvent_Connected value)? connected,TResult Function( BridgeEvent_Lost value)? lost,TResult Function( BridgeEvent_Reconnecting value)? reconnecting,TResult Function( BridgeEvent_Disconnected value)? disconnected,TResult Function( BridgeEvent_AudioStarted value)? audioStarted,TResult Function( BridgeEvent_AudioStopped value)? audioStopped,TResult Function( BridgeEvent_SnapshotChanged value)? snapshotChanged,TResult Function( BridgeEvent_PttCapability value)? pttCapability,required TResult orElse(),}){
final _that = this;
switch (_that) {
case BridgeEvent_Connected() when connected != null:
@@ -65,7 +65,8 @@ return reconnecting(_that);case BridgeEvent_Disconnected() when disconnected !=
return disconnected(_that);case BridgeEvent_AudioStarted() when audioStarted != null:
return audioStarted(_that);case BridgeEvent_AudioStopped() when audioStopped != null:
return audioStopped(_that);case BridgeEvent_SnapshotChanged() when snapshotChanged != null:
return snapshotChanged(_that);case _:
return snapshotChanged(_that);case BridgeEvent_PttCapability() when pttCapability != null:
return pttCapability(_that);case _:
return orElse();
}
@@ -83,7 +84,7 @@ return snapshotChanged(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( BridgeEvent_Connected value) connected,required TResult Function( BridgeEvent_Lost value) lost,required TResult Function( BridgeEvent_Reconnecting value) reconnecting,required TResult Function( BridgeEvent_Disconnected value) disconnected,required TResult Function( BridgeEvent_AudioStarted value) audioStarted,required TResult Function( BridgeEvent_AudioStopped value) audioStopped,required TResult Function( BridgeEvent_SnapshotChanged value) snapshotChanged,}){
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( BridgeEvent_Connected value) connected,required TResult Function( BridgeEvent_Lost value) lost,required TResult Function( BridgeEvent_Reconnecting value) reconnecting,required TResult Function( BridgeEvent_Disconnected value) disconnected,required TResult Function( BridgeEvent_AudioStarted value) audioStarted,required TResult Function( BridgeEvent_AudioStopped value) audioStopped,required TResult Function( BridgeEvent_SnapshotChanged value) snapshotChanged,required TResult Function( BridgeEvent_PttCapability value) pttCapability,}){
final _that = this;
switch (_that) {
case BridgeEvent_Connected():
@@ -93,7 +94,8 @@ return reconnecting(_that);case BridgeEvent_Disconnected():
return disconnected(_that);case BridgeEvent_AudioStarted():
return audioStarted(_that);case BridgeEvent_AudioStopped():
return audioStopped(_that);case BridgeEvent_SnapshotChanged():
return snapshotChanged(_that);}
return snapshotChanged(_that);case BridgeEvent_PttCapability():
return pttCapability(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
@@ -107,7 +109,7 @@ return snapshotChanged(_that);}
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( BridgeEvent_Connected value)? connected,TResult? Function( BridgeEvent_Lost value)? lost,TResult? Function( BridgeEvent_Reconnecting value)? reconnecting,TResult? Function( BridgeEvent_Disconnected value)? disconnected,TResult? Function( BridgeEvent_AudioStarted value)? audioStarted,TResult? Function( BridgeEvent_AudioStopped value)? audioStopped,TResult? Function( BridgeEvent_SnapshotChanged value)? snapshotChanged,}){
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( BridgeEvent_Connected value)? connected,TResult? Function( BridgeEvent_Lost value)? lost,TResult? Function( BridgeEvent_Reconnecting value)? reconnecting,TResult? Function( BridgeEvent_Disconnected value)? disconnected,TResult? Function( BridgeEvent_AudioStarted value)? audioStarted,TResult? Function( BridgeEvent_AudioStopped value)? audioStopped,TResult? Function( BridgeEvent_SnapshotChanged value)? snapshotChanged,TResult? Function( BridgeEvent_PttCapability value)? pttCapability,}){
final _that = this;
switch (_that) {
case BridgeEvent_Connected() when connected != null:
@@ -117,7 +119,8 @@ return reconnecting(_that);case BridgeEvent_Disconnected() when disconnected !=
return disconnected(_that);case BridgeEvent_AudioStarted() when audioStarted != null:
return audioStarted(_that);case BridgeEvent_AudioStopped() when audioStopped != null:
return audioStopped(_that);case BridgeEvent_SnapshotChanged() when snapshotChanged != null:
return snapshotChanged(_that);case _:
return snapshotChanged(_that);case BridgeEvent_PttCapability() when pttCapability != null:
return pttCapability(_that);case _:
return null;
}
@@ -134,7 +137,7 @@ return snapshotChanged(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function( String serverName)? connected,TResult Function( String reason)? lost,TResult Function( int attempt, int delaySecs)? reconnecting,TResult Function( String reason)? disconnected,TResult Function()? audioStarted,TResult Function()? audioStopped,TResult Function( int channels, int clients)? snapshotChanged,required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function( String serverName)? connected,TResult Function( String reason)? lost,TResult Function( int attempt, int delaySecs)? reconnecting,TResult Function( String reason)? disconnected,TResult Function()? audioStarted,TResult Function()? audioStopped,TResult Function( int channels, int clients)? snapshotChanged,TResult Function( String level, String backendId, String boundInputClass)? pttCapability,required TResult orElse(),}) {final _that = this;
switch (_that) {
case BridgeEvent_Connected() when connected != null:
return connected(_that.serverName);case BridgeEvent_Lost() when lost != null:
@@ -143,7 +146,8 @@ return reconnecting(_that.attempt,_that.delaySecs);case BridgeEvent_Disconnected
return disconnected(_that.reason);case BridgeEvent_AudioStarted() when audioStarted != null:
return audioStarted();case BridgeEvent_AudioStopped() when audioStopped != null:
return audioStopped();case BridgeEvent_SnapshotChanged() when snapshotChanged != null:
return snapshotChanged(_that.channels,_that.clients);case _:
return snapshotChanged(_that.channels,_that.clients);case BridgeEvent_PttCapability() when pttCapability != null:
return pttCapability(_that.level,_that.backendId,_that.boundInputClass);case _:
return orElse();
}
@@ -161,7 +165,7 @@ return snapshotChanged(_that.channels,_that.clients);case _:
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function( String serverName) connected,required TResult Function( String reason) lost,required TResult Function( int attempt, int delaySecs) reconnecting,required TResult Function( String reason) disconnected,required TResult Function() audioStarted,required TResult Function() audioStopped,required TResult Function( int channels, int clients) snapshotChanged,}) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function( String serverName) connected,required TResult Function( String reason) lost,required TResult Function( int attempt, int delaySecs) reconnecting,required TResult Function( String reason) disconnected,required TResult Function() audioStarted,required TResult Function() audioStopped,required TResult Function( int channels, int clients) snapshotChanged,required TResult Function( String level, String backendId, String boundInputClass) pttCapability,}) {final _that = this;
switch (_that) {
case BridgeEvent_Connected():
return connected(_that.serverName);case BridgeEvent_Lost():
@@ -170,7 +174,8 @@ return reconnecting(_that.attempt,_that.delaySecs);case BridgeEvent_Disconnected
return disconnected(_that.reason);case BridgeEvent_AudioStarted():
return audioStarted();case BridgeEvent_AudioStopped():
return audioStopped();case BridgeEvent_SnapshotChanged():
return snapshotChanged(_that.channels,_that.clients);}
return snapshotChanged(_that.channels,_that.clients);case BridgeEvent_PttCapability():
return pttCapability(_that.level,_that.backendId,_that.boundInputClass);}
}
/// A variant of `when` that fallback to returning `null`
///
@@ -184,7 +189,7 @@ return snapshotChanged(_that.channels,_that.clients);}
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function( String serverName)? connected,TResult? Function( String reason)? lost,TResult? Function( int attempt, int delaySecs)? reconnecting,TResult? Function( String reason)? disconnected,TResult? Function()? audioStarted,TResult? Function()? audioStopped,TResult? Function( int channels, int clients)? snapshotChanged,}) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function( String serverName)? connected,TResult? Function( String reason)? lost,TResult? Function( int attempt, int delaySecs)? reconnecting,TResult? Function( String reason)? disconnected,TResult? Function()? audioStarted,TResult? Function()? audioStopped,TResult? Function( int channels, int clients)? snapshotChanged,TResult? Function( String level, String backendId, String boundInputClass)? pttCapability,}) {final _that = this;
switch (_that) {
case BridgeEvent_Connected() when connected != null:
return connected(_that.serverName);case BridgeEvent_Lost() when lost != null:
@@ -193,7 +198,8 @@ return reconnecting(_that.attempt,_that.delaySecs);case BridgeEvent_Disconnected
return disconnected(_that.reason);case BridgeEvent_AudioStarted() when audioStarted != null:
return audioStarted();case BridgeEvent_AudioStopped() when audioStopped != null:
return audioStopped();case BridgeEvent_SnapshotChanged() when snapshotChanged != null:
return snapshotChanged(_that.channels,_that.clients);case _:
return snapshotChanged(_that.channels,_that.clients);case BridgeEvent_PttCapability() when pttCapability != null:
return pttCapability(_that.level,_that.backendId,_that.boundInputClass);case _:
return null;
}
@@ -604,6 +610,82 @@ as int,
}
}
/// @nodoc
class BridgeEvent_PttCapability extends BridgeEvent {
const BridgeEvent_PttCapability({required this.level, required this.backendId, required this.boundInputClass}): super._();
/// Stable capability identifier (`"L0Focused"`,
/// `"L1GlobalShortcut"`, `"L2GlobalHoldToTalk"`,
/// `"L3GlobalWithMouseButtons"`, or `"L4DeviceAware"`).
final String level;
/// Stable backend identifier (e.g. `"focused"`).
final String backendId;
/// Coarse bound input class (e.g. `"keyboard"`,
/// `"mouse-side-button"`); empty when no binding is active.
final String boundInputClass;
/// Create a copy of BridgeEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$BridgeEvent_PttCapabilityCopyWith<BridgeEvent_PttCapability> get copyWith => _$BridgeEvent_PttCapabilityCopyWithImpl<BridgeEvent_PttCapability>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is BridgeEvent_PttCapability&&(identical(other.level, level) || other.level == level)&&(identical(other.backendId, backendId) || other.backendId == backendId)&&(identical(other.boundInputClass, boundInputClass) || other.boundInputClass == boundInputClass));
}
@override
int get hashCode => Object.hash(runtimeType,level,backendId,boundInputClass);
@override
String toString() {
return 'BridgeEvent.pttCapability(level: $level, backendId: $backendId, boundInputClass: $boundInputClass)';
}
}
/// @nodoc
abstract mixin class $BridgeEvent_PttCapabilityCopyWith<$Res> implements $BridgeEventCopyWith<$Res> {
factory $BridgeEvent_PttCapabilityCopyWith(BridgeEvent_PttCapability value, $Res Function(BridgeEvent_PttCapability) _then) = _$BridgeEvent_PttCapabilityCopyWithImpl;
@useResult
$Res call({
String level, String backendId, String boundInputClass
});
}
/// @nodoc
class _$BridgeEvent_PttCapabilityCopyWithImpl<$Res>
implements $BridgeEvent_PttCapabilityCopyWith<$Res> {
_$BridgeEvent_PttCapabilityCopyWithImpl(this._self, this._then);
final BridgeEvent_PttCapability _self;
final $Res Function(BridgeEvent_PttCapability) _then;
/// Create a copy of BridgeEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? level = null,Object? backendId = null,Object? boundInputClass = null,}) {
return _then(BridgeEvent_PttCapability(
level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable
as String,backendId: null == backendId ? _self.backendId : backendId // ignore: cast_nullable_to_non_nullable
as String,boundInputClass: null == boundInputClass ? _self.boundInputClass : boundInputClass // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
// dart format on
@@ -830,6 +830,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
channels: dco_decode_u_32(raw[1]),
clients: dco_decode_u_32(raw[2]),
);
case 7:
return BridgeEvent_PttCapability(
level: dco_decode_String(raw[1]),
backendId: dco_decode_String(raw[2]),
boundInputClass: dco_decode_String(raw[3]),
);
default:
throw Exception("unreachable");
}
@@ -1074,6 +1080,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
channels: var_channels,
clients: var_clients,
);
case 7:
var var_level = sse_decode_String(deserializer);
var var_backendId = sse_decode_String(deserializer);
var var_boundInputClass = sse_decode_String(deserializer);
return BridgeEvent_PttCapability(
level: var_level,
backendId: var_backendId,
boundInputClass: var_boundInputClass,
);
default:
throw UnimplementedError('');
}
@@ -1340,6 +1355,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_i_32(6, serializer);
sse_encode_u_32(channels, serializer);
sse_encode_u_32(clients, serializer);
case BridgeEvent_PttCapability(
level: final level,
backendId: final backendId,
boundInputClass: final boundInputClass,
):
sse_encode_i_32(7, serializer);
sse_encode_String(level, serializer);
sse_encode_String(backendId, serializer);
sse_encode_String(boundInputClass, serializer);
}
}