feat: 增加AI配置文件与TTS自动朗读,修复二级页面返回按钮与音频播放

This commit is contained in:
shenlei
2026-09-15 19:11:39 +09:00
parent 37c86f7ecb
commit a717365c10
18 changed files with 1322 additions and 397 deletions
@@ -199,8 +199,10 @@ class _AbilityRow extends StatelessWidget {
}
class SettingsPage extends StatefulWidget {
const SettingsPage({super.key, required this.state});
const SettingsPage({super.key, required this.state, this.onBack});
final AppState state;
final VoidCallback? onBack;
@override
State<SettingsPage> createState() => _SettingsPageState();
}
@@ -209,6 +211,8 @@ class _SettingsPageState extends State<SettingsPage> {
late final TextEditingController endpoint;
late final TextEditingController model;
final apiKey = TextEditingController();
bool _testingConnection = false;
@override
void initState() {
super.initState();
@@ -226,7 +230,20 @@ class _SettingsPageState extends State<SettingsPage> {
@override
Widget build(BuildContext context) => AppPage(
appBar: AppBar(title: const Text('学习设置')),
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back),
tooltip: "返回",
onPressed: () {
if (widget.onBack != null) {
widget.onBack!();
} else if (Navigator.canPop(context)) {
Navigator.pop(context);
}
},
),
title: const Text('学习设置'),
),
child: SpacedColumn(
spacing: 4,
children: [
@@ -350,17 +367,49 @@ class _SettingsPageState extends State<SettingsPage> {
},
),
SecondaryButton(
label: '测试连接',
label: _testingConnection ? '正在测试连接...' : '测试连接',
onPressed: _testingConnection
? null
: () async {
setState(() => _testingConnection = true);
final result = await AiService.instance.testConnection(
provider: widget.state.aiProvider,
endpoint: endpoint.text,
model: model.text,
explicitApiKey: apiKey.text,
);
if (!mounted) return;
setState(() => _testingConnection = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(result.message),
backgroundColor:
result.ok ? AppColors.green : Colors.redAccent,
duration: const Duration(seconds: 4),
),
);
},
),
SecondaryButton(
label: '从配置文件重载 (ai_config.json)',
onPressed: () async {
final result = await AiService.instance.testConnection(
provider: widget.state.aiProvider,
endpoint: endpoint.text,
model: model.text,
);
if (!context.mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(result.message)));
final ok = await widget.state.reloadAiConfigFromAsset();
if (!mounted) return;
if (ok) {
setState(() {
endpoint.text = widget.state.aiEndpoint;
model.text = widget.state.aiModel;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('已从 assets/config/ai_config.json 载入配置。'),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('未找到配置文件或解析失败。')),
);
}
},
),
const Divider(height: 28),