chore: 汇总2026-05-30全量更新

### 详细变更:
1.  **文档与配置**:更新AGENTS.md添加命令超时约束,升级Rive依赖至0.14.7并替换平台插件引用
2.  **UI优化**:重构AppInfo页面布局、移除图表冗余配置、锁定部分系统设置项
3.  **功能增强**:
    - 新增工具面板拖拽状态管理与介绍弹窗
    - 新增进度页面编辑/重排/清空用户进度功能
    - 新增摇一摇路由作用域拦截逻辑
4.  **体验优化**:
    - 统一外部链接跳转弹窗,添加文件打开确认逻辑
    - 修复设备卡片IP溢出、Android权限声明问题
    - 后台任务初始化增加协议校验
5.  **代码重构**:拆分工具面板配置、拖拽逻辑与动画参数,优化状态管理代码
6.  **工具脚本**:新增协议文件上传脚本
This commit is contained in:
Developer
2026-05-30 05:29:50 +08:00
parent ca68fe29c7
commit adfa0af825
123 changed files with 17747 additions and 4641 deletions

View File

@@ -0,0 +1,837 @@
# 闲言APP 批量问题修复与功能完善 实施计划
> **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:** 修复25项问题涵盖Android合规、UI/UX修复、功能完善和页面重设计
**Architecture:** Flutter feature-first架构Riverpod状态管理GoRouter路由iOS风格Cupertino组件优先
**Tech Stack:** Flutter 3.x / Dart / Riverpod / GoRouter / sensors_plus / workmanager / permission_handler
---
## 任务分组
本计划按优先级和依赖关系分为6个批次每批次内的任务可并行执行。
---
## 批次1: 合规与关键Bug修复 (高优先级)
### Task 1: AndroidManifest自启动修复
**问题:** APP未向用户明示未经用户同意存在频繁自启动行为。举证: `android.intent.action.BOOT_COMPLETED``androidx.work.impl.background.systemalarm.RescheduleReceiver` 触发
**分析:** 项目AndroidManifest.xml中未直接声明BOOT_COMPLETED权限和Receiver`workmanager`库的`RescheduleReceiver`会在合并后的Manifest中自动注册。项目`BackgroundTaskService`已初始化但未实际注册周期性任务。
**Files:**
- Modify: `android/app/src/main/AndroidManifest.xml`
- Modify: `lib/core/services/background/background_task_service.dart`
- Modify: `lib/core/services/background/background_callback.dart`
- [ ] **Step 1: 在AndroidManifest.xml中移除workmanager的自动注册**
`<application>`标签内添加`tools:node="remove"`来移除workmanager的RescheduleReceiver:
```xml
<!-- 移除workmanager自启动Receiver -->
<receiver
android:name="androidx.work.impl.background.systemalarm.RescheduleReceiver"
tools:node="remove" />
```
同时在`<manifest>`标签添加 `xmlns:tools="http://schemas.android.com/tools"`
- [ ] **Step 2: 修改BackgroundTaskService仅在用户同意后初始化**
`background_task_service.dart`中添加条件检查只有用户同意协议后才初始化workmanager:
```dart
Future<void> init() async {
final agreed = KvStorage.get<bool>('onboarding_completed') ?? false;
if (!agreed) return;
// ... 原有初始化逻辑
}
```
- [ ] **Step 3: 在隐私政策中添加后台任务说明**
在协议数据文件中添加workmanager/后台同步的使用场景说明。
- [ ] **Step 4: 验证编译通过**
Run: `flutter build apk --debug`
Expected: 编译成功合并后的AndroidManifest不再包含RescheduleReceiver
---
### Task 2: 主页句子广场下拉列表动画恢复
**问题:** 原本下拉列表有动画,现在没有了
**分析:** `home_page.dart`使用`AnimatedBuilder`+`SheetAnimationNotifier`实现底部弹窗打开时的缩放+圆角效果。句子广场列表项使用`ListItemAnimation.slideUp`入场动画。需要检查动画是否被禁用或条件判断有误。
**Files:**
- Modify: `lib/features/home/presentation/home_page.dart`
- Check: `lib/core/utils/ui/interaction_animations.dart`
- [ ] **Step 1: 检查home_page.dart中句子列表的动画代码**
搜索句子广场列表构建代码,确认是否使用了`ListItemAnimation``flutter_animate`的入场动画。检查`reduceAnimations`设置是否影响了动画。
- [ ] **Step 2: 恢复下拉刷新后的列表入场动画**
在句子列表的`ListView.builder`为每个item添加`ListItemAnimation``flutter_animate`的fadeIn+slideUp效果:
```dart
itemBuilder: (context, index) {
return ListItemAnimation.wrap(
index: index,
child: SentenceCard(...),
);
}
```
- [ ] **Step 3: 确保动画不受reduceAnimations影响下拉刷新时强制启用**
下拉刷新时即使`reduceAnimations=true`,也应展示入场动画。
- [ ] **Step 4: 验证动画效果**
---
### Task 3: 摇一摇权限写入权限管理页面
**问题:** 摇一摇权限需在权限管理页面显示,且需手动打开/关闭
**Files:**
- Modify: `lib/core/services/auth/permission_service.dart`
- Modify: `lib/features/mine/settings/presentation/privacy/permission_management_page.dart`
- [ ] **Step 1: 在AppPermission枚举中添加shake权限**
```dart
shake(
label: '摇一摇',
permission: null, // 虚拟权限,不需要系统授权
icon: CupertinoIcons.arrow_counterclockwise,
description: '摇晃手机触发特定功能,如换句、刷新等',
color: AppColors.iosPurple,
isRequired: false,
isVirtual: true,
group: PermissionGroup.optional,
usageScenes: ['切换每日推荐句子', '刷新内容', '互动彩蛋'],
),
```
- [ ] **Step 2: 在PermissionService中添加shake权限状态管理**
添加`isShakeEnabled`/`setShakeEnabled`方法状态存储在KvStorage中:
```dart
bool get isShakeEnabled => KvStorage.get<bool>('shake_enabled') ?? true;
Future<void> setShakeEnabled(bool enabled) async {
await KvStorage.set('shake_enabled', enabled);
if (!enabled) {
ShakeDetector.instance.stop();
}
}
```
- [ ] **Step 3: 在权限管理页面添加摇一摇权限卡片**
在虚拟权限列表中添加摇一摇,显示当前启用状态,点击可手动切换。
- [ ] **Step 4: 修改ShakeDetector.start()检查权限**
```dart
void start() {
if (!PermissionService.instance.isShakeEnabled) return;
// ... 原有逻辑
}
```
---
### Task 4: 非主页摇一摇触发修复
**问题:** 不在主页句子卡片的3级4级页面摇一摇也能被触发
**分析:** ShakeDetector使用处理器栈模式`StatefulShellRoute.indexedStack`不调用子页面dispose导致handler可能残留。需确保只有主页的句子卡片页面注册了摇一摇handler。
**Files:**
- Modify: `lib/core/services/device/shake_detector.dart`
- Modify: `lib/features/home/presentation/home_page.dart`
- Check: `lib/features/check/presentation/check_page.dart`
- Check: `lib/features/daily_fortune/presentation/daily_fortune_page.dart`
- [ ] **Step 1: 检查所有使用摇一摇的页面**
搜索所有调用`pushHandler`的页面确认是否在3/4级页面也注册了handler。
- [ ] **Step 2: 限制摇一摇仅在主页Tab生效**
修改方案在ShakeDetector中添加路由层级检查只有`/home`路由的handler才在主页Tab生效。或者更简单`pushHandler`时记录路由深度,只有深度<=1的handler才生效。
```dart
void pushHandler(String route, ShakeCallback callback) {
_handlerStack.removeWhere((e) => e.route == route);
_handlerStack.add(_ShakeHandlerEntry(route, callback));
_updateSubscription();
}
```
- [ ] **Step 3: 在非主页子页面导航时暂停摇一摇**
当用户从主页导航到3/4级页面时ShakeDetector应自动暂停通过GoRouter路由监听:
```dart
// 在AppShell或路由观察者中
@override
void didPush(Route route, Route? previousRoute) {
final currentPath = GoRouterState.of(context).fullPath;
if (currentPath != '/home') {
ShakeDetector.instance.stop();
}
}
```
- [ ] **Step 4: 验证3/4级页面不再触发摇一摇**
---
### Task 22: 引导页未同意协议就读取权限修复
**问题:** 未同意协议就读取传感器列表、网络等权限
**Files:**
- Modify: `lib/main.dart`
- Modify: `lib/features/onboarding/presentation/pages/agreement_page.dart`
- [ ] **Step 1: 在main.dart中延迟初始化需要权限的服务**
将以下服务的初始化移到用户同意协议之后:
- `ConnectivityService.init()` — 网络检测
- `ClipboardMonitorService` — 剪贴板监控
- `BackgroundTaskService.instance.init()` — 后台任务
- `LocalNotificationService.init()` — 本地通知
- `ShakeDetector` — 传感器
创建一个`postAgreementInit()`方法,在用户同意协议后调用。
- [ ] **Step 2: 修改onboarding_provider.dart**
`completeOnboarding()`中调用`postAgreementInit()`:
```dart
Future<void> completeOnboarding() async {
// ... 原有逻辑
await PostAgreementInitializer.init();
}
```
- [ ] **Step 3: 确保引导页期间不触发任何权限请求**
检查agreement_page.dart中的权限说明Tab确保只是展示文本不调用任何权限API。
- [ ] **Step 4: 验证引导页期间无权限访问**
---
## 批次2: 数据与显示修复 (高优先级)
### Task 7: 稍后读句子不显示修复
**问题:** 主页句子广场点击稍后读的句子,在发现页稍后读页面没有显示
**Files:**
- Modify: `lib/features/home/presentation/providers/readlater_page.dart`
- Check: `lib/features/home/presentation/home_sentence_card.dart`
- Check: `lib/features/discover/presentation/pages/home/discover_page.dart`
- [ ] **Step 1: 检查稍后读添加逻辑**
搜索"稍后读"或"readlater"的添加方法,确认点击稍后读按钮后的数据流向。
- [ ] **Step 2: 检查稍后读页面数据加载逻辑**
`readlater_page.dart`中,`_loadData()`方法并行加载Feed API + 聊天消息。检查Feed类型稍后读的加载是否正确。
- [ ] **Step 3: 修复数据同步问题**
确保添加稍后读时写入的数据key与稍后读页面读取的key一致。可能需要检查`ReadlaterService`的存储和读取逻辑。
- [ ] **Step 4: 验证稍后读功能正常**
---
### Task 8: 稍后读图片视频空白+发送弹窗
**问题:** 稍后读页面从其他页面发送的图片/视频看不了,就一个空白图片。发送后要求弹出对话框。
**Files:**
- Modify: `lib/features/home/presentation/providers/readlater_page.dart`
- [ ] **Step 1: 检查图片/视频条目渲染逻辑**
`readlater_page.dart``_buildImageEntry()``_buildVideoEntry()`中,检查缩略图加载是否正确处理本地文件路径。
- [ ] **Step 2: 修复图片/视频显示**
确保图片路径正确解析网络URL vs 本地文件路径),使用`Image.file()``Image.network()`正确加载。
- [ ] **Step 3: 添加发送成功对话框**
在分享到稍后读成功后弹出CupertinoAlertDialog确认:
```dart
showCupertinoDialog(
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text('已添加到稍后读'),
content: Text('内容已成功保存到稍后读列表'),
actions: [
CupertinoDialogAction(
isDefaultAction: true,
child: Text('好的'),
onPressed: () => Navigator.pop(context),
),
],
),
);
```
- [ ] **Step 4: 验证图片/视频显示和弹窗**
---
### Task 9: 闲情逸致Sheet热度排版+外部跳转提示
**问题:** 闲情逸致卡片Sheet的热度范围小、杂乱不堪要求重新排版。底部按钮点击直接跳转外部软件要求跳转前弹窗提示。
**Files:**
- Modify: `lib/features/tool_center/leisure/presentation/widgets/leisure_card_detail_sheet.dart`
- [ ] **Step 1: 重新设计信息网格布局**
`_buildInfoGrid()`从Wrap双列改为更清晰的列表式布局每个信息项一行图标+标签+值使用Divider分隔:
```dart
Widget _buildInfoItem(IconData icon, String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
children: [
Icon(icon, size: 14, color: ext.textHint),
const SizedBox(width: 8),
Text(label, style: caption1),
const Spacer(),
Flexible(child: Text(value, style: caption1, textAlign: TextAlign.end)),
],
),
);
}
```
- [ ] **Step 2: 为所有外部跳转添加确认弹窗**
在地图按钮和外部搜索按钮的点击事件中,添加跳转确认弹窗:
```dart
Future<void> _launchExternal(String url, String appName) async {
final confirmed = await showCupertinoDialog<bool>(
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text('即将离开闲言'),
content: Text('将打开$appName查看更多内容'),
actions: [
CupertinoDialogAction(child: Text('取消'), onPressed: () => Navigator.pop(_, false)),
CupertinoDialogAction(isDefaultAction: true, child: Text('打开'), onPressed: () => Navigator.pop(_, true)),
],
),
);
if (confirmed == true) await launchUrl(Uri.parse(url));
}
```
- [ ] **Step 3: 举一反三 — 检查其他页面的外部跳转**
搜索所有`launchUrl``url_launcher`调用,为每个外部跳转添加确认弹窗。涉及文件:
- leisure_share_sheet.dart
- leisure_card_detail_sheet.dart
- 其他使用url_launcher的页面
- [ ] **Step 4: 验证排版和跳转提示**
---
### Task 10: 我的收藏记录不显示+输入法问题
**问题:** 收藏的记录没显示。输入框动不动弹输入法,要求不点输入框禁止输入法。
**Files:**
- Modify: `lib/features/home/presentation/favorite_page.dart`
- Check: `lib/features/home/providers/favorite_provider.dart`
- [ ] **Step 1: 检查收藏数据加载逻辑**
`favorite_provider.dart`中检查数据加载方法确认API调用和数据解析是否正确。
- [ ] **Step 2: 修复收藏记录显示**
确保收藏列表正确渲染,检查空状态处理和数据绑定。
- [ ] **Step 3: 修复输入法自动弹出问题**
在搜索框外层添加`GestureDetector`拦截触摸,搜索框默认`enabled: false`,点击时才启用:
```dart
GestureDetector(
onTapDown: (_) => FocusScope.of(context).requestFocus(_searchFocusNode),
child: CupertinoTextField(
focusNode: _searchFocusNode,
enabled: false, // 默认禁用
...
),
)
```
或使用`KeyboardDismissOnTap`包装整个页面,页面进入时不自动聚焦搜索框。
- [ ] **Step 4: 验证收藏显示和输入法控制**
---
### Task 11: 我的设备页面时间和IP被遮住
**问题:** 最后活跃时间后面的几点几分看不到IP归属地后面的信息也被遮住了
**Files:**
- Modify: `lib/features/mine/user_center/presentation/devices/device_detail_sheet.dart`
- Modify: `lib/features/mine/user_center/presentation/devices/device_card.dart`
- [ ] **Step 1: 修复DeviceInfoRow的文本溢出**
`device_detail_sheet.dart``DeviceInfoRow`将value的`Flexible`改为`Expanded`并确保label使用固定宽度:
```dart
Row(
children: [
Icon(icon, size: 14, color: ext.textHint),
const SizedBox(width: 8),
SizedBox(
width: 72, // 固定label宽度
child: Text(label, style: caption1),
),
Expanded( // value占满剩余空间
child: Text(value, style: caption1, textAlign: TextAlign.end, maxLines: 2, overflow: TextOverflow.ellipsis),
),
],
)
```
- [ ] **Step 2: 修复device_card.dart中IP显示溢出**
确保IP地址文本有足够空间可能需要调整Row布局或减小字体。
- [ ] **Step 3: 验证长文本不再被遮住**
---
### Task 20: 主页精灵气泡秒消失修复
**问题:** 主页顶部的精灵角色点击弹出的气泡秒消失要求下一句不触发最少显示3秒
**Files:**
- Modify: `lib/features/home/presentation/home_page.dart`
- Check: `lib/shared/widgets/animation/appbar_character_sprite.dart` 或相关精灵组件
- [ ] **Step 1: 找到精灵气泡的显示逻辑**
搜索气泡/精灵相关的显示和隐藏代码。
- [ ] **Step 2: 添加最小显示时间**
在气泡显示后设置3秒计时器计时器未结束时不得隐藏或替换:
```dart
Timer? _bubbleTimer;
bool _bubbleVisible = false;
void _showBubble(String text) {
if (_bubbleTimer?.isActive ?? false) return; // 3秒内不触发新气泡
setState(() {
_bubbleText = text;
_bubbleVisible = true;
});
_bubbleTimer = Timer(const Duration(seconds: 3), () {
if (mounted) setState(() => _bubbleVisible = false);
});
}
```
- [ ] **Step 3: 验证气泡至少显示3秒**
---
## 批次3: 页面重设计与功能完善 (中优先级)
### Task 5-6: 工具中心设置页面+拖拽+介绍
**问题:** 发现页工具中心需增加设置页面、支持长按拖拽删除、长按弹出工具介绍
**Files:**
- Create: `lib/features/discover/presentation/pages/tool_center_settings_page.dart`
- Modify: `lib/features/discover/presentation/pages/home/discover_page.dart`
- Modify: `lib/features/discover/providers/tool_center_provider.dart`
- Modify: `lib/core/router/app_routes.dart` + 对应路由文件
- [ ] **Step 1: 创建工具中心设置页面**
包含: 使用统计、已删除工具管理、工具排序、搜索恢复已删除工具
- [ ] **Step 2: 在发现页底部添加设置按钮**
点击跳转工具中心设置页面
- [ ] **Step 3: 实现长按拖拽功能**
使用`ReorderableGridView`或自定义`Draggable`实现工具图标拖拽,底部显示垃圾桶区域:
```dart
Draggable<ToolItem>(
data: tool,
feedback: Material(child: ToolIcon(tool, scale: 1.1)),
childWhenDragging: Opacity(opacity: 0.3, child: ToolIcon(tool)),
child: ToolIcon(tool),
)
```
- [ ] **Step 4: 实现删除和恢复逻辑**
删除工具: 从工具列表移除,标记为`isDeleted`
恢复工具: 在设置页面搜索找到已删除工具,点击恢复
- [ ] **Step 5: 添加长按弹出工具介绍**
对重要工具添加介绍弹窗:
```dart
onLongPress: () => _showToolIntro(context, tool),
```
- [ ] **Step 6: 验证拖拽、删除、恢复功能**
---
### Task 12: 内容纠错页面增强
**问题:** 增加"其他"内容类型选择、内容ID增加icon提示、纠错描述增加字数限制提示、纠错记录增加本地/服务端标识
**Files:**
- Modify: `lib/features/correction/presentation/correction_page.dart`
- Modify: `lib/features/correction/providers/correction_provider.dart`
- [ ] **Step 1: 添加"其他"内容类型**
在内容类型列表中添加`other`选项
- [ ] **Step 2: 内容ID右侧添加info icon**
点击显示提示: "若无ID请填写0"
- [ ] **Step 3: 纠错描述增加最少字数提示**
添加提示文字: "请至少描述10个字",并在提交时校验
- [ ] **Step 4: 纠错记录增加本地/服务端标识**
在记录列表中每条记录添加来源标签(本地/服务端)
- [ ] **Step 5: 验证纠错功能**
---
### Task 13: 日签卡片页面重新设计
**问题:** 布局混乱不堪,要求重新设计,支持动态主题和动态样式
**Files:**
- Modify: `lib/features/daily_card/presentation/daily_card_page.dart`
- Modify: `lib/features/daily_card/presentation/widgets/card_renderer.dart`
- [ ] **Step 1: 分析当前布局问题**
- [ ] **Step 2: 重新设计日签卡片页面布局**
采用iOS 26风格: 顶部大卡片预览 + 底部样式/内容选择器 + 操作按钮栏
- [ ] **Step 3: 确保动态主题支持**
使用`AppTheme.ext(context)`获取主题色,所有颜色从主题获取
- [ ] **Step 4: 验证日签卡片页面**
---
### Task 15: 灵感页面重新设计
**问题:** 杂乱不堪没有appbar要求重写重新设计
**Files:**
- Modify: `lib/features/discover/presentation/pages/home/inspiration_page.dart`
- [ ] **Step 1: 添加CupertinoNavigationBar**
- [ ] **Step 2: 重新设计页面布局**
分类标签+内容卡片+视图切换iOS 26风格
- [ ] **Step 3: 确保动态主题支持**
- [ ] **Step 4: 验证灵感页面**
---
### Task 16: 进度页面完善
**问题:** 进度设置有空壳UI和空壳功能要求完善显示样式、数据管理、分享
**Files:**
- Modify: `lib/features/progress/presentation/progress_page.dart`
- [ ] **Step 1: 完善进度显示样式**
添加更多可视化: 环形进度、进度条、倒计时网格
- [ ] **Step 2: 完善数据管理**
添加编辑/删除进度项功能
- [ ] **Step 3: 完善分享功能**
生成进度卡片图片并分享
- [ ] **Step 4: 验证进度页面**
---
## 批次4: 设置与权限修复 (中优先级)
### Task 14: 壁纸模板下载/编辑按钮提示修改
**问题:** 壁纸下载和编辑按钮的toast提示改成"暂无版权相关的描述"
**Files:**
- Modify: `lib/features/template/presentation/template_gallery_page.dart`
- Check: 壁纸预览Sheet相关文件
- [ ] **Step 1: 找到下载和编辑按钮的toast提示代码**
- [ ] **Step 2: 修改提示文字为版权相关描述**
```dart
showToast('暂无版权授权,无法下载/编辑此壁纸');
```
- [ ] **Step 3: 验证提示文字**
---
### Task 17: 面对面快传跳转文件传输助手
**问题:** 点击面对面快传要求跳转文件传输助手页面
**Files:**
- Modify: `lib/features/mine/profile/presentation/profile_page.dart`
- [ ] **Step 1: 修改_quickActions中面对面快传的回调**
`FeatureFlag.quickTransfer.unsupportedMessage`改为导航到文件传输页面:
```dart
CupertinoActionSheetAction(
onPressed: () {
Navigator.pop(context);
context.go(AppRoutes.fileTransfer);
},
child: Text('面对面快传'),
),
```
- [ ] **Step 2: 验证跳转**
---
### Task 18: 预测返回和长按预览默认关闭锁定
**问题:** 预测返回按钮默认关闭锁定不可打开,长按预览同样
**Files:**
- Modify: `lib/features/mine/settings/presentation/general/general_settings_sections.dart`
- Modify: `lib/features/mine/settings/providers/general_settings_provider.dart`
- [ ] **Step 1: 将预测返回和长按预览设置为锁定状态**
在设置项中添加`isLocked: true`属性:
```dart
SettingItem(
id: 'predictive_back',
...
isLocked: true, // 锁定不可修改
lockedReason: '该功能暂不可用',
),
```
- [ ] **Step 2: 在设置页面UI中处理锁定状态**
锁定项显示锁定icon点击弹出提示"该功能暂不可用"
- [ ] **Step 3: 确保默认值为false**
- [ ] **Step 4: 验证锁定状态**
---
### Task 19: 主题壁纸/背景功能完善
**问题:** 壁纸/背景点击无反应,空壳功能
**Files:**
- Modify: `lib/features/mine/settings/presentation/theme/theme_sections_style.dart`
- [ ] **Step 1: 完善`_selectFromGallery`方法**
使用`image_picker`实现从相册选择壁纸:
```dart
Future<void> _selectFromGallery(BuildContext context, WidgetRef ref) async {
final hasPermission = await PermissionService.instance.requestPhotos();
if (!hasPermission) return;
final picker = ImagePicker();
final image = await picker.pickImage(source: ImageSource.gallery);
if (image != null) {
ref.read(themeSettingsProvider.notifier).setWallpaper(image.path, 'gallery');
}
}
```
- [ ] **Step 2: 完善预设壁纸选择**
确保预设壁纸资源文件存在,或使用渐变色代替
- [ ] **Step 3: 验证壁纸设置功能**
---
### Task 21: 拼音注音icon样式和对话框
**问题:** 拼音注音右下角icon样式改成其他的点击弹出对话框说明汉语拼音等
**Files:**
- Modify: `lib/features/mine/settings/presentation/plugin/plugin_pinyin_card.dart`
- [ ] **Step 1: 修改右下角icon样式**
从当前样式改为`CupertinoIcons.info_circle`或自定义样式
- [ ] **Step 2: 添加点击弹出对话框**
```dart
onTap: () => _showPinyinIntro(context),
void _showPinyinIntro(BuildContext context) {
showCupertinoDialog(
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text('拼音注音'),
content: Text('基于汉语拼音方案,为汉字自动标注带声调的拼音。\n\n'
'• 支持逐字注音\n'
'• 支持带调标注\n'
'• 支持诗词全文注音\n\n'
'数据来源:《现代汉语词典》标准拼音'),
actions: [
CupertinoDialogAction(isDefaultAction: true, child: Text('了解了'), onPressed: () => Navigator.pop(_)),
],
),
);
}
```
- [ ] **Step 3: 验证icon和对话框**
---
### Task 23: 分析存储权限必要性
**问题:** 分析READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限是否有必要保留
**分析:**
- `READ_EXTERNAL_STORAGE` (maxSdkVersion=32): Android 12及以下需要读取图片/视频。Android 13+使用READ_MEDIA_IMAGES/READ_MEDIA_VIDEO替代。**需要保留**但maxSdkVersion=32已正确限制。
- `WRITE_EXTERNAL_STORAGE` (maxSdkVersion=29): Android 10及以下需要写入外部存储。Android 10+使用Scoped Storage不需要此权限。**可以移除**因为maxSdkVersion=29意味着只在Android 9及以下生效而项目minSdkVersion可能已高于此。
- [ ] **Step 1: 确认项目minSdkVersion**
- [ ] **Step 2: 如果minSdkVersion >= 30移除WRITE_EXTERNAL_STORAGE**
- [ ] **Step 3: 保留READ_EXTERNAL_STORAGE(maxSdk=32)和READ_MEDIA_*权限**
- [ ] **Step 4: 更新权限说明文档**
---
## 批次5: 页面细节优化 (中低优先级)
### Task 13+15+16 的具体实现已在批次3中描述
---
## 批次6: 审计与总结
### Task 24: 审计验收
- [ ] **Step 1: 编译检查**`flutter analyze`
- [ ] **Step 2: Android编译测试**`flutter build apk --debug`
- [ ] **Step 3: 逐项验证25个问题的修复**
- [ ] **Step 4: 更新CHANGELOG.md**
### Task 25: 项目不足分析和建议
- [ ] **Step 1: 分析项目架构不足**
- [ ] **Step 2: 提出可扩展的三方库和交互功能建议**
- [ ] **Step 3: 输出分析报告**
---
## 文件变更总览
| 文件 | 变更类型 | 涉及任务 |
|------|---------|---------|
| `android/app/src/main/AndroidManifest.xml` | 修改 | Task 1, 23 |
| `lib/main.dart` | 修改 | Task 22 |
| `lib/core/services/device/shake_detector.dart` | 修改 | Task 3, 4 |
| `lib/core/services/auth/permission_service.dart` | 修改 | Task 3 |
| `lib/core/services/background/background_task_service.dart` | 修改 | Task 1 |
| `lib/features/home/presentation/home_page.dart` | 修改 | Task 2, 4, 20 |
| `lib/features/mine/settings/presentation/privacy/permission_management_page.dart` | 修改 | Task 3 |
| `lib/features/discover/presentation/pages/home/discover_page.dart` | 修改 | Task 5-6 |
| `lib/features/discover/providers/tool_center_provider.dart` | 修改 | Task 5-6 |
| `lib/features/discover/presentation/pages/home/inspiration_page.dart` | 修改 | Task 15 |
| `lib/features/home/presentation/providers/readlater_page.dart` | 修改 | Task 7, 8 |
| `lib/features/tool_center/leisure/presentation/widgets/leisure_card_detail_sheet.dart` | 修改 | Task 9 |
| `lib/features/home/presentation/favorite_page.dart` | 修改 | Task 10 |
| `lib/features/mine/user_center/presentation/devices/device_detail_sheet.dart` | 修改 | Task 11 |
| `lib/features/mine/user_center/presentation/devices/device_card.dart` | 修改 | Task 11 |
| `lib/features/correction/presentation/correction_page.dart` | 修改 | Task 12 |
| `lib/features/daily_card/presentation/daily_card_page.dart` | 修改 | Task 13 |
| `lib/features/template/presentation/template_gallery_page.dart` | 修改 | Task 14 |
| `lib/features/progress/presentation/progress_page.dart` | 修改 | Task 16 |
| `lib/features/mine/profile/presentation/profile_page.dart` | 修改 | Task 17 |
| `lib/features/mine/settings/presentation/general/general_settings_sections.dart` | 修改 | Task 18 |
| `lib/features/mine/settings/providers/general_settings_provider.dart` | 修改 | Task 18 |
| `lib/features/mine/settings/presentation/theme/theme_sections_style.dart` | 修改 | Task 19 |
| `lib/features/mine/settings/presentation/plugin/plugin_pinyin_card.dart` | 修改 | Task 21 |
| `lib/features/onboarding/presentation/pages/agreement_page.dart` | 修改 | Task 22 |
| `lib/features/discover/presentation/pages/tool_center_settings_page.dart` | 新建 | Task 5-6 |
| `CHANGELOG.md` | 修改 | Task 24 |

