diff --git a/lib/src/widgets/recording_button.dart b/lib/src/widgets/recording_button.dart index b61c25b..4e6b3ba 100644 --- a/lib/src/widgets/recording_button.dart +++ b/lib/src/widgets/recording_button.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import '../interfaces/speech_recognition_service.dart'; import '../yx_asr_service.dart'; import '../models/speech_recognition_result.dart'; @@ -69,6 +70,7 @@ class _RecordingButtonState extends State late SpeechRecognitionService _speechService; bool _isListening = false; bool _isInitialized = false; + bool _isProcessing = false; // 防抖标志 late AnimationController _animationController; late Animation _scaleAnimation; @@ -146,9 +148,23 @@ class _RecordingButtonState extends State } Future _toggleRecording() async { - if (!_isInitialized || !widget.enabled) return; + // 防抖检查:如果正在处理中或未初始化或被禁用,则直接返回 + if (_isProcessing || !_isInitialized || !widget.enabled) return; + + // 设置处理中标志,防止重复点击 + setState(() { + _isProcessing = true; + }); try { + // 触觉反馈 + await HapticFeedback.lightImpact(); + + // 播放点击动画 + _animationController.forward().then((_) { + _animationController.reverse(); + }); + if (_isListening) { await _speechService.stopListening(); } else { @@ -160,6 +176,15 @@ class _RecordingButtonState extends State errorMsg: '切换录音状态失败: $e', errorCode: null, )); + } finally { + // 延迟重置处理标志,确保有足够的防抖时间 + Future.delayed(const Duration(milliseconds: 300), () { + if (mounted) { + setState(() { + _isProcessing = false; + }); + } + }); } } @@ -170,6 +195,8 @@ class _RecordingButtonState extends State Color buttonColor; if (!widget.enabled || !_isInitialized) { buttonColor = widget.disabledColor ?? Colors.grey; + } else if (_isProcessing) { + buttonColor = (widget.idleColor ?? theme.primaryColor).withValues(alpha: 0.7); } else if (_isListening) { buttonColor = widget.recordingColor ?? Colors.red; } else { @@ -200,11 +227,20 @@ class _RecordingButtonState extends State child: InkWell( borderRadius: BorderRadius.circular(widget.size / 2), onTap: _toggleRecording, - child: Icon( - _isListening ? Icons.stop : Icons.mic, - size: widget.size * 0.4, - color: Colors.white, - ), + child: _isProcessing + ? SizedBox( + width: widget.size * 0.4, + height: widget.size * 0.4, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ) + : Icon( + _isListening ? Icons.stop : Icons.mic, + size: widget.size * 0.4, + color: Colors.white, + ), ), ), ),