You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
240 lines
8.6 KiB
240 lines
8.6 KiB
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:get/get.dart';
|
|
import '../controllers/realtime_controller.dart';
|
|
import 'widgets/voice_mic_flow.dart';
|
|
|
|
class RealtimeView extends GetView<RealtimeController> {
|
|
const RealtimeView({Key? key}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
// 设置状态栏为黑色文字
|
|
SystemChrome.setSystemUIOverlayStyle(
|
|
const SystemUiOverlayStyle(
|
|
statusBarColor: Colors.transparent,
|
|
statusBarIconBrightness: Brightness.dark,
|
|
statusBarBrightness: Brightness.light,
|
|
),
|
|
);
|
|
|
|
return Scaffold(
|
|
backgroundColor: Colors.white,
|
|
body: SafeArea(
|
|
child: Stack(
|
|
children: [
|
|
// 右上角图标按钮
|
|
Positioned(
|
|
top: 16,
|
|
right: 16,
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// 分享按钮
|
|
Icon(
|
|
Icons.ios_share,
|
|
color: Colors.grey[600],
|
|
size: 24,
|
|
),
|
|
const SizedBox(width: 20),
|
|
// 设置按钮
|
|
Icon(
|
|
Icons.tune,
|
|
color: Colors.grey[600],
|
|
size: 24,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
// 状态和字幕显示区域
|
|
Positioned(
|
|
top: 100,
|
|
left: 20,
|
|
right: 20,
|
|
child: Column(
|
|
children: [
|
|
// 当前状态显示
|
|
Obx(() => Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
margin: const EdgeInsets.only(bottom: 12),
|
|
decoration: BoxDecoration(
|
|
color: Colors.black.withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(20),
|
|
),
|
|
child: Text(
|
|
controller.currentStatus.value,
|
|
textAlign: TextAlign.center,
|
|
style: const TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.black87,
|
|
),
|
|
),
|
|
)),
|
|
|
|
// 用户ASR内容显示
|
|
Obx(() => AnimatedContainer(
|
|
duration: const Duration(milliseconds: 300),
|
|
width: double.infinity,
|
|
height: controller.userSpeechText.value.isNotEmpty ? null : 0,
|
|
padding: controller.userSpeechText.value.isNotEmpty
|
|
? const EdgeInsets.symmetric(horizontal: 16, vertical: 12)
|
|
: EdgeInsets.zero,
|
|
margin: controller.userSpeechText.value.isNotEmpty
|
|
? const EdgeInsets.only(bottom: 8)
|
|
: EdgeInsets.zero,
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(16),
|
|
border: Border.all(
|
|
color: Colors.blue.withOpacity(0.3),
|
|
width: 1,
|
|
),
|
|
),
|
|
child: controller.userSpeechText.value.isNotEmpty
|
|
? Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
'你说:',
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w600,
|
|
color: Colors.blue,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
controller.userSpeechText.value,
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
color: Colors.black87,
|
|
),
|
|
),
|
|
],
|
|
)
|
|
: null,
|
|
)),
|
|
|
|
// AI回复内容显示
|
|
Obx(() => AnimatedContainer(
|
|
duration: const Duration(milliseconds: 300),
|
|
width: double.infinity,
|
|
height: controller.aiResponseText.value.isNotEmpty ? null : 0,
|
|
padding: controller.aiResponseText.value.isNotEmpty
|
|
? const EdgeInsets.symmetric(horizontal: 16, vertical: 12)
|
|
: EdgeInsets.zero,
|
|
margin: controller.aiResponseText.value.isNotEmpty
|
|
? const EdgeInsets.only(bottom: 20)
|
|
: EdgeInsets.zero,
|
|
decoration: BoxDecoration(
|
|
color: Colors.green.withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(16),
|
|
border: Border.all(
|
|
color: Colors.green.withOpacity(0.3),
|
|
width: 1,
|
|
),
|
|
),
|
|
child: controller.aiResponseText.value.isNotEmpty
|
|
? Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
'AI回复:',
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w600,
|
|
color: Colors.green,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
controller.aiResponseText.value,
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
color: Colors.black87,
|
|
),
|
|
),
|
|
],
|
|
)
|
|
: null,
|
|
)),
|
|
],
|
|
),
|
|
),
|
|
|
|
// 中间会呼吸的云彩动画
|
|
Positioned.fill(
|
|
child: Align(
|
|
alignment: const Alignment(0, 0.1),
|
|
child: const VoiceMicFlow(size: 280),
|
|
),
|
|
),
|
|
|
|
// 底部控制按钮
|
|
Positioned(
|
|
bottom: 80,
|
|
left: 0,
|
|
right: 0,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 40),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
// 摄像头按钮
|
|
_buildBottomButton(Icons.videocam, null),
|
|
// 麦克风按钮
|
|
_buildBottomButton(Icons.mic_none, controller.toggleListening),
|
|
// 更多按钮
|
|
_buildBottomButton(Icons.more_horiz, null),
|
|
// 关闭按钮
|
|
_buildBottomButton(Icons.close, controller.closeAndGoBack),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
// Home Indicator
|
|
Positioned(
|
|
bottom: 8,
|
|
left: 0,
|
|
right: 0,
|
|
child: Center(
|
|
child: Container(
|
|
width: 134,
|
|
height: 5,
|
|
decoration: BoxDecoration(
|
|
color: Colors.black,
|
|
borderRadius: BorderRadius.circular(2.5),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 构建底部圆形按钮
|
|
Widget _buildBottomButton(IconData icon, VoidCallback? onTap) {
|
|
return GestureDetector(
|
|
onTap: onTap,
|
|
child: Container(
|
|
width: 60,
|
|
height: 60,
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[200],
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(
|
|
icon,
|
|
color: Colors.black,
|
|
size: 26,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|