import 'package:flutter/material.dart'; import 'device_category.dart'; /// 功能模块(agent)定义。 /// /// AI 页与广场页共用同一份注册表:广场展示全部,AI 页只展示用户启用的那些, /// 顺序由 [AgentModuleService] 持久化。新增 agent 只需往 [AgentModules.all] /// 里加一条,两个页面自动生效。 class AgentModule { const AgentModule({ required this.id, required this.title, required this.icon, required this.gradient, this.subtitle, this.requiresDevice = false, this.comingSoon = false, }); /// 唯一标识,持久化时存的就是它,改名会导致用户已有配置失效 final String id; /// i18n key,展示时 `.tr`(不是中文文案本身) final String title; /// i18n key,展示时 `.tr` final String? subtitle; final IconData icon; /// 卡片图标底色渐变(两个色值) final List gradient; /// 是否依赖设备连接:未连接时卡片置灰,点击提示连接设备 final bool requiresDevice; /// 尚未实现的占位模块:可以加到 AI 页排版,但点击只提示"敬请期待" final bool comingSoon; } /// 全部可用模块的注册表 class AgentModules { AgentModules._(); // ---------- 已实现(对应现有路由) ---------- static const String meeting = 'meeting'; static const String simultaneous = 'simultaneous'; static const String faceToFace = 'faceToFace'; static const String call = 'call'; static const String audioVideo = 'audioVideo'; static const String callRecording = 'callRecording'; static const String fieldRecording = 'fieldRecording'; /// EMAI 助手:原来 AI 页底部那颗悬浮球,改成广场里的一个正式 agent static const String emaiAssistant = 'emaiAssistant'; static const String textTranslation = 'textTranslation'; static const String pictureTranslation = 'pictureTranslation'; // ---------- 规划中(占位,方便测试增删) ---------- static const String englishChat = 'englishChat'; static const String englishStudy = 'englishStudy'; static const String kidsStory = 'kidsStory'; static const List all = [ AgentModule( id: meeting, title: 'agentMeeting', subtitle: 'agentMeetingDesc', icon: Icons.groups_2, gradient: [Color(0xFFAB47BC), Color(0xFFEC407A)], ), AgentModule( id: emaiAssistant, title: 'agentEmai', subtitle: 'agentEmaiDesc', icon: Icons.auto_awesome, gradient: [Color(0xFF5B8DEF), Color(0xFF7E57C2)], ), AgentModule( id: simultaneous, title: 'agentSimultaneous', subtitle: 'agentSimultaneousDesc', icon: Icons.record_voice_over, gradient: [Color(0xFF4CAF50), Color(0xFF009688)], ), AgentModule( id: faceToFace, title: 'agentFaceToFace', subtitle: 'agentFaceToFaceDesc', icon: Icons.forum, gradient: [Color(0xFF42A5F5), Color(0xFF1E88E5)], ), AgentModule( id: callRecording, title: 'agentCallRecording', subtitle: 'agentCallRecordingDesc', icon: Icons.fiber_manual_record, gradient: [Color(0xFFEF5350), Color(0xFFE53935)], requiresDevice: true, ), AgentModule( id: fieldRecording, title: 'agentFieldRecording', // 有设备走设备录音通路,没设备退回手机麦克风,两种情况都能用 subtitle: 'agentFieldRecordingDesc', icon: Icons.mic, gradient: [Color(0xFF26C6DA), Color(0xFF00838F)], ), AgentModule( id: call, title: 'agentCall', subtitle: 'agentCallDesc', icon: Icons.phone_in_talk, gradient: [Color(0xFFFFA726), Color(0xFFFB8C00)], requiresDevice: true, ), AgentModule( id: audioVideo, title: 'agentAudioVideo', subtitle: 'agentAudioVideoDesc', // 放映机图标:这个功能是音视频内容翻译,用投影/放映的意象更贴切 icon: Icons.slideshow, gradient: [Color(0xFF5C6BC0), Color(0xFF3949AB)], ), AgentModule( id: textTranslation, title: 'agentTextTranslation', subtitle: 'agentTextTranslationDesc', icon: Icons.translate, gradient: [Color(0xFF26A69A), Color(0xFF00796B)], ), AgentModule( id: pictureTranslation, title: 'agentPictureTranslation', subtitle: 'agentPictureTranslationDesc', icon: Icons.image_search, gradient: [Color(0xFFEC407A), Color(0xFFAD1457)], ), AgentModule( id: englishChat, title: 'agentEnglishChat', subtitle: 'agentEnglishChatDesc', icon: Icons.chat_bubble_outline, gradient: [Color(0xFF7E57C2), Color(0xFF5E35B1)], comingSoon: true, ), AgentModule( id: englishStudy, title: 'agentEnglishStudy', subtitle: 'agentEnglishStudyDesc', icon: Icons.menu_book, gradient: [Color(0xFF29B6F6), Color(0xFF0288D1)], comingSoon: true, ), AgentModule( id: kidsStory, title: 'agentKidsStory', subtitle: 'agentKidsStoryDesc', icon: Icons.auto_stories, gradient: [Color(0xFFFF7043), Color(0xFFF4511E)], comingSoon: true, ), ]; /// AI 页首次进入时的默认模块。 /// /// 没连过设备也能用的三个(都只依赖手机本身):语音记录助手、EMAI助手、现场录音。 /// 依赖设备的功能等连上对应设备后由 [defaultsForCategory] 自动补进来。 static const List defaultEnabled = [ // 网格区(左大 + 右上下两小) call, simultaneous, faceToFace, // 并排方块 meeting, audioVideo, // 往下是整行横条,现场录音是第一行 fieldRecording, callRecording, textTranslation, pictureTranslation, emaiAssistant, ]; /// 各设备品类**第一次连接成功**时要铺到 AI 页的默认功能与顺序。 /// /// key 用的是 [DeviceCategories] 的品类 id。只在该品类首次连接时生效一次 /// (由 AgentModuleService 记录已应用过的品类),之后用户怎么增删排序都不再覆盖。 static const Map> defaultsByCategory = { // AI手机支架 / AI录音卡片:只有录音相关能力,AI 页就只留这三个 DeviceCategories.phoneHolder: [meeting, fieldRecording, callRecording], DeviceCategories.noteCard: [meeting, fieldRecording, callRecording], // AI耳机(恒玄):通话 + 翻译整套都能跑,铺开全量默认编排 DeviceCategories.earphone: defaultEnabled, }; static List defaultsForCategory(String? categoryId) { if (categoryId == null) return const []; return defaultsByCategory[categoryId] ?? const []; } static AgentModule? byId(String id) { for (final m in all) { if (m.id == id) return m; } return null; } }