Files
xianyan/docs/spec/plugin_system_spec.md
Developer d2bd53f3bc refactor: 完成v6.5.28版本迭代,修复多项体验问题
主要变更:
1. 重构多处Provider初始化逻辑,使用Future.microtask避免build阶段修改state
2. 重命名"灵感"模块为"工作流","天气诗词"改为"情景诗词"
3. 新增插件系统页面与路由,添加speech_to_text_windows插件支持
4. 优化玻璃容器性能,添加性能节流与模糊值适配
5. 新增离线横幅、阅读体验控制器、手势控制器等组件
6. 完善头像审核状态展示与缓存管理
7. 修复键盘弹出与页面路由问题
8. 更新依赖与项目配置,优化widget默认数据
2026-05-26 01:47:47 +08:00

16 KiB
Raw Blame History

闲言APP — 插件系统开发规格文档

创建时间: 2026-05-25 版本: v1.0 状态: 待确认


一、功能概述

在通用设置页新增「插件」入口,点击进入插件管理页面。插件页面参考微信插件列表风格,每个插件卡片包含预览图、启用开关、功能说明和配置项。

两个插件

插件 图标 功能 数据源
翻译守护 🌐 一键翻译句子内容 复用现有 TranslateApiServiceBing/Google/MyMemory等
文本朗读 🔊 语音朗读句子 系统TTSflutter_tts+ Edge TTS在线WebSocket

启用后的UI注入

位置 翻译守护 文本朗读
主页每日推荐卡片 🌐 按钮(爱心左侧) 🔊 按钮(爱心左侧)
句子广场列表卡片 🌐 按钮(收藏左侧) 🔊 按钮(收藏左侧)

二、页面结构

2.1 通用设置 — 新增入口

位置: 在现有分组之间新增「功能扩展」分组

交互设置 (现有)
通知设置 (现有)
功能扩展 (新增) ← 新分组
  └ 插件 → 导航到插件列表页
显示设置 (现有)
性能设置 (现有)
隐私与权限 (现有)
高级 (现有)

决策点:

  • 放在通知设置和显示设置之间(功能扩展属于增强功能,不是基础设置)
  • 或者放在高级分组内作为子项?

2.2 插件列表页

CupertinoPageScaffold
 └ CupertinoSliverNavigationBar (title: "插件")
     └ SliverList
         ├ 分组标题: "已启用的插件"
         ├ 插件卡片: 翻译守护 (图标+名称+简介+启用状态+箭头)
         ├ 插件卡片: 文本朗读 (图标+名称+简介+启用状态+箭头)
         ├ 分组标题: "关于插件"
         └ 说明文字

交互: 点击插件卡片 → 进入插件详情页

2.3 翻译守护 — 插件详情页

CupertinoPageScaffold
 └ CupertinoSliverNavigationBar (title: "翻译守护")
     └ SliverList
         ├ 头部区域 (图标 + 名称 + 版本号)
         ├ 预览Banner (渐变背景 + 标语)
         ├ 启用开关行
         ├ 配置分组: 翻译设置
         │   ├ 翻译引擎 → 导航到引擎选择页
         │   ├ 目标语言 → 导航到语言选择页
         │   ├ 自动检测源语言 → Toggle
         │   └ 降级策略 → 显示当前降级链
         ├ 配置分组: 显示设置
         │   ├ 按钮位置 → 选择器
         │   └ 自动翻译 → Toggle
         └ 配置分组: 数据管理
             ├ 翻译缓存 → 显示缓存大小
             └ 清除缓存 → Action

决策点:

  • 翻译引擎选择页:复用翻译助手的引擎列表,还是简化为仅展示?
    • 复用翻译助手的引擎选择逻辑,共享 translateSettingsProvider
    • 独立一套引擎配置

2.4 文本朗读 — 插件详情页

CupertinoPageScaffold
 └ CupertinoSliverNavigationBar (title: "文本朗读")
     └ SliverList
         ├ 头部区域 (图标 + 名称 + 版本号)
         ├ 预览Banner (渐变背景 + 标语)
         ├ 启用开关行
         ├ 配置分组: 朗读引擎
         │   ├ 系统TTS (推荐·离线) → Radio选择
         │   └ 在线语音合成 → Radio选择 + 子项
         ├ 配置分组: 朗读设置
         │   ├ 语速 → Slider (0.1-2.0)
         │   ├ 音调 → Slider (0.5-2.0)
         │   ├ 音量 → Slider (0.0-1.0)
         │   └ 朗读语言 → 选择器
         └ 配置分组: 在线引擎设置 (仅在线引擎时显示)
             ├ 语音选择 → 选择器
             └ 试听 → Action

