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) { return Scaffold( appBar: AppBar( title: const Text('火山语音合成测试'), centerTitle: true, ), body: 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: 8), Obx(() => DropdownButton( isExpanded: true, value: controller.selectedVoiceType.value, onChanged: (String? newValue) { if (newValue != null) { controller.selectedVoiceType.value = newValue; } }, items: controller.voiceTypes.map>((String value) { // 根据语音类型ID获取友好名称 String displayName = _getVoiceTypeDisplayName(value); return DropdownMenuItem( value: value, child: Text(displayName), ); }).toList(), )), ], ), ), ), 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), TextField( controller: controller.textController, maxLines: 5, decoration: const InputDecoration( hintText: '请输入要转换为语音的文本...', border: OutlineInputBorder(), ), ), ], ), ), ), 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), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Obx(() => ElevatedButton.icon( onPressed: controller.isPlaying.value || controller.isLoading.value ? null : () => controller.speakText(), icon: controller.isLoading.value ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2) ) : const Icon(Icons.play_arrow), label: Text(controller.isLoading.value ? '准备中...' : '播放'), )), ElevatedButton.icon( onPressed: controller.isPlaying.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: 8), Obx(() => Text( controller.isLoading.value ? '准备中...' : controller.isPlaying.value ? '正在播放...' : '就绪', style: TextStyle( color: controller.isLoading.value ? Colors.orange : controller.isPlaying.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), ), if (controller.errorMessage.value.contains('授权错误')) Padding( padding: const EdgeInsets.only(top: 8.0), child: Text( '提示: 请尝试选择基础语音类型,如"zh_male_qingse_common"或"zh_female_qingse_common"', style: TextStyle( fontStyle: FontStyle.italic, color: Colors.red.shade700, ), ), ), ], ), ) : const SizedBox.shrink()), ], ), ), ), ], ), ), ); } // 根据语音类型ID获取友好名称 String _getVoiceTypeDisplayName(String voiceTypeId) { switch (voiceTypeId) { // 趣味方言 case 'zh_female_wanqudashu_moon_bigtts': return '湾区大叔 (趣味方言)'; case 'zh_female_daimengchuanmei_moon_bigtts': return '呆萌川妹 (趣味方言)'; case 'zh_male_guozhoudege_moon_bigtts': return '广州德哥 (趣味方言)'; case 'zh_male_beijingxiaoye_moon_bigtts': return '北京小爷 (趣味方言)'; case 'zh_male_haoyuxiaoge_moon_bigtts': return '浩宇小哥 (趣味方言)'; // 通用场景 case 'zh_male_shaonianzixin_moon_bigtts': return '少年梓辛/Brayan (通用场景)'; // 角色扮演 case 'zh_female_meilinvyou_moon_bigtts': return '魅力女友 (角色扮演)'; case 'zh_male_shenyeboke_moon_bigtts': return '深夜播客 (角色扮演)'; case 'zh_female_sajiaonvyou_moon_bigtts': return '柔美女友 (角色扮演)'; case 'zh_female_yuanqinvyou_moon_bigtts': return '撒娇学妹 (角色扮演)'; // 基础语音类型 case 'zh_male_qingse_common': return '基础男声'; case 'zh_female_qingse_common': return '基础女声'; case 'zh_male_M392_conversation_wvae_bigtts': return '高级男声'; case 'zh_female_F392_conversation_wvae_bigtts': return '高级女声'; default: return voiceTypeId; } } }