import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../controllers/tts_test_controller.dart'; class TtsTestView extends GetView { 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()), ], ), ), ), ], ), ), ), ); } }