Skip to content
Open
15 changes: 8 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
| `AI_ANALYSIS.md` | 模块分析文档:功能、文件结构、数据流、关键类、修改建议 |
| 路由注册 | 在 `lib/router/app_route_table.dart` 的 `_modules` 中注册 |
| 模块元数据 | `ModuleEntry` 必须填写 `category`、`difficulty`、`concepts`、`estimatedMinutes`、`status`、`subtitle` |
| 教学页面 | 至少 1 个页面使用 `lib/shared/learning/` 中的教学模板组件 |
| 教学页面 | 至少 1 个页面使用外部 `flutter_study_learning` 包中的教学模板组件(`LearningScaffold` 等) |

## 修改模块规则

Expand Down Expand Up @@ -57,7 +57,7 @@ dart run flutterguard_cli:flutterguard scan --path . --fail-on high

1. 扫描 `lib/` 下所有模块目录,检查是否都在 `_modules` 中注册
2. 检查每个模块是否有 `AI_ANALYSIS.md`
3. 检查重点模块是否使用教学模板(`lib/shared/learning/`
3. 检查重点模块是否使用教学模板(`flutter_study_learning` 包
4. 检查 `ModuleEntry` 元数据是否完整(所有必填字段)
5. 标记低质量模块的 `status` 为 `ModuleStatus.pending`
6. 检查 `flutter analyze` 和 `dart format` 是否通过
Expand All @@ -73,11 +73,12 @@ git config core.hooksPath .githooks
## 模块分类枚举

```dart
ModuleCategory.basic // 基础机制
ModuleCategory.async // 异步并发
ModuleCategory.state // 状态管理
ModuleCategory.ui // UI 与动效
ModuleCategory.platform // 网络与平台
ModuleCategory.basic // 基础机制
ModuleCategory.async // 异步并发
ModuleCategory.state // 状态管理
ModuleCategory.ui // UI 与动效
ModuleCategory.popupTable // 弹窗与列表
ModuleCategory.platform // 网络与平台
```

## 难度等级枚举
Expand Down
23 changes: 11 additions & 12 deletions AI_PROJECT_CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,19 @@ lib/
│ ├── module_entry.dart
│ └── module_category.dart
├── shared/ # 共享能力
│ ├── learning/
│ │ └── learning_scaffold.dart # 教学模板组件
│ ├── platform/ # 平台通道与系统能力封装
│ ├── widgets/
│ ├── utils/
│ └── theme/
└── modules/ # 学习模块分区
├── basic/ # 基础机制
├── async/ # 异步并发
├── state/ # 状态管理
├── ui/ # UI 与动效
└── platform/ # 网络与平台
│ ├── multi_window/ # 多窗口能力封装
│ └── platform/ # 平台通道与系统能力封装
├── modules/ # 学习模块分区
│ ├── basic/ # 基础机制
│ ├── async/ # 异步并发
│ ├── state/ # 状态管理
│ ├── ui/ # UI 与动效
│ ├── popup_table/ # 弹窗与列表
│ └── platform/ # 网络与平台
```

教学模板组件由外部包 `flutter_study_learning` 提供(`LearningScaffold`、`LearningObjectives`、`ConceptChips`、`CodeSnippetCard`、`CommonPitfalls`、`ExerciseCard`、`StateLogView`)。

## 模块内部结构(推荐)

```
Expand Down
5 changes: 3 additions & 2 deletions REFACTOR_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@ abstract class FilePickerService {

### 2.2 shared 能力治理

- [ ] 为 `lib/shared/learning/` 补充/更新 `AI_ANALYSIS.md`
- [ ] 为 `lib/shared/platform/` 建立边界: 只放跨平台/平台通道能力,不放具体业务解析逻辑
- [x] 教学模板组件已从 `lib/shared/learning/` 抽出为外部 `flutter_study_learning` 包
- [x] `file_picker` 已从 `lib/shared/platform/` 抽出为外部 `file_picker_bridge` 包
- [ ] 为 `lib/shared/platform/` 补充平台能力说明 `AI_ANALYSIS.md`
- [ ] 共享能力必须提供业务无关接口,模块只能传入业务参数
- [ ] 共享能力新增后必须至少被 1 个模块接入验证
- [ ] 若 shared 能力 3 个月内仍只有 1 个模块使用,保留在 shared,但不升级为独立插件
Expand Down
26 changes: 14 additions & 12 deletions lib/app/router/app_route_table.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ import '../../modules/async/stream_subscription/module_entry.dart';
import '../../modules/async/stream_subscription/module_routes.dart';

import '../../modules/state/flutter_ioc/module_entry.dart';
import '../../modules/state/status_management/app/app_routes.dart';
import '../../modules/state/status_management/module_entry.dart';
import '../../modules/state/status_management/module_routes.dart';

import '../../modules/state/status_management/module_entry.dart';
import '../../modules/ui/adsorption_line/module_entry.dart';
import '../../modules/ui/download_animation/module_entry.dart';
import '../../modules/ui/download_animation/module_routes.dart';
Expand All @@ -38,14 +38,16 @@ import '../../modules/platform/usb_detector/module_entry.dart';

// ==================== 状态管理子路由(模块内部已定义映射) ====================

List<GoRoute> _buildStatusManageRoutes() => AppRoutes.routes.entries
.map(
(entry) => GoRoute(
path: entry.key.startsWith('/') ? entry.key.substring(1) : entry.key,
builder: (context, state) => entry.value(context),
),
)
.toList();
List<GoRoute> _buildStatusManageRoutes() =>
StatusManagementRoutes.routes.entries
.map(
(entry) => GoRoute(
path:
entry.key.startsWith('/') ? entry.key.substring(1) : entry.key,
builder: (context, state) => entry.value(context),
),
)
.toList();

// ==================== 模块注册 ====================

Expand Down Expand Up @@ -217,7 +219,7 @@ final List<ModuleEntry> _modules = [
difficulty: Difficulty.beginner,
concepts: ['TableView', '固定表头', '二维滚动'],
estimatedMinutes: 15,
status: ModuleStatus.pending,
status: ModuleStatus.ready,
builder: (context) => const ScrollTableEntry(),
),
ModuleEntry(
Expand Down Expand Up @@ -259,7 +261,7 @@ final List<ModuleEntry> _modules = [
difficulty: Difficulty.intermediate,
concepts: ['usb_serial', 'device_info_plus', 'Stream 广播', '设备扫描'],
estimatedMinutes: 25,
status: ModuleStatus.pending,
status: ModuleStatus.ready,
builder: (context) => const UsbDetectorEntry(),
),
];
Expand Down
25 changes: 21 additions & 4 deletions lib/modules/async/isolate_basic/AI_ANALYSIS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,28 @@
"path": "lib/modules/async/isolate_basic",
"status": "active"
},
"entrypoints": ["module_entry.dart","module_routes.dart","module_root.dart","pages","widgets","state"],
"owns": ["module_entry","module_ui","module_state","module_docs"],
"depends": ["module_registry","go_router"],
"entrypoints": ["module_entry.dart","module_root.dart"],
"owns": ["module_entry","module_ui"],
"depends": ["flutter_study_learning","module_registry","go_router"],
"mutates": ["AI_ANALYSIS.md","**/*.dart"],
"files": ["module_entry.dart","module_root.dart","module_routes.dart","with_isolate_page.dart","without_isolate_page.dart"],
"files": [
"module_entry.dart",
"module_root.dart",
"module_routes.dart",
"with_isolate_page.dart",
"without_isolate_page.dart"
],
"teaching_components": {
"page": "module_root.dart",
"components": [
"LearningScaffold",
"LearningObjectives",
"ConceptChips",
"CodeSnippetCard",
"CommonPitfalls",
"ExerciseCard"
]
},
"contracts": {
"no_natural_language": true,
"doc_consumer": "vibecoding",
Expand Down
166 changes: 99 additions & 67 deletions lib/modules/async/isolate_basic/module_root.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables
import 'package:flutter/material.dart';
import 'package:flutter_study_learning/flutter_study_learning.dart';
import 'package:go_router/go_router.dart';

class HomePage extends StatelessWidget {
Expand All @@ -8,79 +10,109 @@ class HomePage extends StatelessWidget {

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Isolate 对比演示'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Isolate 测试与对比',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
const Text(
'本演示通过大量计算来对比使用和不使用 Isolate 的差异',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16),
),
const SizedBox(height: 10),
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.amber.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.amber),
return LearningScaffold(
title: 'Isolate 并发对比',
interactiveDemo: SizedBox(
height: 350,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'本演示通过大量计算来对比使用和不使用 Isolate 的差异',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16),
),
child: const Column(
children: [
Text(
'测试说明:',
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text(
'1. 两个页面执行相同的计算任务(查找素数)\n'
'2. 计算过程中观察动画流畅度\n'
'3. 尝试点击"点击测试响应"按钮\n'
'4. 尝试在蓝色区域滑动\n'
'5. 对比两者UI响应差异',
style: TextStyle(fontSize: 14),
),
],
const SizedBox(height: 10),
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.amber.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.amber),
),
child: const Column(
children: [
Text('测试说明:',
style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text(
'1. 两个页面执行相同的计算任务(查找素数)\n'
'2. 计算过程中观察动画流畅度\n'
'3. 尝试点击"点击测试响应"按钮\n'
'4. 尝试在蓝色区域滑动\n'
'5. 对比两者UI响应差异',
style: TextStyle(fontSize: 14),
),
],
),
),
),
const SizedBox(height: 40),
ElevatedButton(
style: ElevatedButton.styleFrom(
padding:
const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
backgroundColor: Colors.red[100],
const SizedBox(height: 40),
ElevatedButton(
style: ElevatedButton.styleFrom(
padding:
const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
backgroundColor: Colors.red[100],
),
onPressed: () {
context.push('$_baseRoute/without-isolate');
},
child: const Text('不使用 Isolate (卡顿示例)'),
),
onPressed: () {
context.push('$_baseRoute/without-isolate');
},
child: const Text('不使用 Isolate (卡顿示例)'),
),
const SizedBox(height: 20),
ElevatedButton(
style: ElevatedButton.styleFrom(
padding:
const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
backgroundColor: Colors.green[100],
const SizedBox(height: 20),
ElevatedButton(
style: ElevatedButton.styleFrom(
padding:
const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
backgroundColor: Colors.green[100],
),
onPressed: () {
context.push('$_baseRoute/with-isolate');
},
child: const Text('使用 Isolate (流畅示例)'),
),
onPressed: () {
context.push('$_baseRoute/with-isolate');
},
child: const Text('使用 Isolate (流畅示例)'),
),
],
],
),
),
),
sections: [
LearningObjectives(objectives: [
'理解 Isolate 与主线程的内存隔离机制',
'掌握 Isolate.spawn + SendPort/ReceivePort 通信模式',
'对比有/无 Isolate 时 UI 流畅度差异',
]),
ConceptChips(concepts: [
'Isolate',
'SendPort',
'ReceivePort',
'并发',
'UI 流畅度',
'耗时计算',
]),
CodeSnippetCard(
title: 'Isolate 基础用法',
code: 'final receivePort = ReceivePort();\n'
'await Isolate.spawn(\n'
' computeTask,\n'
' receivePort.sendPort,\n'
');\n'
'receivePort.listen((result) {\n'
' // 接收计算结果\n'
'});',
explanation: 'Isolate.spawn 在新 Isolate 中执行函数,通过 Port 通信。',
),
CommonPitfalls(pitfalls: [
'Isolate 间不能共享变量 — 必须通过消息传递,无法直接访问主线程数据',
'ReceivePort 需要及时关闭 — 不关闭会导致内存泄漏',
'大量小消息的性能开销 — 频繁跨 Isolate 通信可能得不偿失',
]),
ExerciseCard(
task:
'修改 without_isolate_page.dart,尝试使用 compute 工具函数替换 Isolate.spawn,对比两种 API 的差异。',
hint: 'Flutter 提供了 compute() 函数作为 Isolate 的简化封装,适合一次性耗时计算。',
),
],
);
}
}
Loading