决策点:

  • 在线语音合成引擎选择:
    • Edge TTS免费、无需Key、高音质、8种中文语音← 推荐
    • 百度语音合成需申请API Key
    • 同时支持两者

2.5 翻译结果弹窗

使用 AppBottomSheet.showHalf 展示:

StupidSimpleGlassSheetRoute (半屏面板)
 ├ Handle
 ├ 标题: "🌐 翻译结果"
 ├ 翻译结果卡片 (蓝色背景)
 │   ├ 标签: "🌐 英文翻译 · Bing"
 │   └ 翻译文本
 ├ 原文卡片 (灰色背景)
 │   ├ 标签: "📝 原文 · 自动检测: 中文"
 │   └ 原文文本
 └ 操作按钮行
     ├ 复制翻译 → 复制到剪贴板 + Toast
     └ 朗读翻译 → 调用TTS朗读翻译结果

决策点:

  • 弹窗样式:
    • 使用 AppBottomSheet.showHalf(半屏面板,多级吸附 [0.4, 0.7, 1.0]
    • 使用 AppBottomSheet.showCustom(自定义高度)

2.6 朗读控制弹窗

使用 AppBottomSheet.showCustom 展示:

StupidSimpleGlassSheetRoute (自定义面板)
 ├ Handle
 ├ 标题: "🔊 文本朗读"
 ├ 朗读播放器卡片 (紫色渐变背景)
 │   ├ 状态标题 + 语速标签
 │   ├ 当前朗读文本 (最多2行)
 │   └ 播放控制行
 │       ├ 上一句按钮
 │       ├ 播放/暂停按钮 (大圆)
 │       ├ 下一句按钮
 │       └ 进度条 + 时间
 ├ 设置行
 │   ├ 语速滑块
 │   └ 引擎切换
 └ 关闭按钮

决策点:

  • 朗读弹窗是否需要"上一句/下一句"功能?
    • 仅播放当前句子,不需要上下句切换(简化实现)
    • 支持上下句切换

三、数据模型

3.1 插件状态模型

/// 插件启用状态
class PluginState {
  /// 翻译守护是否启用
  final bool translateEnabled;
  
  /// 文本朗读是否启用
  final bool ttsEnabled;
  
  /// 翻译目标语言 (默认: en)
  final String translateTargetLang;
  
  /// 翻译引擎ID (默认: bing)
  final String translateEngineId;
  
  /// 是否自动检测源语言
  final bool autoDetectLang;
  
  /// 是否自动翻译 (滑动到新卡片时自动翻译)
  final bool autoTranslate;
  
  /// TTS引擎类型: 'system' | 'online'
  final String ttsEngineType;
  
  /// TTS在线引擎语音名称 (默认: zh-CN-XiaoxiaoNeural)
  final String ttsOnlineVoice;
  
  /// TTS语速 (0.1-2.0, 默认0.5)
  final double ttsSpeed;
  
  /// TTS音调 (0.5-2.0, 默认1.0)
  final double ttsPitch;
  
  /// TTS音量 (0.0-1.0, 默认0.8)
  final double ttsVolume;
}

3.2 持久化键

类型 默认值 说明
plugin_translate_enabled bool false 翻译守护开关
plugin_tts_enabled bool false 文本朗读开关
plugin_translate_target_lang String 'en' 翻译目标语言
plugin_translate_engine_id String 'bing' 翻译引擎
plugin_auto_detect_lang bool true 自动检测源语言
plugin_auto_translate bool false 自动翻译
plugin_tts_engine_type String 'system' TTS引擎类型
plugin_tts_online_voice String 'zh-CN-XiaoxiaoNeural' 在线TTS语音
plugin_tts_speed double 0.5 TTS语速
plugin_tts_pitch double 1.0 TTS音调
plugin_tts_volume double 0.8 TTS音量

3.3 翻译缓存模型

/// 翻译缓存条目
class TranslateCacheEntry {
  final String sourceText;
  final String sourceLang;
  final String targetLang;
  final String translatedText;
  final String engineId;
  final DateTime cachedAt;
}

决策点:

  • 翻译缓存策略:
    • 内存缓存 + KvStorage 持久化(简单高效,同一句子不重复请求)
    • 使用 Hive 数据库缓存(更强大但增加复杂度)
    • 不缓存,每次都请求

四、服务层设计

4.1 PluginProvider (Riverpod)

/// 插件状态管理
/// 
/// 职责:
/// 1. 管理插件启用/禁用状态
/// 2. 管理插件配置参数
/// 3. 持久化到 KvStorage
/// 4. 提供便捷方法供卡片组件查询
@riverpod
class PluginNotifier extends _$PluginNotifier {
  @override
  PluginState build() { /* 从KvStorage恢复状态 */ }
  
  // 翻译守护
  void setTranslateEnabled(bool enabled);
  void setTranslateTargetLang(String lang);
  void setTranslateEngine(String engineId);
  void setAutoDetectLang(bool auto);
  void setAutoTranslate(bool auto);
  
  // 文本朗读
  void setTtsEnabled(bool enabled);
  void setTtsEngineType(String type);
  void setTtsOnlineVoice(String voice);
  void setTtsSpeed(double speed);
  void setTtsPitch(double pitch);
  void setTtsVolume(double volume);
}

4.2 翻译插件服务 (复用 TranslateApiService)

/// 翻译插件服务
/// 
/// 复用现有翻译API体系:
/// - BingTranslateService (默认首选)
/// - GoogleTranslateService
/// - MyMemoryTranslateService
/// - AppWorldsTranslateService
/// - LibreTranslateService
/// - CustomTranslateService
/// 
/// 降级顺序: 用户选择 → bing → mymemory → appworlds → google → libre
class TranslatePluginService {
  /// 翻译单个句子
  Future<TranslateResult> translateSentence(String text, {String? targetLang});
  
  /// 获取翻译(优先缓存)
  Future<String> getTranslation(String text, {String? targetLang});
  
  /// 清除翻译缓存
  void clearCache();
}

4.3 在线TTS服务 (Edge TTS)

/// Edge TTS 在线语音合成服务
/// 
/// 通过 WebSocket 连接 speech.platform.bing.com
/// 支持 100+ 语音,音质接近真人
/// 无需 API Key
/// 
/// 协议流程:
/// 1. WebSocket 握手 (带 TrustedClientToken)
/// 2. 发送 speech.config 配置消息
/// 3. 发送 SSML 合成请求
/// 4. 接收音频数据流 (MP3格式)
/// 5. 播放音频
class OnlineTtsService {
  /// 合成语音并播放
  Future<void> speak(String text, {String? voice});
  
  /// 停止播放
  Future<void> stop();
  
  /// 暂停播放
  Future<void> pause();
  
  /// 获取可用语音列表
  Future<List<VoiceInfo>> getAvailableVoices();
  
  /// 状态流
  Stream<TtsState> get onStateChanged;
  Stream<(int, int, String)> get onProgress;
}

Edge TTS WebSocket 协议细节:

  • 端点: wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1
  • 认证: URL参数 TrustedClientToken=6A5AA1D4EAFF4E9FB37E23D68491D6F4
  • 请求格式: SSML + 配置消息(二进制帧头 + 音频数据)
  • 输出格式: audio-24khz-48kbitrate-mono-mp3
  • 中文语音: XiaoxiaoNeural(女), YunxiNeural(男), YunjianNeural(男), YunyangNeural(男新闻), XiaoyiNeural(女), YunxiaNeural(男), XiaobeiNeural(东北), XiaoniNeural(陕西)

决策点:

  • Edge TTS 音频播放方式:
    • WebSocket接收MP3 → 临时文件 → audioplayers播放项目已有audioplayers依赖
    • WebSocket接收MP3 → 内存缓冲 → audioplayers播放更高效但更复杂

五、UI组件设计

5.1 卡片按钮注入方式

DailyCard (home_daily_card.dart):

当前 buildAuthorRow() 布局:

Row [作者(Expanded), ⭐收藏, ❤️点赞]

修改后:

Row [作者(Expanded), 🌐翻译(条件), 🔊朗读(条件), ⭐收藏, ❤️点赞]

条件渲染逻辑:

if (ref.watch(pluginProvider.select((s) => s.translateEnabled)))
  _buildTranslateButton(sentence),
if (ref.watch(pluginProvider.select((s) => s.ttsEnabled)))
  _buildTtsButton(sentence),

SentenceCard (home_sentence_card.dart):

当前 _buildActionRow() 布局:

Row [作者(Expanded), ⭐收藏, ❤️点赞]

修改后:

Row [作者(Expanded), 🌐翻译(条件), 🔊朗读(条件), ⭐收藏, ❤️点赞]

5.2 按钮样式

属性 翻译按钮 朗读按钮
图标 CupertinoIcons.globe CupertinoIcons.speaker_2_fill
颜色 主题色 ext.primary 紫色 Color(0xFFAF52DE)
大小 18px 18px
间距 与收藏按钮间距 AppSpacing.sm 与翻译按钮间距 AppSpacing.sm
动画 点击缩放0.9 点击缩放0.9

决策点:

  • 按钮图标选择:

    • CupertinoIconsiOS风格统一
    • Emoji🌐/🔊,与现有收藏风格一致)

    → 推荐 CupertinoIcons因为项目规则要求"优先使用iOS风格组件"。但现有收藏按钮用的是emoji ,点赞用的是 CupertinoIcons.heart。

    最终方案: 翻译用 CupertinoIcons.globe,朗读用 CupertinoIcons.speaker_2_fill,与点赞按钮风格统一。

