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
224 lines
9.7 KiB
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import '../controllers/volcano_tts_test_controller.dart';
|
|
|
|
class VolcanoTtsTestView extends GetView<VolcanoTtsTestController> {
|
|
const VolcanoTtsTestView({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()),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|