chore: 批量整理优化项目代码与配置

- 新增模型目录占位文件与翻译类型拆分
- 调整路由配置与桌面端窗口初始化
- 移除多处冗余图表配置项
- 重构右侧面板注册表与三栏布局组件
- 添加智能AppBar、拖拽书签等新功能组件
- 优化安卓编译配置与多平台插件注册
- 新增翻译覆盖率测试与共享组件
- 格式化代码与修复静态分析警告
This commit is contained in:
Developer
2026-05-29 10:08:02 +08:00
parent 5a49d20c8a
commit ca68fe29c7
105 changed files with 14839 additions and 5571 deletions

View File

@@ -0,0 +1,528 @@
# 宽屏适配增强 — 22项任务实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 实施宽屏适配的22项增强任务涵盖架构优化、UX改进、动画升级、库集成和高级功能
**Architecture:** 以 splitViewProvider 为唯一数据源,消除双写;使用 flutter_animate 替代手动 AnimationController引入 freezed 生成不可变状态类;构建三栏布局支持超宽屏
**Tech Stack:** Flutter 3.11+ / Riverpod 3.0 / flutter_animate 4.5 / freezed 3.2 / photo_view 0.15 / heroine 0.7 / desktop_drop / bitsdojo_window
---
## 文件结构
### 新建文件
- `lib/core/providers/split_view_provider.freezed.dart` — freezed 生成
- `lib/core/layout/panel_cache.dart` — 面板缓存管理
- `lib/core/layout/smart_app_bar.dart` — 智能AppBar位置适配
- `lib/core/layout/panel_bookmark.dart` — 面板书签功能
- `lib/core/layout/triple_column_view.dart` — 三栏布局组件
### 修改文件
- `lib/core/providers/split_view_provider.dart` — freezed重写+三栏状态
- `lib/core/layout/adaptive_split_view.dart` — flutter_animate+三栏
- `lib/core/layout/split_divider.dart` — 双击重置+触控区域增大
- `lib/core/layout/overview_dashboard.dart` — 接入真实Provider数据
- `lib/core/layout/app_shell.dart` — 横屏居中+三栏+智能AppBar
- `lib/core/layout/adaptive_nav_bar.dart` — 自定义标题栏融合
- `lib/features/discover/presentation/panels/chat_flow_panel.dart` — 键盘适配
- `lib/features/home/presentation/home_page.dart` — Hero动画
- `lib/features/home/presentation/panels/sentence_detail_panel.dart` — photo_view+Hero
- `lib/features/mine/settings/providers/sub/display_settings_provider.dart` — 移除分屏字段
- `lib/features/mine/settings/providers/general_settings_provider.dart` — 移除分屏setter
- `lib/features/mine/settings/presentation/general/general_settings_sections.dart` — 设置项读取splitViewProvider
- `lib/features/mine/settings/presentation/general/general_settings_pickers.dart` — picker读取splitViewProvider
- `pubspec.yaml` — 新增依赖
---
## Phase 1: 核心架构修复
### Task 1: 状态管理去重 — splitViewProvider 为唯一数据源
**Files:**
- Modify: `lib/core/providers/split_view_provider.dart`
- Modify: `lib/features/mine/settings/providers/sub/display_settings_provider.dart`
- Modify: `lib/features/mine/settings/providers/general_settings_provider.dart`
- Modify: `lib/features/mine/settings/presentation/general/general_settings_sections.dart`
- Modify: `lib/features/mine/settings/presentation/general/general_settings_pickers.dart`
- Modify: `lib/features/mine/settings/presentation/general/general_settings_page.dart`
- [ ] **Step 1: 从 DisplaySettingsState 移除分屏三字段**
`display_settings_provider.dart` 中移除 `navBarPositionIndex``splitRatio``splitViewEnabled` 三个字段及其 copyWith 参数、fromStorage/saveToStorage 中的对应行、setter 方法。
- [ ] **Step 2: 从 GeneralSettingsState 移除分屏相关 getter 和 setter**
`general_settings_provider.dart` 中移除 `navBarPositionIndex``splitRatio``splitViewEnabled` 三个 getter 和 `setNavBarPosition``setSplitRatio``setSplitViewEnabled` 三个 setter。
- [ ] **Step 3: 修改设置项数据源为 splitViewProvider**
`general_settings_sections.dart` 中,将 `settings.navBarPositionIndex`/`settings.splitRatio`/`settings.splitViewEnabled` 改为接收外部参数,调用方从 `ref.watch(splitViewProvider)` 读取。修改 `buildGeneralSettingSections` 签名增加 `SplitViewState splitState` 参数。
- [ ] **Step 4: 修改 picker 直接操作 splitViewProvider**
`general_settings_pickers.dart` 中,`showNavBarPositionPicker`/`showSplitRatioPicker` 移除对 `generalSettingsProvider` 的写入,仅操作 `splitViewProvider`
- [ ] **Step 5: 修改 toggle 事件直接操作 splitViewProvider**
`general_settings_page.dart` 中,`_onToggle``split_view_enabled` case 移除对 `notifier.setSplitViewEnabled(value)` 的调用,仅保留 `ref.read(splitViewProvider.notifier).setSplitViewEnabled(value)`
- [ ] **Step 6: 验证编译通过**
Run: `flutter analyze --no-fatal-infos`
Expected: 零 error
### Task 2: 面板内容缓存 — AutomaticKeepAliveClientMixin
**Files:**
- Modify: `lib/core/layout/adaptive_split_view.dart`
- Create: `lib/core/layout/panel_cache.dart`
- [ ] **Step 1: 创建 PanelCacheWrapper 组件**
创建 `panel_cache.dart`,实现一个 `KeepAlivePanelWrapper`,使用 `AutomaticKeepAliveClientMixin` 保持子组件存活:
```dart
class KeepAlivePanelWrapper extends ConsumerStatefulWidget {
const KeepAlivePanelWrapper({required this.child, super.key});
final Widget child;
@override
ConsumerState<KeepAlivePanelWrapper> createState() => _KeepAlivePanelWrapperState();
}
class _KeepAlivePanelWrapperState extends ConsumerState<KeepAlivePanelWrapper>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return widget.child;
}
}
```
- [ ] **Step 2: 在 AdaptiveSplitView 中包裹左右面板**
修改 `adaptive_split_view.dart`,在左侧面板和右侧面板外层包裹 `KeepAlivePanelWrapper`确保切换Tab时面板不被销毁。
- [ ] **Step 3: 验证编译通过**
---
## Phase 2: UX 改进
### Task 3: 右侧面板键盘适配
**Files:**
- Modify: `lib/features/discover/presentation/panels/chat_flow_panel.dart`
- [ ] **Step 1: 在 ChatFlowPanel 中处理键盘遮挡**
`_ChatFlowPanelState.build()` 中,使用 `MediaQuery.viewInsets.bottom` 获取键盘高度,在面板底部添加对应的 padding
```dart
final keyboardHeight = MediaQuery.of(context).viewInsets.bottom;
// 在 Column 底部添加 SizedBox(height: keyboardHeight)
```
- [ ] **Step 2: 验证编译通过**
### Task 4: 分割线双击重置 + 触控区域增大
**Files:**
- Modify: `lib/core/layout/split_divider.dart`
- [ ] **Step 1: 增大触控区域至 24px**
修改外层 Container 的 width 从 17 改为 24内部手柄视觉保持细线2px但触控区域更大。
- [ ] **Step 2: 添加双击重置功能**
`GestureDetector` 外层包裹 `GestureDetector(onDoubleTap: ...)`,双击时调用 `onRatioChanged(0.4)` 重置为默认比例,并添加 `HapticFeedback.mediumImpact()` 触觉反馈。
- [ ] **Step 3: 验证编译通过**
### Task 5: 窄屏横屏居中效果
**Files:**
- Modify: `lib/core/layout/app_shell.dart`
- [ ] **Step 1: 在 _buildNarrowLayout 中添加横屏居中逻辑**
检测 `MediaQuery.of(context).size.width > 600 && MediaQuery.of(context).size.height < 500`(横屏但未达分屏断点),使用 `Center + ConstrainedBox(maxWidth: 600)` 包裹内容区域,两侧留白。
- [ ] **Step 2: 验证编译通过**
---
## Phase 3: 数据与动画
### Task 6: 概览仪表盘接入真实 Provider 数据
**Files:**
- Modify: `lib/core/layout/overview_dashboard.dart`
- [ ] **Step 1: 接入今日推荐数据**
使用 `ref.watch(homeProvider)` 获取推荐句子列表替换硬编码的3条假数据。空状态时显示占位提示。
- [ ] **Step 2: 接入快捷操作数据**
使用 `ref.watch(generalSettingsProvider)` 获取用户常用功能列表替换8项硬编码操作。
- [ ] **Step 3: 接入统计数据**
使用 `ref.watch(userStatsProvider)` 或类似 Provider 获取真实统计值收藏数、阅读天数等替换全0硬编码。
- [ ] **Step 4: 验证编译通过**
### Task 7: 面板切换 Hero 动画
**Files:**
- Modify: `lib/features/home/presentation/home_page.dart`
- Modify: `lib/features/home/presentation/panels/sentence_detail_panel.dart`
- [ ] **Step 1: 在句子卡片添加 Heroine tag**
`home_page.dart``_showDailyDetailSheet` 中,为句子卡片添加 `Heroine(tag: 'sentence_${item.id}')` 包裹。
- [ ] **Step 2: 在详情面板添加对应 Heroine tag**
`sentence_detail_panel.dart` 的句子卡片区域添加 `Heroine(tag: 'sentence_${widget.sentenceId}')` 包裹,确保窄屏 Sheet 和宽屏 Panel 共享相同的 Hero tag。
- [ ] **Step 3: 验证编译通过**
### Task 8: flutter_animate 替代手动 AnimationController
**Files:**
- Modify: `lib/core/layout/adaptive_split_view.dart`
- [ ] **Step 1: 移除手动 AnimationController**
移除 `SingleTickerProviderStateMixin``AnimationController``CurvedAnimation``SlideTransition``FadeTransition`
- [ ] **Step 2: 使用 flutter_animate 重写面板动画**
使用 `AnimateController` + `.slideX()` + `.fadeIn()` 替代,代码更简洁:
```dart
final controller = AnimateController(onAttach: (c) { /* forward/reverse logic */ });
rightPanel.animate(controller: controller).slideX(begin: 1.0, end: 0.0, duration: 350.ms, curve: Curves.easeInOutCubic).fadeIn(duration: 200.ms);
```
- [ ] **Step 3: 验证编译通过**
### Task 9: flutter_staggered_animations 列表交错动画
**Files:**
- Modify: `pubspec.yaml`
- Modify: `lib/core/layout/overview_dashboard.dart`
- [ ] **Step 1: 添加依赖**
`pubspec.yaml` 中添加 `flutter_staggered_animations: ^0.1.3`
- [ ] **Step 2: 在概览仪表盘中使用交错动画**
`_buildQuickActions``_buildStats` 中,使用 `AnimationLimiter` + `AnimationConfiguration.staggeredList` + `SlideAnimation` + `FadeInAnimation` 替代手动 stagger 逻辑。
- [ ] **Step 3: 运行 flutter pub get**
---
## Phase 4: 库集成
### Task 10: photo_view 图片查看器集成
**Files:**
- Modify: `lib/features/home/presentation/panels/sentence_detail_panel.dart`
- [ ] **Step 1: 在句子详情面板中集成 photo_view**
当句子包含图片时,点击图片使用 `PhotoView` 全屏查看,支持缩放/平移。使用 `PhotoView.gallery` 支持多图浏览。
- [ ] **Step 2: 验证编译通过**
### Task 11: dartx 集合扩展方法
**Files:**
- Modify: `pubspec.yaml`
- Modify: `lib/core/providers/split_view_provider.dart`
- Modify: `lib/core/layout/right_panel_registry.dart`
- [ ] **Step 1: 添加依赖**
`pubspec.yaml` 中添加 `dartx: ^1.2.0`
- [ ] **Step 2: 使用 dartx 简化数据处理**
`split_view_provider.dart` 中使用 `.firstOrNull``.sortedBy()` 等扩展方法简化逻辑。在 `right_panel_registry.dart` 中使用 `.getOrNull()` 等安全访问。
- [ ] **Step 3: 运行 flutter pub get**
### Task 12: freezed 不可变数据类
**Files:**
- Modify: `lib/core/providers/split_view_provider.dart`
- Create: `lib/core/providers/split_view_provider.freezed.dart`
- [ ] **Step 1: 为 SplitViewState 添加 freezed 注解**
`SplitViewState` 改为 freezed 类:
```dart
@freezed
class SplitViewState with _$SplitViewState {
const SplitViewState._();
const factory SplitViewState({
@Default(0.4) double splitRatio,
String? rightPanelContent,
Map<String, dynamic>? rightPanelArgs,
@Default(NavBarPosition.left) NavBarPosition navBarPosition,
@Default(true) bool splitViewEnabled,
String? homeRightPanel,
String? discoverRightPanel,
String? profileRightPanel,
@Default(0) int currentTab,
}) = _SplitViewState;
String? get activeRightPanel => switch (currentTab) { ... };
}
```
- [ ] **Step 2: 运行 build_runner 生成代码**
Run: `dart run build_runner build --delete-conflicting-outputs`
- [ ] **Step 3: 修复编译错误**
更新所有引用 `SplitViewState` 的地方,确保 `copyWith` 签名兼容。
- [ ] **Step 4: 验证编译通过**
---
## Phase 5: 高级功能
### Task 13: 文件拖放发送 — desktop_drop
**Files:**
- Modify: `pubspec.yaml`
- Modify: `lib/features/discover/presentation/panels/chat_flow_panel.dart`
- [ ] **Step 1: 添加依赖**
`pubspec.yaml` 中添加 `desktop_drop: ^0.5.0`
- [ ] **Step 2: 在 ChatFlowPanel 中集成拖放区域**
使用 `DropTarget` 包裹聊天面板,监听 `onDragDone` 获取拖入的文件路径,调用聊天发送逻辑。
- [ ] **Step 3: 添加拖放视觉反馈**
`onDragEntered` 时显示高亮边框,`onDragExited` 时移除。
- [ ] **Step 4: 验证编译通过**
### Task 14: 自定义标题栏 — bitsdojo_window
**Files:**
- Modify: `pubspec.yaml`
- Modify: `lib/core/layout/app_shell.dart`
- Modify: `lib/core/layout/adaptive_nav_bar.dart`
- Modify: `lib/main.dart`
- [ ] **Step 1: 添加依赖**
`pubspec.yaml` 中添加 `bitsdojo_window: ^0.1.6`
- [ ] **Step 2: 在 main.dart 中初始化**
`main()` 中添加 `BitsdojoWindow.doWhenWindowReady()` 设置最小窗口尺寸和标题栏高度。
- [ ] **Step 3: 在 AdaptiveNavBar 中融合标题栏**
当导航栏位置为顶部时,将窗口控制按钮(关闭/最小化/最大化)嵌入导航栏右侧,使用 `WindowTitleBarBox` + `MoveWindow` 实现拖拽移动。
- [ ] **Step 4: 在 AppShell 中处理标题栏区域**
宽屏模式下移除系统标题栏,使用 `appWindow.titleBarHeight = 0`,导航栏融合标题栏功能。
- [ ] **Step 5: 验证编译通过(仅桌面端生效,移动端无影响)**
### Task 15: 面板书签功能
**Files:**
- Create: `lib/core/layout/panel_bookmark.dart`
- Modify: `lib/core/providers/split_view_provider.dart`
- [ ] **Step 1: 创建 PanelBookmark 数据模型和 Provider**
```dart
class PanelBookmark {
const PanelBookmark({required this.name, required this.tabIndex, required this.panelId, this.panelArgs});
final String name;
final int tabIndex;
final String panelId;
final Map<String, dynamic>? panelArgs;
}
```
使用 Hive 持久化书签列表。
- [ ] **Step 2: 在 SplitViewNotifier 中添加书签方法**
添加 `addBookmark()``removeBookmark()``applyBookmark()` 方法。
- [ ] **Step 3: 在概览仪表盘中显示书签快捷入口**
在 OverviewDashboard 中添加"已保存的面板组合"区域,点击可一键切换。
- [ ] **Step 4: 验证编译通过**
### Task 16: 跨面板拖拽 — LongPressDraggable
**Files:**
- Modify: `lib/features/home/presentation/home_page.dart`
- Modify: `lib/features/home/presentation/panels/sentence_detail_panel.dart`
- [ ] **Step 1: 在句子卡片添加 LongPressDraggable**
在 HomeSentenceCard 外层包裹 `LongPressDraggable<String>`data 为句子ID。
- [ ] **Step 2: 在右侧面板添加 DragTarget**
在 SentenceDetailPanel 外层包裹 `DragTarget<String>`接收拖入的句子ID自动加载对应详情。
- [ ] **Step 3: 添加拖拽视觉反馈**
拖拽中显示半透明卡片预览,目标区域高亮。
- [ ] **Step 4: 验证编译通过**
### Task 17: 三栏布局 — 超宽屏支持
**Files:**
- Create: `lib/core/layout/triple_column_view.dart`
- Modify: `lib/core/providers/split_view_provider.dart`
- Modify: `lib/core/layout/app_shell.dart`
- [ ] **Step 1: 在 SplitViewState 中添加三栏状态**
添加 `thirdPanelContent``thirdPanelArgs``thirdPanelRatio` 字段和对应 setter。添加 `kTripleColumnBreakpoint = 1400.0` 常量。
- [ ] **Step 2: 创建 TripleColumnView 组件**
实现三栏布局:左侧列表 + 中间详情 + 右侧辅助面板。两条可拖拽分割线。
- [ ] **Step 3: 在 AppShell 中集成三栏检测**
当屏幕宽度 >= 1400px 时,使用 TripleColumnView 替代 AdaptiveSplitView。右侧面板可再分屏。
- [ ] **Step 4: 验证编译通过**
---
## Phase 6: 平台与打磨
### Task 18: rive 交互式动画
**Files:**
- Modify: `pubspec.yaml`
- Modify: `lib/core/layout/adaptive_nav_bar.dart`
- [ ] **Step 1: 添加依赖**
`pubspec.yaml` 中添加 `rive: ^0.13.0`
- [ ] **Step 2: 创建 Rive Tab 动画组件**
创建 `RiveTabIcon` 组件,加载 Rive 动画文件根据选中状态切换动画状态机输入isSelected → bounce/idle
- [ ] **Step 3: 在 AdaptiveNavBar 中可选替换 TabIconSprite**
当用户设置启用 Rive 动画时,使用 `RiveTabIcon` 替代 `TabIconSprite`
- [ ] **Step 4: 验证编译通过**
### Task 19: 跨平台兼容处理
**Files:**
- Modify: `lib/core/layout/app_shell.dart`
- Modify: `lib/core/layout/adaptive_nav_bar.dart`
- Modify: `lib/core/layout/split_divider.dart`
- [ ] **Step 1: 平台条件编译处理**
`desktop_drop``bitsdojo_window` 等桌面端库使用 `kIsWeb` / `Platform.isWindows` 等条件判断,移动端跳过桌面特有逻辑。
- [ ] **Step 2: 触觉反馈平台适配**
`split_divider.dart` 中的 `HapticFeedback` 在桌面端无效,添加平台检测跳过。
- [ ] **Step 3: 键盘快捷键支持**
桌面端添加 `Shortcuts` + `Actions`,支持 Ctrl+1/2/3 切换TabCtrl+W 关闭面板。
- [ ] **Step 4: 验证全平台编译通过**
### Task 20: 智能 AppBar 标题位置适配
**Files:**
- Create: `lib/core/layout/smart_app_bar.dart`
- Modify: `lib/core/layout/app_shell.dart`
- [ ] **Step 1: 创建 SmartAppBar 组件**
自动检测当前是否为宽屏分屏模式:
- 窄屏:标题在 AppBar 中居中
- 宽屏左侧面板:标题在内容区靠左(无 AppBar
- 宽屏右侧面板:标题在面板 Header 靠左
```dart
class SmartAppBar extends ConsumerWidget {
const SmartAppBar({required this.title, this.actions, super.key});
final String title;
final List<Widget>? actions;
@override
Widget build(BuildContext context, WidgetRef ref) {
final isWidescreen = MediaQuery.of(context).size.width >= kSplitViewBreakpoint;
if (isWidescreen) {
return _buildContentHeader(context);
}
return _buildCupertinoAppBar(context);
}
}
```
- [ ] **Step 2: 在 AppShell 中集成 SmartAppBar**
替换各面板中的硬编码 AppBar使用 SmartAppBar 自动适配位置。
- [ ] **Step 3: 验证编译通过**
---
## Phase 7: 最终验收审计
### Task 21: 全量编译验证 + 归档文档更新
- [ ] **Step 1: 运行 flutter analyze**
Run: `flutter analyze --no-fatal-infos`
Expected: 零 error
- [ ] **Step 2: 更新归档文档**
更新 `docs/specs/2026-05-29-widescreen-adaptation-archive.md`,添加新增的视图组件、逻辑事件和动画。
- [ ] **Step 3: 更新 CHANGELOG.md**
添加 v6.5.99 版本记录包含所有22项任务的变更。
- [ ] **Step 4: 逐项审计验收**
对照22项需求逐项验证功能是否正确实现。