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.

224 lines
9.7 KiB

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/tts_test_controller.dart';
class TtsTestView extends GetView<TtsTestController> {
const TtsTestView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// 强制更新控制器状态
WidgetsBinding.instance.addPostFrameCallback((_) {
// 在下一帧渲染完成后调用
controller.updateUIState();
});
return Scaffold(
appBar: AppBar(
title: const Text('语音合成测试'),
centerTitle: true,
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 播放控制
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'播放控制',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Obx(() {
return ElevatedButton.icon(
onPressed: controller.isAudioPlaying.value || controller.isLoading.value
? null
: () => controller.speakContinuousTexts(),
icon: controller.isAudioPlaying.value
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2)
)
: const Icon(Icons.playlist_play),
label: Text(controller.isAudioPlaying.value ? '播放中...' : '全部播放'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
);
}),
Obx(() => ElevatedButton.icon(
onPressed: controller.isAudioPlaying.value
? () => controller.stopSpeaking()
: null,
icon: const Icon(Icons.stop),
label: const Text('停止'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
)),
],
),
],
),
),
),
const SizedBox(height: 16),
// 播报内容列表
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'播报内容列表',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
// 生成5条可点击的播报内容
Obx(() => ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: controller.speechTexts.length,
separatorBuilder: (context, index) => const Divider(height: 1),
itemBuilder: (context, index) {
final isPlaying = controller.isAudioPlaying.value &&
controller.currentPlayingIndex.value == index;
return ListTile(
title: Text(
controller.speechTexts[index],
style: TextStyle(
fontWeight: isPlaying ? FontWeight.bold : FontWeight.normal,
color: isPlaying ? Colors.blue : null,
),
),
leading: CircleAvatar(
backgroundColor: isPlaying ? Colors.blue : Colors.grey.shade200,
radius: 18,
child: Icon(
isPlaying ? Icons.volume_up : Icons.play_arrow,
color: isPlaying ? Colors.white : Colors.black,
size: 20,
),
),
trailing: isPlaying
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: null,
onTap: controller.isAudioPlaying.value || controller.isLoading.value
? null
: () => controller.playSingle(index),
enabled: !(controller.isAudioPlaying.value || controller.isLoading.value),
tileColor: isPlaying ? Colors.blue.withOpacity(0.1) : null,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: isPlaying
? const BorderSide(color: Colors.blue, width: 1)
: BorderSide.none,
),
);
},
)),
],
),
),
),
const SizedBox(height: 16),
// 状态显示
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'状态',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Obx(() => Text(
controller.statusMessage.value,
style: TextStyle(
color: controller.isLoading.value
? Colors.orange
: controller.isAudioPlaying.value
? Colors.green
: Colors.grey,
fontWeight: FontWeight.bold,
),
)),
const SizedBox(height: 8),
Obx(() => controller.errorMessage.value.isNotEmpty
? Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.red.shade50,
borderRadius: BorderRadius.circular(4),
border: Border.all(color: Colors.red.shade200),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.error_outline, color: Colors.red, size: 16),
SizedBox(width: 8),
Text(
'错误',
style: TextStyle(
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
],
),
SizedBox(height: 4),
Text(
controller.errorMessage.value,
style: TextStyle(color: Colors.red.shade800),
),
],
),
)
: const SizedBox.shrink()),
],
),
),
),
],
),
),
),
);
}
}