Files
chanora/apps/chanora_flutter/lib/l10n/app_zh.arb
T
EdisonJwa 7c62d14dd8 feat(ui,ios): inline mode+tail into voice sheet, fix Unknown audio route, tap-outside unfocus
Three user-reported issues addressed at once.

1. Audio output displaying as Unknown on iOS

The route tile only set _device from currentDeviceStream events,
which fire on route *changes*. On first sheet open with no route
change yet, _device was null \u2192 _deviceLabel fell through to
audioRouteUnknown.

Fix: query AudioRouterPlatform.instance.getCurrentDevice() in
initState before attaching the stream listener. Plugin returns the
current AVAudioSession route synchronously (well, via Future) so
the tile renders Speaker / iPhone receiver / AirPods / etc.
immediately on first open. Errors swallowed \u2014 the stream remains
authoritative for subsequent updates.

2. 'Adjust mode & release tail' too deep (chip \u2192 modal \u2192 button \u2192 dialog)

Inlined the mode radio buttons and release-tail slider directly
into the voice modal sheet. Dropped the OutlinedButton 'Adjust'
trigger and the nested VoiceSettingsDialog dispatch entirely on
mobile.

Modal sheet is now a single-screen control panel:

  Title 'Voice'
  --------
  Audio output: <current route>           >    (iOS/Android only)
  --------
  Transmit mode
    \u25c9 PTT
    \u25cb Continuous
    \u25cb Voice activity (Coming soon)             (disabled)
  --------
  Release tail                  200 ms
  [\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u25cf\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501]                       (0\u20131000 ms, step 50)
  Bound key: F                                  (desktop only)
  --------
  Level meter
  TX/RX frame counts
  PTT capability badge                          (desktop only)

VoiceSettingsDialog is retained for the wide-mode VoiceBar
'configure' button (desktop entrypoint) and the PTT-bind flow, so
desktop UX is unaffected.

New widgets: _VoiceSheetBody (StatefulWidget with local _mode +
_tail), _ModeRow (RadioListTile-shaped row with optional disabled
state for VoiceActivity). New API on showVoiceDetailsSheet:
onModeChanged + onReleaseTailChanged callbacks (replace
onAdjustVoiceSettings). Wiring in main.dart writes through to
rust.setTransmitMode / rust.setReleaseTailMs and mirrors _state.

l10n: dropped voiceAdjustSettings (en + zh). Added voiceBoundKeyLabel
(en + zh) for the desktop-only bound-key row.

