feat(flutter): surface bound PTT key label in capability badge (SDD-091 follow-up)

After a user saved a PTT binding through _PttBindingCaptureDialog,
the capability badge showed the resolved level + backend (e.g.
'PTT: L2WindowsRawInput (windows-raw-input)') but never told the
user which key they had actually bound. Reported on the Windows
verification round as 'do you think we should tell user what key
they have set and then they will know what to press'.

This commit caches the captured platform-neutral key label in
_BetaHomeState whenever _onConfigurePtt succeeds, and threads it
through _AudioControls to a new boundKeyLabel prop on
PttCapabilityBadge. When the prop is non-empty the badge renders
a second line below the existing row:

  PTT: L2WindowsRawInput (windows-raw-input)    [ⓘ] [Configure]
    Key: Space

The label uses bodySmall + monospace + onSurfaceVariant to stay
visually subordinate to the capability descriptor. Two new l10n
entries (en + zh) cover the 'Key: {key}' string.

Privacy: the displayed label is the same platform-neutral
LogicalKeyboardKey.keyLabel string the dialog already shows
during capture and that already crosses the bridge as
PttBinding.platform_key. No raw OS key code is introduced
(DEC-027 / SDD-077 compliance preserved).

State scope: display-only cache that resets on app restart. The
bridge-side PttController (SDD-088) holds the authoritative
binding; this UI cache is purely for display continuity within
a single process.

Verified on Linux: flutter analyze clean, cargo test --workspace
55/0/3.
This commit is contained in:
EdisonJwa
2026-05-15 20:35:42 +08:00
parent 9831624079
commit feceacfdad
6 changed files with 101 additions and 25 deletions
+6
View File
@@ -40,6 +40,12 @@
"backend": { "type": "String" }
}
},
"pttCapabilityBoundKey": "Key: {key}",
"@pttCapabilityBoundKey": {
"placeholders": {
"key": { "type": "String" }
}
},
"pttCapabilityExplainTitle": "Push-to-Talk capability",
"pttCapabilityExplainFocusedHeading": "Focused PTT",
"pttCapabilityExplainFocusedBody": "Chanora is currently using Focused Push-to-Talk: the binding only fires while the Chanora window is focused. This is the universal fallback used on every platform when a global capture path is not available.",
+1
View File
@@ -30,6 +30,7 @@
"pttTransmitting": "正在发送…",
"pttHoldToTalkSemanticsHint": "按住进行语音发送,松开停止。",
"pttCapabilityBadge": "对讲能力:{level}{backend}",
"pttCapabilityBoundKey": "按键:{key}",
"pttCapabilityExplainTitle": "对讲能力说明",
"pttCapabilityExplainFocusedHeading": "聚焦对讲",
"pttCapabilityExplainFocusedBody": "Chanora 当前使用聚焦对讲:按键只在 Chanora 窗口处于聚焦时生效。这是所有平台在无法启用全局采集时的通用回退方案。",
@@ -253,6 +253,12 @@ abstract class AppL10n {
/// **'PTT: {level} ({backend})'**
String pttCapabilityBadge(String level, String backend);
/// No description provided for @pttCapabilityBoundKey.
///
/// In en, this message translates to:
/// **'Key: {key}'**
String pttCapabilityBoundKey(String key);
/// No description provided for @pttCapabilityExplainTitle.
///
/// In en, this message translates to:
@@ -96,6 +96,11 @@ class AppL10nEn extends AppL10n {
return 'PTT: $level ($backend)';
}
@override
String pttCapabilityBoundKey(String key) {
return 'Key: $key';
}
@override
String get pttCapabilityExplainTitle => 'Push-to-Talk capability';
@@ -93,6 +93,11 @@ class AppL10nZh extends AppL10n {
return '对讲能力:$level$backend';
}
@override
String pttCapabilityBoundKey(String key) {
return '按键:$key';
}
@override
String get pttCapabilityExplainTitle => '对讲能力说明';