AI人设可以配置
This commit is contained in:
@@ -7,15 +7,15 @@ import '../../../models/ai_config.dart';
|
||||
import '../../../providers/ai_config_provider.dart';
|
||||
import '../../../utils/toast.dart';
|
||||
import '../../../widgets/state_views.dart';
|
||||
import 'ai_persona_page.dart';
|
||||
|
||||
/// AI 模型配置管理:列出现有配置、切换、增删改。
|
||||
/// 「AI 设置」页:两个 Tab —— 模型 / 人设。
|
||||
///
|
||||
/// 设计上的三个要点:
|
||||
/// 1. **「默认」那一项是虚拟的** —— 值来自服务器 `.env`,不能编辑/删除。
|
||||
/// 它就是「什么都不选」的状态,选中后请求里 configId 传 null。
|
||||
/// 2. **列表不打勾谁在用**,打勾的是 [selectedAiConfigProvider] 里存的那个。
|
||||
/// 选中状态存在手机本地,不改服务端 —— 否则网页端和手机会互相打架。
|
||||
/// 3. **api key 只显示掩码**。编辑时留空 = 不改动。
|
||||
/// 为什么是 Tab 而不是顶栏再加一个胶囊:顶栏已经有返回、标题、当前模型胶囊、
|
||||
/// 历史、新对话五块,320 宽的小屏塞不下第二个(`page_layout_test.dart` 会抓出来)。
|
||||
/// 而且模型和人设本来就是**一对平行的配置**,放一个页面里切换很自然。
|
||||
///
|
||||
/// 入口函数名保留 `openAiConfigPage` —— 助手页的胶囊用它,不用改。
|
||||
Future<void> openAiConfigPage(BuildContext context) {
|
||||
return Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (_) => const AiConfigPage()),
|
||||
@@ -25,21 +25,52 @@ Future<void> openAiConfigPage(BuildContext context) {
|
||||
class AiConfigPage extends ConsumerWidget {
|
||||
const AiConfigPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('AI 设置'),
|
||||
bottom: const TabBar(
|
||||
labelColor: Color(0xFFC8956E),
|
||||
unselectedLabelColor: Color(0xFFBCAAA4),
|
||||
indicatorColor: Color(0xFFC8956E),
|
||||
indicatorSize: TabBarIndicatorSize.label,
|
||||
tabs: [
|
||||
Tab(text: '模型'),
|
||||
Tab(text: '人设'),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: const TabBarView(
|
||||
children: [
|
||||
AiModelTab(),
|
||||
AiPersonaTab(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 模型配置 Tab(原来的整页内容,去掉了自己的 Scaffold/AppBar)
|
||||
class AiModelTab extends ConsumerWidget {
|
||||
const AiModelTab({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final configs = ref.watch(aiConfigsProvider);
|
||||
final selectedId = ref.watch(selectedAiConfigProvider);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('AI 模型'),
|
||||
actions: [
|
||||
IconButton(
|
||||
tooltip: '新增配置',
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () => _openEditor(context, ref, null),
|
||||
),
|
||||
],
|
||||
backgroundColor: const Color(0xFFFAF8F5),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () => _openEditor(context, ref, null),
|
||||
backgroundColor: const Color(0xFFC8956E),
|
||||
foregroundColor: Colors.white,
|
||||
tooltip: '新增配置',
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
body: configs.when(
|
||||
loading: () => const LoadingView(tip: '正在加载配置...'),
|
||||
@@ -50,7 +81,7 @@ class AiConfigPage extends ConsumerWidget {
|
||||
data: (list) {
|
||||
final custom = list.where((c) => c.editable).length;
|
||||
return ListView(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 24),
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 88),
|
||||
children: [
|
||||
_introCard(),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
Reference in New Issue
Block a user