5.3 翻译弹窗组件

class TranslateSheet extends ConsumerStatefulWidget {
  final String text;           // 原文
  final String? sourceLang;   // 源语言(可选)
  final AppThemeExtension ext;
  
  static void show(BuildContext context, {...}) {
    AppBottomSheet.showHalf(
      context: context,
      builder: (context) => TranslateSheet(...),
    );
  }
}

5.4 朗读控制弹窗组件

class TtsPlayerSheet extends ConsumerStatefulWidget {
  final String text;           // 朗读文本
  final AppThemeExtension ext;
  
  static void show(BuildContext context, {...}) {
    AppBottomSheet.showCustom(
      context: context,
      builder: (context) => TtsPlayerSheet(...),
    );
  }
}

六、文件清单

新增文件

文件路径 类型 行数估算 说明
lib/features/mine/settings/presentation/plugin/plugin_page.dart 页面 ~200 插件列表页
lib/features/mine/settings/presentation/plugin/translate_plugin_page.dart 页面 ~350 翻译守护详情页
lib/features/mine/settings/presentation/plugin/tts_plugin_page.dart 页面 ~350 文本朗读详情页
lib/features/mine/settings/providers/plugin_provider.dart 状态 ~250 插件状态管理
lib/core/services/audio/online_tts_service.dart 服务 ~300 Edge TTS在线语音合成
lib/shared/widgets/plugin/translate_sheet.dart 组件 ~150 翻译结果弹窗
lib/shared/widgets/plugin/tts_player_sheet.dart 组件 ~200 朗读控制弹窗