View File

@@ -0,0 +1,171 @@
# 工具面板15项改进实施计划
> **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:** 实施工具面板15项架构重构与功能扩展
**Architecture:** 分4个阶段实施Phase 1 架构基础 → Phase 2 代码质量 → Phase 3 UX打磨 → Phase 4 新功能。每阶段完成后运行 flutter analyze 验证。
**Tech Stack:** Flutter/Dart, Riverpod, share_plus, Cupertino风格
---
## Phase 1: 架构基础5项
### Task 1: 动画配置类抽取 (#5)
**Files:**
- Create: `lib/features/discover/presentation/widgets/tool/tool_panel_config.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel.dart`
- [ ] 创建 ToolPanelAnimConfig 配置类,抽取所有硬编码动画参数
- [ ] 在 _ToolPanelAnimatedContentState 中使用配置类替换硬编码值
### Task 2: ToolPanelOverlayRoute 公开化 (#15)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel.dart`
- [ ]`_ToolPanelOverlayRoute` 重命名为 `ToolPanelOverlayRoute` 并公开
- [ ] 确保外部可测试和复用
### Task 3: DragState 封装 (#12)
**Files:**
- Create: `lib/features/discover/presentation/widgets/tool/tool_panel_drag_state.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_sections.dart`
- [ ] 创建 DragState 类封装拖拽状态管理
- [ ] 替换4个抽象方法为单一 DragState 对象
- [ ] 更新 SectionsMixin 使用 DragState
### Task 4: 导航配置数据驱动 (#8)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_navigator.dart`
- Modify: `lib/features/discover/models/tool_item.dart`
- [ ] 在 ToolItem 模型中添加 navConfig 字段
- [ ] 创建 ToolNavConfig 数据类替代 switch-case
- [ ] 在 defaultTools 中为每个工具配置 navConfig
- [ ] ToolPanelNavHelper 改为从 navConfig 读取
### Task 5: Mixin链简化为组合模式 (#9)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_navigator.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_actions.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_sections.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel.dart`
- [ ] 将 NavigatorMixin 改为独立 ToolPanelNavigation 类(持有 ref/context
- [ ] 将 ActionsMixin 改为独立 ToolPanelActions 类
- [ ] 将 SectionsMixin 改为独立 ToolPanelSections 类
- [ ] State 中通过组合持有这些类实例
---
## Phase 2: 代码质量3项
### Task 6: GridView 重复代码抽取 (#10)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_sections.dart`
- [ ] 抽取 buildToolGrid 公共方法
- [ ] buildCategorizedTools 和 buildSearchResults 复用
### Task 7: ToolGridItem 回调简化 (#11)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_sections.dart`
- [ ] 抽取 buildGridItemCallbacks 方法
- [ ] childWhenDragging 和 child 共用回调
### Task 8: 错误边界 — 工具跳转失败用户提示 (#13)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_navigator.dart`
- [ ] navigateToTool 添加 try-catch + AppToast 错误提示
- [ ] 离线工具点击时显示状态提示
---
## Phase 3: UX打磨3项
### Task 9: 分类吸顶实现 (#4)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_sections.dart`
- [ ] 将 Column+SliverToBoxAdapter 改为纯 Sliver 布局
- [ ] 实现 CategoryPinnedHeaderDelegate (SliverPersistentHeaderDelegate)
- [ ] 分类标题滚动时吸顶
### Task 10: 弹性回弹动画 (#14)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel.dart`
- [ ] 使用 SpringSimulation 替代线性 dismissOffset 归零
- [ ] 添加弹性回弹效果
### Task 11: 无障碍 Semantics 支持 (#6)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_sections.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_widgets.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_grid_item.dart`
- [ ] 工具网格项添加 Semanticslabel/hint
- [ ] 操作菜单项添加 Semantics
- [ ] 搜索结果空状态添加 Semantics
- [ ] 拖拽反馈添加 Semantics
---
## Phase 4: 新功能4项
### Task 12: 工具收藏/自定义排序 (#1)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_sections.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel.dart`
- [ ] 新增收藏工具专区favoritedTools
- [ ] 排序选择器(使用频率/名称/最近使用/评分)
- [ ] 排序状态持久化
### Task 13: 工具使用统计面板 (#2)
**Files:**
- Create: `lib/features/discover/presentation/widgets/tool/tool_stats_sheet.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_actions.dart`
- [ ] 创建 ToolStatsSheet 底部弹窗
- [ ] 显示使用频率柱状图 + 时长统计 + 最近使用记录
- [ ] 长按菜单"📊 使用统计"接入
### Task 14: 工具分享功能 (#3)
**Files:**
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_navigator.dart`
- [ ] 接入项目已有 ShareSheet 系统
- [ ] 构建 ToolItem → ShareData 转换
- [ ] 替换 Toast 提示为真实分享
### Task 15: 工具版本管理 (#7)
**Files:**
- Modify: `lib/features/discover/models/tool_item.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_grid_item.dart`
- Modify: `lib/features/discover/presentation/widgets/tool/tool_panel_sections.dart`
- [ ] ToolItem 添加 version/changelog/updatedAt 字段
- [ ] isNew 角标逻辑优化(基于版本更新时间)
- [ ] 工具详情弹窗显示版本号和更新日志