Files
ai_chat_assistant/lib/widgets/chat_footer.dart

154 lines
5.4 KiB
Dart

import 'package:t_basic_intl/intl.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../services/message_service.dart';
import '../utils/common_util.dart';
import 'large_audio_wave.dart';
import '../utils/assets_util.dart';
class ChatFooter extends StatefulWidget {
final VoidCallback? onClear;
const ChatFooter({super.key, this.onClear});
@override
State<ChatFooter> createState() => _ChatFooterState();
}
class _ChatFooterState extends State<ChatFooter>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this,
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// 定义颜色常量
const Color buttonColor = Color(0xFF6F72F1); // 主题紫色(应用栏和按钮边框)
return Container(
color: Colors.transparent,
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 16, bottom: 12),
child: GestureDetector(
onTap: widget.onClear,
child: AssetsUtil.getImageWidget(
'delete.png',
width: 24,
height: 24,
),
),
),
Expanded(
child: Padding(
key: const Key('startBtn'),
padding: const EdgeInsets.only(bottom: 12, left: 16, right: 16),
child: Consumer<MessageService>(
builder: (context, messageService, child) {
// 立即响应录音状态变化,无延迟启动动画
WidgetsBinding.instance.addPostFrameCallback((_) {
if (messageService.isRecording) {
if (!_animationController.isAnimating) {
_animationController.repeat();
}
} else {
if (_animationController.isAnimating) {
_animationController.stop();
}
}
});
return GestureDetector(
onTap: () {
HapticFeedback.heavyImpact();
messageService.abortReply();
},
onLongPress: () {
HapticFeedback.mediumImpact();
// 立即启动动画,无延迟
_animationController.repeat();
Future.delayed(const Duration(milliseconds: 100), () {
HapticFeedback.heavyImpact();
});
messageService.startVoiceInput();
},
onLongPressUp: () {
HapticFeedback.lightImpact();
// 立即停止动画
_animationController.stop();
messageService.stopAndProcessVoiceInput();
},
child: LayoutBuilder(
builder: (context, constraints) {
final containerWidth = constraints.maxWidth;
final waveWidth = containerWidth * 0.57; // 波形宽度为容器的57%
return Container(
height: 48, // 固定高度 48px
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color(0x14FFFFFF), // 白色背景透明度8%
borderRadius: BorderRadius.circular(8), // 圆角按钮 8px
border: Border.all(
color: buttonColor, // 边框颜色 #6F72F1
width: 0.5, // 边框粗细 0.5px
),
),
child: messageService.isRecording
? AudioWaveLarge(
animationController: _animationController,
totalWidth: waveWidth,
)
: Text(
Intl.getCurrentLocale().startsWith('zh')
? '按住 说话'
: 'Hold to Speak',
style: TextStyle(
color: CommonUtil.commonColor,
fontSize: 18,
fontWeight: FontWeight.bold),
),
);
},
),
);
},
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 12, right: 16),
child: GestureDetector(
onTap: () {
},
child: AssetsUtil.getImageWidget(
'keyboard_mini.png',
width: 24,
height: 24,
),
),
),
],
),
);
}
}