修改文件

文件路径 修改内容
lib/features/mine/settings/presentation/general/general_settings_sections.dart 新增「功能扩展」分组 + 插件导航项
lib/features/mine/settings/presentation/general/general_settings_page.dart _onNavigate 增加 plugin case
lib/core/router/app_routes.dart 新增 plugintranslatePluginttsPlugin 路由常量
lib/core/router/settings_routes.dart 新增3条路由注册
lib/core/router/ohos_nav_bridge.dart 鸿蒙端路由注册
lib/features/home/presentation/home_daily_card.dart buildAuthorRow 注入翻译/朗读按钮
lib/features/home/presentation/home_sentence_card.dart _buildActionRow 注入翻译/朗读按钮
CHANGELOG.md 记录功能变更

七、跨平台兼容

平台 翻译守护 文本朗读(系统TTS) 文本朗读(Edge TTS)
Android HTTP API flutter_tts WebSocket
iOS HTTP API flutter_tts WebSocket
macOS HTTP API flutter_tts WebSocket
Windows HTTP API flutter_tts WebSocket
Linux HTTP API flutter_tts WebSocket
鸿蒙 HTTP API flutter_tts(本地化) WebSocket
Web HTTP API ⚠️ 有限支持 WebSocket

注意事项:

  • Web端 flutter_tts 支持有限,在线引擎作为备选
  • 鸿蒙端 flutter_tts 已本地化适配pubspec.yaml中有path引用
  • Edge TTS 的 WebSocket 在所有平台均可用(基于 dart:io 的 WebSocket

八、待确认决策项

  1. 插件入口位置: 功能扩展独立分组 vs 放在高级分组内?
  2. 翻译引擎配置: 复用翻译助手配置 vs 独立配置?
  3. 在线TTS引擎: 仅Edge TTS vs 同时支持百度?
  4. 翻译缓存: 内存缓存 vs Hive缓存 vs 不缓存?
  5. 朗读弹窗: 仅播放当前句 vs 支持上下句?
  6. Edge TTS播放: 临时文件播放 vs 内存缓冲播放?
  7. 按钮图标: CupertinoIcons vs Emoji