3. iOS first-tap-keyboard regression (flutter/flutter#181474)

The 79f8360 _kickFocus workaround (unfocus + microtask refocus on
every TextField.onTap) was kept, but extended with a tap-outside-
to-unfocus GestureDetector wrapping the connect form Column. This
guarantees the FocusNode is in the unfocused state when the next
field tap arrives, so the focus transition is always false\u2192true
on first tap.

GestureDetector(HitTestBehavior.translucent, onTap: unfocus) is the
canonical pattern recommended in the flutter/flutter#181474 thread
+ several older iOS keyboard issues. Translucent behaviour means it
catches taps on the column padding / empty regions without
swallowing taps on the TextFields themselves (those have
onTap: _kickFocus already).

flutter analyze: 6 pre-existing Radio.groupValue deprecation infos
in voice_settings.dart (unchanged). flutter build ios --release
--no-codesign: 27.9 s, Runner.app 30.2 MB (unchanged).

Awaiting iPhone retest to confirm all three fixes.
2026-05-16 18:44:48 +08:00

113 lines
5.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"@@locale": "zh",
"@@x-source-of-truth": "DEC-015 (register v0.9.5). Simplified Chinese for the Beta key set.",
"appTitle": "Chanora",
"homeNotProductionReadyBanner": "Beta 版本——已接通语音收发;尚未达到生产环境质量。",
"fieldServerHost": "服务器地址",
"fieldNickname": "昵称",
"fieldServerPassword": "服务器密码",
"fieldServerPasswordHelp": "如果服务器无需密码,留空即可。",
"fieldPassword": "密码",
"fieldDisplayName": "显示名称",
"connectAction": "连接",
"disconnectAction": "断开连接",
"refreshAction": "刷新",
"diagnosticsAction": "诊断信息",
"aboutAction": "关于",
"aboutVersion": "版本 {version}",
"aboutNonAffiliation": "Chanora 是独立项目,与 TeamSpeak 之间不存在任何附属、认可、赞助或官方关联关系。",
"aboutLicenseHeading": "许可协议",
"aboutLicenseBody": "Chanora 采用 Apache License 2.0 或 MIT License 双协议授权,使用者可任选其一。完整协议文本以 LICENSE-APACHE 与 LICENSE-MIT 形式随仓库一同分发。",
"aboutThirdPartyHeading": "第三方组件",
"aboutThirdPartyBody": "Chanora 基于 tsclientlib、flutter_rust_bridge、cpal、rusqlite、Flutter 框架等开源组件构建。完整归属信息请参阅仓库根目录的 NOTICE 文件。",
"copyAction": "复制",
"closeAction": "关闭",
"startAudioAction": "启动语音",
"pttHoldToTalk": "按住说话",
"pttTransmitting": "正在发送…",
"pttHoldToTalkSemanticsHint": "按住进行语音发送,松开停止。",
"pttCapabilityBadge": "对讲能力:{level}{backend}",
"pttCapabilityBoundKey": "按键:{key}",
"pttCapabilityExplainTitle": "对讲能力说明",
"pttCapabilityExplainFocusedHeading": "聚焦对讲",
"pttCapabilityExplainFocusedBody": "Chanora 当前使用聚焦对讲:按键只在 Chanora 窗口处于聚焦时生效。这是所有平台在无法启用全局采集时的通用回退方案。",
"pttCapabilityExplainGoGlobalWindows": "在 Windows 上,绑定按键后会自动启用全局对讲,无需额外权限。",
"pttCapabilityExplainGoGlobalMacos": "在 macOS 上,启用全局对讲需要「输入监视」权限。请打开「系统设置 → 隐私与安全 → 输入监视」,授权 Chanora 后重新绑定按键。",
"pttCapabilityExplainGoGlobalLinux": "在 Linux 上,启用全局对讲需要带 GlobalShortcuts 门户的 GNOME-Wayland 桌面。请重新绑定按键,并在桌面弹出快捷键对话框时接受。",
"pttCapabilityExplainGoGlobalGeneric": "当前环境暂不支持全局对讲。聚焦对讲在 Chanora 窗口获得焦点时仍可正常使用。",
"pttConfigureAction": "配置",
"pttConfigureTitle": "配置对讲按键",
"pttConfigurePrompt": "按下您希望用于对讲的按键或鼠标侧键。",
"pttConfigureWaiting": "(等待输入…)",
"pttConfigureCaptured": "已捕获",
"pttConfigurePrivacyNote": "Chanora 不会记录具体的按键值。本对话框只会向应用提交输入类别(键盘 / 鼠标侧键)以及一个跨平台标签。",
"pttConfigureSaveAction": "保存",
"pttConfigurePortalRedirect": "您的桌面环境将打开自带的快捷键对话框,请在其中选择用于对讲的按键。",
"inputMuteAction": "静音麦克风",
"inputUnmuteAction": "取消麦克风静音",
"outputMuteAction": "静音扬声器",
"outputUnmuteAction": "取消扬声器静音",
"joinChannelAction": "加入频道",
"channelPasswordTitle": "频道密码",
"bookmarksHeading": "书签",
"bookmarksEmpty": "尚无书签。先在上方填写服务器,然后点击“保存书签”。",
"bookmarkAddAction": "保存书签",
"bookmarkAddTitle": "保存书签",
"bookmarkDeleteAction": "删除书签",
"statusIdle": "未连接",
"statusConnecting": "正在连接…",
"statusConnected": "已连接到 {server}",
"statusError": "错误:{message}",
"statusReconnecting": "正在重新连接……第 {attempt} 次尝试,{delay} 秒后",
"statusConnectionLost": "连接已断开:{reason}",
"audioStatsLine": "发送 {sent} 帧 • 接收 {received} 帧 • 麦克风 {ptt}",
"channelsHeading": "频道",
"clientsHeading": "在线用户",
"countChannelsAndClients": "{channels} 个频道 • {clients} 在线",
"voiceModePtt": "按键说话",
"voiceModeContinuous": "持续发送",
"voiceModeVoiceActivity": "语音激活",
"voiceModeComingSoon": "即将推出",
"voiceModeLabel": "发送模式",
"voiceReleaseTailLabel": "释放延迟",
"voiceReleaseTailHint": "毫秒",
"voiceLeaveAction": "离开语音",
"voiceHardMuteLabel": "麦克风静音",
"voiceOutputMuteLabel": "扬声器静音",
"voiceSettingsTitle": "语音设置",
"voiceBindKeyAction": "绑定 PTT 按键",
"voiceBoundKeyLabel": "已绑定按键",
"voicePttHoldHint": "按住按钮",
"voiceMicOn": "开启",
"voiceMicOff": "关闭",
"voiceSheetTitle": "语音",
"audioOutputLabel": "音频输出",
"audioRouteSpeaker": "扬声器",
"audioRouteReceiver": "听筒",
"audioRouteBluetooth": "蓝牙",
"audioRouteWiredHeadset": "有线耳机",
"audioRouteCarAudio": "车载音频",
"audioRouteAirplay": "AirPlay",
"audioRouteUnknown": "未知",
"channelJoinFailedPermission": "权限不足,无法加入此频道。",
"channelJoinFailedPassword": "频道密码错误。",
"channelJoinFailedFull": "频道已满。",
"channelJoinFailedFamilyFull": "频道家族人数已达上限。",
"channelJoinFailedPrivate": "此频道为私有频道。",
"channelJoinFailedTimeout": "无法加入频道:服务器响应超时。",
"channelJoinFailedGeneric": "无法加入频道:{message}",
"@channelJoinFailedGeneric": {
"placeholders": {
"message": { "type": "String" }
}
}
}