diff --git a/lib/modules/agent/controllers/agent_controller.dart b/lib/modules/agent/controllers/agent_controller.dart index 03bce6c62..b71f502d1 100644 --- a/lib/modules/agent/controllers/agent_controller.dart +++ b/lib/modules/agent/controllers/agent_controller.dart @@ -81,6 +81,12 @@ class AgentController extends GetxController { // 打电话模式状态 final isPhoneCallMode = false.obs; // 是否处于打电话模式 + // 按住说话状态 + final isPushToTalkActive = false.obs; // 是否正在按住说话 + + // 按住说话模式状态 - 用于区分是否处于按住说话模式(即使当前没有按住) + final isPushToTalkMode = false.obs; // 是否处于按住说话模式 + // 键盘状态 final isKeyboardVisible = false.obs; // 键盘是否可见 @@ -340,7 +346,11 @@ class AgentController extends GetxController { break; case AgentServiceEventType.recognitionStopped: isListening.value = false; - isTextInputMode.value = true; + // 只有在非按住说话模式且非打电话模式下才自动切换到文字模式 + // 按住说话模式下应该保持在语音模式,等待下次按住 + if (!isPushToTalkMode.value && !isPhoneCallMode.value) { + isTextInputMode.value = true; + } // isTextInputMode.refresh(); Logger.i(TAG, '识别停止'); break; @@ -765,7 +775,7 @@ class AgentController extends GetxController { } } - // 切换输入模式 + // 切换输入模式(改造为按住说话模式) void toggleInputMode() async { // 如果当前在图片输入模式,先清除 if (isImageInputActive.value) { @@ -780,7 +790,7 @@ class AgentController extends GetxController { // context: Get.context!, permissionType: Permission.microphone, permissionName: '麦克风', - explanationText: '语音识别与翻译功能需要访问麦克风。', + explanationText: '语音识别功能需要访问麦克风。', permanentDenialText: '您已永久拒绝麦克风权限,请前往系统设置开启权限。', settingsButtonText: '去设置', cancelButtonText: '取消', @@ -792,13 +802,15 @@ class AgentController extends GetxController { isTextInputMode.toggle(); - // 切换到语音模式时,直接开始语音输入 - if (!isTextInputMode.value) { - startVoiceInput(); - } - // 切换到文本模式时,直接停止语音输入 - else { + // 切换到语音模式时,启用按住说话模式 + // 切换到文本模式时,禁用按住说话模式并停止任何正在进行的语音输入 + if (isTextInputMode.value) { + // 切换到文本模式 + isPushToTalkMode.value = false; stopVoiceInput(); + } else { + // 切换到语音模式,启用按住说话模式 + isPushToTalkMode.value = true; } } @@ -1057,6 +1069,8 @@ class AgentController extends GetxController { // 切换到语音模式并开始语音输入 isTextInputMode.value = false; + // 打电话模式不使用按住说话模式,而是持续语音输入 + isPushToTalkMode.value = false; await startVoiceInput(); } } @@ -1071,8 +1085,40 @@ class AgentController extends GetxController { // 停止语音输入 await stopVoiceInput(); - // 切换回文本模式 + // 切换回文本模式,并禁用按住说话模式 isTextInputMode.value = true; + isPushToTalkMode.value = false; + } + + // 开始按住说话 + void startPushToTalk() async { + Logger.i(TAG, '🎤 开始按住说话'); + + // 只有在语音模式且按住说话模式下才能按住说话 + if (isTextInputMode.value || !isPushToTalkMode.value) return; + + // 如果已经在按住说话,不重复开始 + if (isPushToTalkActive.value) return; + + // 设置按住说话状态 + isPushToTalkActive.value = true; + + // 开始语音识别 + await startVoiceInput(); + } + + // 结束按住说话 + void endPushToTalk() async { + Logger.i(TAG, '🎤 结束按住说话'); + + // 如果不在按住说话状态,直接返回 + if (!isPushToTalkActive.value) return; + + // 清除按住说话状态(但保持按住说话模式) + isPushToTalkActive.value = false; + + // 停止语音识别 + await stopVoiceInput(); } // 获取音乐播放状态 diff --git a/lib/modules/agent/views/agent_view.dart b/lib/modules/agent/views/agent_view.dart index 9e24b7ef6..cca44635e 100644 --- a/lib/modules/agent/views/agent_view.dart +++ b/lib/modules/agent/views/agent_view.dart @@ -457,75 +457,84 @@ class _AgentViewState extends State with WidgetsBindingObserver { ), ); } else { - // 语音输入模式 - 始终显示波形图 + // 语音输入模式 - 按住说话模式 return GestureDetector( - onTap: () { - if (controller.isListening.value) { - controller.stopVoiceInput(); - } else { - controller.startVoiceInput(); - } + onLongPressStart: (_) { + // 开始按住说话 + controller.startPushToTalk(); }, - child: Container( - height: 50, - padding: const EdgeInsets.symmetric( - horizontal: 16), - decoration: BoxDecoration( - color: isDarkMode - ? Colors.grey[800] - : Colors.grey[200], - borderRadius: BorderRadius.circular(22), - border: Border.all( - color: isDarkMode - ? Colors.grey[800]! - : Colors.grey.withOpacity(0.1), - width: 1.0, + onLongPressEnd: (_) { + // 结束按住说话 + controller.endPushToTalk(); + }, + onLongPressCancel: () { + // 取消按住说话 + controller.endPushToTalk(); + }, + child: Obx(() { + final isPushToTalkActive = controller.isPushToTalkActive.value; + final isListening = controller.isListening.value; + + return Container( + height: 50, + padding: const EdgeInsets.symmetric( + horizontal: 16), + decoration: BoxDecoration( + color: isPushToTalkActive + ? (isDarkMode ? Colors.blue[900] : Colors.blue[100]) + : (isDarkMode ? Colors.grey[800] : Colors.grey[200]), + borderRadius: BorderRadius.circular(22), + border: Border.all( + color: isPushToTalkActive + ? Colors.blue + : (isDarkMode + ? Colors.grey[800]! + : Colors.grey.withOpacity(0.1)), + width: isPushToTalkActive ? 2.0 : 1.0, + ), ), - ), - child: Row( - children: [ - // 语音波形图 - 始终显示 - Expanded( - child: Row( - mainAxisAlignment: - MainAxisAlignment.start, - children: [ - const AgentSoundBarsWidget(), - const Spacer(), - // "正在聆听"文字 - Obx(() { - final isListening = controller - .isListening.value; - return Row( - children: [ - Icon( - Icons.mic, - size: 14, - color: isListening - ? primaryColor - : Colors.grey[500], - ), - const SizedBox(width: 4), - Text( - '正在聆听', - style: TextStyle( - fontSize: 13, - fontWeight: - FontWeight.w500, - color: isListening - ? primaryColor - : Colors.grey[500], - ), - ), - ], - ); - }), - ], + child: Row( + children: [ + // 语音波形图 - 只在按住时显示 + if (isPushToTalkActive) ...[ + const AgentSoundBarsWidget(), + const Spacer(), + ], + + // 状态文字和图标 + Expanded( + child: Row( + mainAxisAlignment: isPushToTalkActive + ? MainAxisAlignment.end + : MainAxisAlignment.center, + children: [ + Icon( + isPushToTalkActive ? Icons.mic : Icons.mic_none, + size: 16, + color: isPushToTalkActive + ? Colors.blue + : Colors.grey[500], + ), + const SizedBox(width: 6), + Text( + isPushToTalkActive + ? '正在录音...' + : '按住说话', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: isPushToTalkActive + ? Colors.blue + : Colors.grey[600], + ), + ), + ], + ), ), - ), - ], - ), - ), + ], + ), + ); + }), ); } }),