code-abyss 1.6.16 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/skills/SKILL.md +24 -16
- package/skills/domains/ai/SKILL.md +2 -2
- package/skills/domains/ai/prompt-and-eval.md +279 -0
- package/skills/domains/architecture/SKILL.md +2 -3
- package/skills/domains/architecture/security-arch.md +87 -0
- package/skills/domains/data-engineering/SKILL.md +188 -26
- package/skills/domains/development/SKILL.md +1 -4
- package/skills/domains/devops/SKILL.md +3 -5
- package/skills/domains/devops/performance.md +63 -0
- package/skills/domains/devops/testing.md +97 -0
- package/skills/domains/frontend-design/SKILL.md +12 -3
- package/skills/domains/frontend-design/claymorphism/SKILL.md +117 -0
- package/skills/domains/frontend-design/claymorphism/references/tokens.css +52 -0
- package/skills/domains/frontend-design/engineering.md +287 -0
- package/skills/domains/frontend-design/glassmorphism/SKILL.md +138 -0
- package/skills/domains/frontend-design/glassmorphism/references/tokens.css +32 -0
- package/skills/domains/frontend-design/liquid-glass/SKILL.md +135 -0
- package/skills/domains/frontend-design/liquid-glass/references/tokens.css +81 -0
- package/skills/domains/frontend-design/neubrutalism/SKILL.md +141 -0
- package/skills/domains/frontend-design/neubrutalism/references/tokens.css +44 -0
- package/skills/domains/infrastructure/SKILL.md +174 -34
- package/skills/domains/mobile/SKILL.md +211 -21
- package/skills/domains/orchestration/SKILL.md +1 -0
- package/skills/domains/security/SKILL.md +4 -6
- package/skills/domains/security/blue-team.md +57 -0
- package/skills/domains/security/red-team.md +54 -0
- package/skills/domains/security/threat-intel.md +50 -0
- package/skills/orchestration/multi-agent/SKILL.md +195 -46
- package/skills/run_skill.js +134 -0
- package/skills/tools/gen-docs/SKILL.md +6 -4
- package/skills/tools/gen-docs/scripts/doc_generator.js +349 -0
- package/skills/tools/verify-change/SKILL.md +8 -6
- package/skills/tools/verify-change/scripts/change_analyzer.js +270 -0
- package/skills/tools/verify-module/SKILL.md +6 -4
- package/skills/tools/verify-module/scripts/module_scanner.js +145 -0
- package/skills/tools/verify-quality/SKILL.md +5 -3
- package/skills/tools/verify-quality/scripts/quality_checker.js +276 -0
- package/skills/tools/verify-security/SKILL.md +7 -5
- package/skills/tools/verify-security/scripts/security_scanner.js +133 -0
- package/skills/__pycache__/run_skill.cpython-312.pyc +0 -0
- package/skills/domains/COVERAGE_PLAN.md +0 -232
- package/skills/domains/ai/model-evaluation.md +0 -790
- package/skills/domains/ai/prompt-engineering.md +0 -703
- package/skills/domains/architecture/compliance.md +0 -299
- package/skills/domains/architecture/data-security.md +0 -184
- package/skills/domains/data-engineering/data-pipeline.md +0 -762
- package/skills/domains/data-engineering/data-quality.md +0 -894
- package/skills/domains/data-engineering/stream-processing.md +0 -791
- package/skills/domains/development/dart.md +0 -963
- package/skills/domains/development/kotlin.md +0 -834
- package/skills/domains/development/php.md +0 -659
- package/skills/domains/development/swift.md +0 -755
- package/skills/domains/devops/e2e-testing.md +0 -914
- package/skills/domains/devops/performance-testing.md +0 -734
- package/skills/domains/devops/testing-strategy.md +0 -667
- package/skills/domains/frontend-design/build-tools.md +0 -743
- package/skills/domains/frontend-design/performance.md +0 -734
- package/skills/domains/frontend-design/testing.md +0 -699
- package/skills/domains/infrastructure/gitops.md +0 -735
- package/skills/domains/infrastructure/iac.md +0 -855
- package/skills/domains/infrastructure/kubernetes.md +0 -1018
- package/skills/domains/mobile/android-dev.md +0 -979
- package/skills/domains/mobile/cross-platform.md +0 -795
- package/skills/domains/mobile/ios-dev.md +0 -931
- package/skills/domains/security/secrets-management.md +0 -834
- package/skills/domains/security/supply-chain.md +0 -931
- package/skills/domains/security/threat-modeling.md +0 -828
- package/skills/run_skill.py +0 -153
- package/skills/tests/README.md +0 -225
- package/skills/tests/SUMMARY.md +0 -362
- package/skills/tests/__init__.py +0 -3
- package/skills/tests/__pycache__/test_change_analyzer.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_doc_generator.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_module_scanner.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_quality_checker.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_security_scanner.cpython-312.pyc +0 -0
- package/skills/tests/test_change_analyzer.py +0 -558
- package/skills/tests/test_doc_generator.py +0 -538
- package/skills/tests/test_module_scanner.py +0 -376
- package/skills/tests/test_quality_checker.py +0 -516
- package/skills/tests/test_security_scanner.py +0 -426
- package/skills/tools/gen-docs/scripts/__pycache__/doc_generator.cpython-312.pyc +0 -0
- package/skills/tools/gen-docs/scripts/doc_generator.py +0 -520
- package/skills/tools/verify-change/scripts/__pycache__/change_analyzer.cpython-312.pyc +0 -0
- package/skills/tools/verify-change/scripts/change_analyzer.py +0 -529
- package/skills/tools/verify-module/scripts/__pycache__/module_scanner.cpython-312.pyc +0 -0
- package/skills/tools/verify-module/scripts/module_scanner.py +0 -321
- package/skills/tools/verify-quality/scripts/__pycache__/quality_checker.cpython-312.pyc +0 -0
- package/skills/tools/verify-quality/scripts/quality_checker.py +0 -481
- package/skills/tools/verify-security/scripts/__pycache__/security_scanner.cpython-312.pyc +0 -0
- package/skills/tools/verify-security/scripts/security_scanner.py +0 -374
|
@@ -1,963 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: dart
|
|
3
|
-
description: Dart 开发技术。Flutter、Widget 树、异步编程、Future、Stream、跨平台开发。当用户提到 Dart、Flutter、Widget、跨平台、移动开发时使用。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# 🎯 Dart 开发 · Dart Development
|
|
7
|
-
|
|
8
|
-
## 生态架构
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
Flutter Framework
|
|
12
|
-
│
|
|
13
|
-
┌─────────┼─────────┐
|
|
14
|
-
│ │ │
|
|
15
|
-
Widgets Material Cupertino
|
|
16
|
-
│ │ │
|
|
17
|
-
└─────────┼─────────┘
|
|
18
|
-
│
|
|
19
|
-
Dart Runtime
|
|
20
|
-
│
|
|
21
|
-
┌─────────┼─────────┐
|
|
22
|
-
Future Stream Isolate
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Dart 语言基础
|
|
26
|
-
|
|
27
|
-
### 变量与类型
|
|
28
|
-
```dart
|
|
29
|
-
// 类型推断
|
|
30
|
-
var name = 'John';
|
|
31
|
-
var age = 30;
|
|
32
|
-
|
|
33
|
-
// 显式类型
|
|
34
|
-
String email = 'john@example.com';
|
|
35
|
-
int count = 0;
|
|
36
|
-
double price = 99.99;
|
|
37
|
-
bool isActive = true;
|
|
38
|
-
|
|
39
|
-
// 可空类型
|
|
40
|
-
String? nullableName;
|
|
41
|
-
int? nullableAge;
|
|
42
|
-
|
|
43
|
-
// late 延迟初始化
|
|
44
|
-
late String description;
|
|
45
|
-
|
|
46
|
-
// final 与 const
|
|
47
|
-
final currentTime = DateTime.now(); // 运行时常量
|
|
48
|
-
const pi = 3.14159; // 编译时常量
|
|
49
|
-
|
|
50
|
-
// 集合
|
|
51
|
-
List<String> names = ['Alice', 'Bob', 'Charlie'];
|
|
52
|
-
Set<int> uniqueNumbers = {1, 2, 3};
|
|
53
|
-
Map<String, int> scores = {'Alice': 95, 'Bob': 87};
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 函数与闭包
|
|
57
|
-
```dart
|
|
58
|
-
// 基础函数
|
|
59
|
-
int add(int a, int b) {
|
|
60
|
-
return a + b;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 箭头函数
|
|
64
|
-
int multiply(int a, int b) => a * b;
|
|
65
|
-
|
|
66
|
-
// 可选参数
|
|
67
|
-
String greet(String name, [String? title]) {
|
|
68
|
-
return title != null ? '$title $name' : name;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// 命名参数
|
|
72
|
-
void printUser({required String name, int age = 0}) {
|
|
73
|
-
print('$name is $age years old');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// 高阶函数
|
|
77
|
-
List<T> transform<T>(List<T> items, T Function(T) transformer) {
|
|
78
|
-
return items.map(transformer).toList();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// 闭包
|
|
82
|
-
Function makeAdder(int addBy) {
|
|
83
|
-
return (int i) => i + addBy;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
var add2 = makeAdder(2);
|
|
87
|
-
print(add2(3)); // 5
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### 类与继承
|
|
91
|
-
```dart
|
|
92
|
-
// 基础类
|
|
93
|
-
class Person {
|
|
94
|
-
String name;
|
|
95
|
-
int age;
|
|
96
|
-
|
|
97
|
-
// 构造函数
|
|
98
|
-
Person(this.name, this.age);
|
|
99
|
-
|
|
100
|
-
// 命名构造函数
|
|
101
|
-
Person.guest() : name = 'Guest', age = 0;
|
|
102
|
-
|
|
103
|
-
// 方法
|
|
104
|
-
void introduce() {
|
|
105
|
-
print('I am $name, $age years old');
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// 继承
|
|
110
|
-
class Student extends Person {
|
|
111
|
-
String school;
|
|
112
|
-
|
|
113
|
-
Student(String name, int age, this.school) : super(name, age);
|
|
114
|
-
|
|
115
|
-
@override
|
|
116
|
-
void introduce() {
|
|
117
|
-
super.introduce();
|
|
118
|
-
print('I study at $school');
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// 抽象类
|
|
123
|
-
abstract class Animal {
|
|
124
|
-
String name;
|
|
125
|
-
Animal(this.name);
|
|
126
|
-
|
|
127
|
-
void makeSound(); // 抽象方法
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
class Dog extends Animal {
|
|
131
|
-
Dog(String name) : super(name);
|
|
132
|
-
|
|
133
|
-
@override
|
|
134
|
-
void makeSound() {
|
|
135
|
-
print('$name says: Woof!');
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Mixin
|
|
140
|
-
mixin Flyable {
|
|
141
|
-
void fly() {
|
|
142
|
-
print('Flying...');
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
class Bird extends Animal with Flyable {
|
|
147
|
-
Bird(String name) : super(name);
|
|
148
|
-
|
|
149
|
-
@override
|
|
150
|
-
void makeSound() {
|
|
151
|
-
print('$name says: Chirp!');
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
## Flutter Widget 基础
|
|
157
|
-
|
|
158
|
-
### StatelessWidget
|
|
159
|
-
```dart
|
|
160
|
-
import 'package:flutter/material.dart';
|
|
161
|
-
|
|
162
|
-
class UserCard extends StatelessWidget {
|
|
163
|
-
final String name;
|
|
164
|
-
final String email;
|
|
165
|
-
final String? avatarUrl;
|
|
166
|
-
|
|
167
|
-
const UserCard({
|
|
168
|
-
Key? key,
|
|
169
|
-
required this.name,
|
|
170
|
-
required this.email,
|
|
171
|
-
this.avatarUrl,
|
|
172
|
-
}) : super(key: key);
|
|
173
|
-
|
|
174
|
-
@override
|
|
175
|
-
Widget build(BuildContext context) {
|
|
176
|
-
return Card(
|
|
177
|
-
margin: EdgeInsets.all(16),
|
|
178
|
-
child: Padding(
|
|
179
|
-
padding: EdgeInsets.all(16),
|
|
180
|
-
child: Row(
|
|
181
|
-
children: [
|
|
182
|
-
CircleAvatar(
|
|
183
|
-
radius: 30,
|
|
184
|
-
backgroundImage: avatarUrl != null
|
|
185
|
-
? NetworkImage(avatarUrl!)
|
|
186
|
-
: null,
|
|
187
|
-
child: avatarUrl == null ? Icon(Icons.person) : null,
|
|
188
|
-
),
|
|
189
|
-
SizedBox(width: 16),
|
|
190
|
-
Expanded(
|
|
191
|
-
child: Column(
|
|
192
|
-
crossAxisAlignment: CrossAxisAlignment.start,
|
|
193
|
-
children: [
|
|
194
|
-
Text(
|
|
195
|
-
name,
|
|
196
|
-
style: Theme.of(context).textTheme.titleLarge,
|
|
197
|
-
),
|
|
198
|
-
SizedBox(height: 4),
|
|
199
|
-
Text(
|
|
200
|
-
email,
|
|
201
|
-
style: Theme.of(context).textTheme.bodyMedium,
|
|
202
|
-
),
|
|
203
|
-
],
|
|
204
|
-
),
|
|
205
|
-
),
|
|
206
|
-
],
|
|
207
|
-
),
|
|
208
|
-
),
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### StatefulWidget
|
|
215
|
-
```dart
|
|
216
|
-
class Counter extends StatefulWidget {
|
|
217
|
-
const Counter({Key? key}) : super(key: key);
|
|
218
|
-
|
|
219
|
-
@override
|
|
220
|
-
State<Counter> createState() => _CounterState();
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
class _CounterState extends State<Counter> {
|
|
224
|
-
int _count = 0;
|
|
225
|
-
|
|
226
|
-
void _increment() {
|
|
227
|
-
setState(() {
|
|
228
|
-
_count++;
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
@override
|
|
233
|
-
Widget build(BuildContext context) {
|
|
234
|
-
return Column(
|
|
235
|
-
mainAxisAlignment: MainAxisAlignment.center,
|
|
236
|
-
children: [
|
|
237
|
-
Text(
|
|
238
|
-
'Count: $_count',
|
|
239
|
-
style: Theme.of(context).textTheme.headlineMedium,
|
|
240
|
-
),
|
|
241
|
-
SizedBox(height: 16),
|
|
242
|
-
ElevatedButton(
|
|
243
|
-
onPressed: _increment,
|
|
244
|
-
child: Text('Increment'),
|
|
245
|
-
),
|
|
246
|
-
],
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### 布局 Widget
|
|
253
|
-
```dart
|
|
254
|
-
class LayoutExample extends StatelessWidget {
|
|
255
|
-
@override
|
|
256
|
-
Widget build(BuildContext context) {
|
|
257
|
-
return Scaffold(
|
|
258
|
-
appBar: AppBar(title: Text('Layout Example')),
|
|
259
|
-
body: Column(
|
|
260
|
-
children: [
|
|
261
|
-
// Row 水平布局
|
|
262
|
-
Row(
|
|
263
|
-
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
264
|
-
children: [
|
|
265
|
-
Icon(Icons.star),
|
|
266
|
-
Icon(Icons.favorite),
|
|
267
|
-
Icon(Icons.thumb_up),
|
|
268
|
-
],
|
|
269
|
-
),
|
|
270
|
-
|
|
271
|
-
// Stack 层叠布局
|
|
272
|
-
Stack(
|
|
273
|
-
children: [
|
|
274
|
-
Container(
|
|
275
|
-
width: 200,
|
|
276
|
-
height: 200,
|
|
277
|
-
color: Colors.blue,
|
|
278
|
-
),
|
|
279
|
-
Positioned(
|
|
280
|
-
top: 20,
|
|
281
|
-
left: 20,
|
|
282
|
-
child: Text('Overlay Text'),
|
|
283
|
-
),
|
|
284
|
-
],
|
|
285
|
-
),
|
|
286
|
-
|
|
287
|
-
// Expanded 填充剩余空间
|
|
288
|
-
Expanded(
|
|
289
|
-
child: Container(
|
|
290
|
-
color: Colors.grey[200],
|
|
291
|
-
child: Center(child: Text('Expanded Area')),
|
|
292
|
-
),
|
|
293
|
-
),
|
|
294
|
-
|
|
295
|
-
// ListView
|
|
296
|
-
Expanded(
|
|
297
|
-
child: ListView.builder(
|
|
298
|
-
itemCount: 20,
|
|
299
|
-
itemBuilder: (context, index) {
|
|
300
|
-
return ListTile(
|
|
301
|
-
leading: Icon(Icons.person),
|
|
302
|
-
title: Text('Item $index'),
|
|
303
|
-
subtitle: Text('Description'),
|
|
304
|
-
trailing: Icon(Icons.chevron_right),
|
|
305
|
-
);
|
|
306
|
-
},
|
|
307
|
-
),
|
|
308
|
-
),
|
|
309
|
-
],
|
|
310
|
-
),
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
### 导航与路由
|
|
317
|
-
```dart
|
|
318
|
-
// 基础导航
|
|
319
|
-
Navigator.push(
|
|
320
|
-
context,
|
|
321
|
-
MaterialPageRoute(builder: (context) => DetailScreen()),
|
|
322
|
-
);
|
|
323
|
-
|
|
324
|
-
Navigator.pop(context);
|
|
325
|
-
|
|
326
|
-
// 命名路由
|
|
327
|
-
MaterialApp(
|
|
328
|
-
initialRoute: '/',
|
|
329
|
-
routes: {
|
|
330
|
-
'/': (context) => HomeScreen(),
|
|
331
|
-
'/detail': (context) => DetailScreen(),
|
|
332
|
-
'/settings': (context) => SettingsScreen(),
|
|
333
|
-
},
|
|
334
|
-
);
|
|
335
|
-
|
|
336
|
-
Navigator.pushNamed(context, '/detail');
|
|
337
|
-
|
|
338
|
-
// 传递参数
|
|
339
|
-
Navigator.pushNamed(
|
|
340
|
-
context,
|
|
341
|
-
'/detail',
|
|
342
|
-
arguments: {'id': '123', 'name': 'Item'},
|
|
343
|
-
);
|
|
344
|
-
|
|
345
|
-
// 接收参数
|
|
346
|
-
class DetailScreen extends StatelessWidget {
|
|
347
|
-
@override
|
|
348
|
-
Widget build(BuildContext context) {
|
|
349
|
-
final args = ModalRoute.of(context)!.settings.arguments as Map;
|
|
350
|
-
return Scaffold(
|
|
351
|
-
appBar: AppBar(title: Text(args['name'])),
|
|
352
|
-
body: Center(child: Text('ID: ${args['id']}')),
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
## 状态管理
|
|
359
|
-
|
|
360
|
-
### Provider
|
|
361
|
-
```dart
|
|
362
|
-
import 'package:provider/provider.dart';
|
|
363
|
-
|
|
364
|
-
// Model
|
|
365
|
-
class Counter with ChangeNotifier {
|
|
366
|
-
int _count = 0;
|
|
367
|
-
|
|
368
|
-
int get count => _count;
|
|
369
|
-
|
|
370
|
-
void increment() {
|
|
371
|
-
_count++;
|
|
372
|
-
notifyListeners();
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
void reset() {
|
|
376
|
-
_count = 0;
|
|
377
|
-
notifyListeners();
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// 提供者
|
|
382
|
-
void main() {
|
|
383
|
-
runApp(
|
|
384
|
-
ChangeNotifierProvider(
|
|
385
|
-
create: (context) => Counter(),
|
|
386
|
-
child: MyApp(),
|
|
387
|
-
),
|
|
388
|
-
);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// 消费者
|
|
392
|
-
class CounterScreen extends StatelessWidget {
|
|
393
|
-
@override
|
|
394
|
-
Widget build(BuildContext context) {
|
|
395
|
-
return Scaffold(
|
|
396
|
-
appBar: AppBar(title: Text('Counter')),
|
|
397
|
-
body: Center(
|
|
398
|
-
child: Column(
|
|
399
|
-
mainAxisAlignment: MainAxisAlignment.center,
|
|
400
|
-
children: [
|
|
401
|
-
Consumer<Counter>(
|
|
402
|
-
builder: (context, counter, child) {
|
|
403
|
-
return Text(
|
|
404
|
-
'Count: ${counter.count}',
|
|
405
|
-
style: Theme.of(context).textTheme.headlineMedium,
|
|
406
|
-
);
|
|
407
|
-
},
|
|
408
|
-
),
|
|
409
|
-
SizedBox(height: 16),
|
|
410
|
-
ElevatedButton(
|
|
411
|
-
onPressed: () {
|
|
412
|
-
context.read<Counter>().increment();
|
|
413
|
-
},
|
|
414
|
-
child: Text('Increment'),
|
|
415
|
-
),
|
|
416
|
-
],
|
|
417
|
-
),
|
|
418
|
-
),
|
|
419
|
-
);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
```
|
|
423
|
-
|
|
424
|
-
### Riverpod
|
|
425
|
-
```dart
|
|
426
|
-
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
427
|
-
|
|
428
|
-
// Provider 定义
|
|
429
|
-
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
|
|
430
|
-
return CounterNotifier();
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
class CounterNotifier extends StateNotifier<int> {
|
|
434
|
-
CounterNotifier() : super(0);
|
|
435
|
-
|
|
436
|
-
void increment() => state++;
|
|
437
|
-
void decrement() => state--;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// 使用
|
|
441
|
-
class CounterScreen extends ConsumerWidget {
|
|
442
|
-
@override
|
|
443
|
-
Widget build(BuildContext context, WidgetRef ref) {
|
|
444
|
-
final count = ref.watch(counterProvider);
|
|
445
|
-
|
|
446
|
-
return Scaffold(
|
|
447
|
-
body: Center(
|
|
448
|
-
child: Column(
|
|
449
|
-
mainAxisAlignment: MainAxisAlignment.center,
|
|
450
|
-
children: [
|
|
451
|
-
Text('Count: $count'),
|
|
452
|
-
ElevatedButton(
|
|
453
|
-
onPressed: () => ref.read(counterProvider.notifier).increment(),
|
|
454
|
-
child: Text('Increment'),
|
|
455
|
-
),
|
|
456
|
-
],
|
|
457
|
-
),
|
|
458
|
-
),
|
|
459
|
-
);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
## 异步编程
|
|
465
|
-
|
|
466
|
-
### Future
|
|
467
|
-
```dart
|
|
468
|
-
// 基础 Future
|
|
469
|
-
Future<String> fetchUserName() async {
|
|
470
|
-
await Future.delayed(Duration(seconds: 2));
|
|
471
|
-
return 'John Doe';
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// 使用 async/await
|
|
475
|
-
void loadUser() async {
|
|
476
|
-
try {
|
|
477
|
-
final name = await fetchUserName();
|
|
478
|
-
print('User: $name');
|
|
479
|
-
} catch (e) {
|
|
480
|
-
print('Error: $e');
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// Future.then
|
|
485
|
-
fetchUserName().then((name) {
|
|
486
|
-
print('User: $name');
|
|
487
|
-
}).catchError((error) {
|
|
488
|
-
print('Error: $error');
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
// 并发执行
|
|
492
|
-
Future<void> loadMultipleData() async {
|
|
493
|
-
final results = await Future.wait([
|
|
494
|
-
fetchUserName(),
|
|
495
|
-
fetchUserEmail(),
|
|
496
|
-
fetchUserAge(),
|
|
497
|
-
]);
|
|
498
|
-
|
|
499
|
-
print('Name: ${results[0]}');
|
|
500
|
-
print('Email: ${results[1]}');
|
|
501
|
-
print('Age: ${results[2]}');
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// FutureBuilder Widget
|
|
505
|
-
class UserProfile extends StatelessWidget {
|
|
506
|
-
@override
|
|
507
|
-
Widget build(BuildContext context) {
|
|
508
|
-
return FutureBuilder<User>(
|
|
509
|
-
future: fetchUser(),
|
|
510
|
-
builder: (context, snapshot) {
|
|
511
|
-
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
512
|
-
return CircularProgressIndicator();
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (snapshot.hasError) {
|
|
516
|
-
return Text('Error: ${snapshot.error}');
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
if (!snapshot.hasData) {
|
|
520
|
-
return Text('No data');
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
final user = snapshot.data!;
|
|
524
|
-
return Text('User: ${user.name}');
|
|
525
|
-
},
|
|
526
|
-
);
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
```
|
|
530
|
-
|
|
531
|
-
### Stream
|
|
532
|
-
```dart
|
|
533
|
-
// 创建 Stream
|
|
534
|
-
Stream<int> countStream() async* {
|
|
535
|
-
for (int i = 1; i <= 5; i++) {
|
|
536
|
-
await Future.delayed(Duration(seconds: 1));
|
|
537
|
-
yield i;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
// 监听 Stream
|
|
542
|
-
void listenToStream() {
|
|
543
|
-
countStream().listen(
|
|
544
|
-
(value) {
|
|
545
|
-
print('Value: $value');
|
|
546
|
-
},
|
|
547
|
-
onError: (error) {
|
|
548
|
-
print('Error: $error');
|
|
549
|
-
},
|
|
550
|
-
onDone: () {
|
|
551
|
-
print('Stream completed');
|
|
552
|
-
},
|
|
553
|
-
);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// StreamController
|
|
557
|
-
class ChatService {
|
|
558
|
-
final _messageController = StreamController<String>.broadcast();
|
|
559
|
-
|
|
560
|
-
Stream<String> get messages => _messageController.stream;
|
|
561
|
-
|
|
562
|
-
void sendMessage(String message) {
|
|
563
|
-
_messageController.add(message);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
void dispose() {
|
|
567
|
-
_messageController.close();
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
// StreamBuilder Widget
|
|
572
|
-
class MessageList extends StatelessWidget {
|
|
573
|
-
final ChatService chatService;
|
|
574
|
-
|
|
575
|
-
const MessageList({required this.chatService});
|
|
576
|
-
|
|
577
|
-
@override
|
|
578
|
-
Widget build(BuildContext context) {
|
|
579
|
-
return StreamBuilder<String>(
|
|
580
|
-
stream: chatService.messages,
|
|
581
|
-
builder: (context, snapshot) {
|
|
582
|
-
if (snapshot.hasError) {
|
|
583
|
-
return Text('Error: ${snapshot.error}');
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
if (!snapshot.hasData) {
|
|
587
|
-
return Text('No messages');
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
return Text('Latest: ${snapshot.data}');
|
|
591
|
-
},
|
|
592
|
-
);
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// Stream 操作符
|
|
597
|
-
Stream<int> transformedStream() {
|
|
598
|
-
return countStream()
|
|
599
|
-
.where((value) => value % 2 == 0)
|
|
600
|
-
.map((value) => value * 2)
|
|
601
|
-
.take(3);
|
|
602
|
-
}
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
## 网络请求
|
|
606
|
-
|
|
607
|
-
### HTTP 包
|
|
608
|
-
```dart
|
|
609
|
-
import 'package:http/http.dart' as http;
|
|
610
|
-
import 'dart:convert';
|
|
611
|
-
|
|
612
|
-
class ApiClient {
|
|
613
|
-
static const baseUrl = 'https://api.example.com';
|
|
614
|
-
|
|
615
|
-
Future<List<User>> fetchUsers() async {
|
|
616
|
-
final response = await http.get(Uri.parse('$baseUrl/users'));
|
|
617
|
-
|
|
618
|
-
if (response.statusCode == 200) {
|
|
619
|
-
final List<dynamic> data = json.decode(response.body);
|
|
620
|
-
return data.map((json) => User.fromJson(json)).toList();
|
|
621
|
-
} else {
|
|
622
|
-
throw Exception('Failed to load users');
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
Future<User> createUser(User user) async {
|
|
627
|
-
final response = await http.post(
|
|
628
|
-
Uri.parse('$baseUrl/users'),
|
|
629
|
-
headers: {'Content-Type': 'application/json'},
|
|
630
|
-
body: json.encode(user.toJson()),
|
|
631
|
-
);
|
|
632
|
-
|
|
633
|
-
if (response.statusCode == 201) {
|
|
634
|
-
return User.fromJson(json.decode(response.body));
|
|
635
|
-
} else {
|
|
636
|
-
throw Exception('Failed to create user');
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
Future<void> deleteUser(String id) async {
|
|
641
|
-
final response = await http.delete(
|
|
642
|
-
Uri.parse('$baseUrl/users/$id'),
|
|
643
|
-
);
|
|
644
|
-
|
|
645
|
-
if (response.statusCode != 204) {
|
|
646
|
-
throw Exception('Failed to delete user');
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// 数据模型
|
|
652
|
-
class User {
|
|
653
|
-
final String id;
|
|
654
|
-
final String name;
|
|
655
|
-
final String email;
|
|
656
|
-
|
|
657
|
-
User({required this.id, required this.name, required this.email});
|
|
658
|
-
|
|
659
|
-
factory User.fromJson(Map<String, dynamic> json) {
|
|
660
|
-
return User(
|
|
661
|
-
id: json['id'],
|
|
662
|
-
name: json['name'],
|
|
663
|
-
email: json['email'],
|
|
664
|
-
);
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
Map<String, dynamic> toJson() {
|
|
668
|
-
return {
|
|
669
|
-
'id': id,
|
|
670
|
-
'name': name,
|
|
671
|
-
'email': email,
|
|
672
|
-
};
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
```
|
|
676
|
-
|
|
677
|
-
### Dio 包
|
|
678
|
-
```dart
|
|
679
|
-
import 'package:dio/dio.dart';
|
|
680
|
-
|
|
681
|
-
class DioClient {
|
|
682
|
-
final Dio _dio = Dio(
|
|
683
|
-
BaseOptions(
|
|
684
|
-
baseUrl: 'https://api.example.com',
|
|
685
|
-
connectTimeout: Duration(seconds: 5),
|
|
686
|
-
receiveTimeout: Duration(seconds: 3),
|
|
687
|
-
),
|
|
688
|
-
);
|
|
689
|
-
|
|
690
|
-
DioClient() {
|
|
691
|
-
_dio.interceptors.add(
|
|
692
|
-
InterceptorsWrapper(
|
|
693
|
-
onRequest: (options, handler) {
|
|
694
|
-
options.headers['Authorization'] = 'Bearer $token';
|
|
695
|
-
return handler.next(options);
|
|
696
|
-
},
|
|
697
|
-
onError: (error, handler) {
|
|
698
|
-
print('Error: ${error.message}');
|
|
699
|
-
return handler.next(error);
|
|
700
|
-
},
|
|
701
|
-
),
|
|
702
|
-
);
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
Future<List<User>> getUsers() async {
|
|
706
|
-
try {
|
|
707
|
-
final response = await _dio.get('/users');
|
|
708
|
-
return (response.data as List)
|
|
709
|
-
.map((json) => User.fromJson(json))
|
|
710
|
-
.toList();
|
|
711
|
-
} on DioException catch (e) {
|
|
712
|
-
throw _handleError(e);
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
Exception _handleError(DioException error) {
|
|
717
|
-
switch (error.type) {
|
|
718
|
-
case DioExceptionType.connectionTimeout:
|
|
719
|
-
return Exception('Connection timeout');
|
|
720
|
-
case DioExceptionType.receiveTimeout:
|
|
721
|
-
return Exception('Receive timeout');
|
|
722
|
-
case DioExceptionType.badResponse:
|
|
723
|
-
return Exception('Server error: ${error.response?.statusCode}');
|
|
724
|
-
default:
|
|
725
|
-
return Exception('Network error');
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
```
|
|
730
|
-
|
|
731
|
-
## 本地存储
|
|
732
|
-
|
|
733
|
-
### SharedPreferences
|
|
734
|
-
```dart
|
|
735
|
-
import 'package:shared_preferences/shared_preferences.dart';
|
|
736
|
-
|
|
737
|
-
class PreferencesService {
|
|
738
|
-
Future<void> saveString(String key, String value) async {
|
|
739
|
-
final prefs = await SharedPreferences.getInstance();
|
|
740
|
-
await prefs.setString(key, value);
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
Future<String?> getString(String key) async {
|
|
744
|
-
final prefs = await SharedPreferences.getInstance();
|
|
745
|
-
return prefs.getString(key);
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
Future<void> saveInt(String key, int value) async {
|
|
749
|
-
final prefs = await SharedPreferences.getInstance();
|
|
750
|
-
await prefs.setInt(key, value);
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
Future<void> saveBool(String key, bool value) async {
|
|
754
|
-
final prefs = await SharedPreferences.getInstance();
|
|
755
|
-
await prefs.setBool(key, value);
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
Future<void> remove(String key) async {
|
|
759
|
-
final prefs = await SharedPreferences.getInstance();
|
|
760
|
-
await prefs.remove(key);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
### SQLite (sqflite)
|
|
766
|
-
```dart
|
|
767
|
-
import 'package:sqflite/sqflite.dart';
|
|
768
|
-
import 'package:path/path.dart';
|
|
769
|
-
|
|
770
|
-
class DatabaseHelper {
|
|
771
|
-
static final DatabaseHelper instance = DatabaseHelper._init();
|
|
772
|
-
static Database? _database;
|
|
773
|
-
|
|
774
|
-
DatabaseHelper._init();
|
|
775
|
-
|
|
776
|
-
Future<Database> get database async {
|
|
777
|
-
if (_database != null) return _database!;
|
|
778
|
-
_database = await _initDB('app.db');
|
|
779
|
-
return _database!;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
Future<Database> _initDB(String filePath) async {
|
|
783
|
-
final dbPath = await getDatabasesPath();
|
|
784
|
-
final path = join(dbPath, filePath);
|
|
785
|
-
|
|
786
|
-
return await openDatabase(
|
|
787
|
-
path,
|
|
788
|
-
version: 1,
|
|
789
|
-
onCreate: _createDB,
|
|
790
|
-
);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
Future _createDB(Database db, int version) async {
|
|
794
|
-
await db.execute('''
|
|
795
|
-
CREATE TABLE users (
|
|
796
|
-
id TEXT PRIMARY KEY,
|
|
797
|
-
name TEXT NOT NULL,
|
|
798
|
-
email TEXT NOT NULL,
|
|
799
|
-
created_at INTEGER NOT NULL
|
|
800
|
-
)
|
|
801
|
-
''');
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
Future<void> insertUser(User user) async {
|
|
805
|
-
final db = await database;
|
|
806
|
-
await db.insert('users', user.toMap());
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
Future<List<User>> getUsers() async {
|
|
810
|
-
final db = await database;
|
|
811
|
-
final result = await db.query('users');
|
|
812
|
-
return result.map((json) => User.fromMap(json)).toList();
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
Future<void> deleteUser(String id) async {
|
|
816
|
-
final db = await database;
|
|
817
|
-
await db.delete('users', where: 'id = ?', whereArgs: [id]);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
```
|
|
821
|
-
|
|
822
|
-
## 测试
|
|
823
|
-
|
|
824
|
-
### 单元测试
|
|
825
|
-
```dart
|
|
826
|
-
import 'package:test/test.dart';
|
|
827
|
-
|
|
828
|
-
void main() {
|
|
829
|
-
group('Calculator', () {
|
|
830
|
-
late Calculator calculator;
|
|
831
|
-
|
|
832
|
-
setUp(() {
|
|
833
|
-
calculator = Calculator();
|
|
834
|
-
});
|
|
835
|
-
|
|
836
|
-
test('addition should return correct result', () {
|
|
837
|
-
expect(calculator.add(2, 3), equals(5));
|
|
838
|
-
});
|
|
839
|
-
|
|
840
|
-
test('division by zero should throw exception', () {
|
|
841
|
-
expect(() => calculator.divide(10, 0), throwsException);
|
|
842
|
-
});
|
|
843
|
-
});
|
|
844
|
-
|
|
845
|
-
group('User', () {
|
|
846
|
-
test('fromJson should create valid user', () {
|
|
847
|
-
final json = {'id': '1', 'name': 'John', 'email': 'john@example.com'};
|
|
848
|
-
final user = User.fromJson(json);
|
|
849
|
-
|
|
850
|
-
expect(user.id, equals('1'));
|
|
851
|
-
expect(user.name, equals('John'));
|
|
852
|
-
expect(user.email, equals('john@example.com'));
|
|
853
|
-
});
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
```
|
|
857
|
-
|
|
858
|
-
### Widget 测试
|
|
859
|
-
```dart
|
|
860
|
-
import 'package:flutter_test/flutter_test.dart';
|
|
861
|
-
|
|
862
|
-
void main() {
|
|
863
|
-
testWidgets('Counter increments', (WidgetTester tester) async {
|
|
864
|
-
await tester.pumpWidget(MaterialApp(home: Counter()));
|
|
865
|
-
|
|
866
|
-
expect(find.text('Count: 0'), findsOneWidget);
|
|
867
|
-
expect(find.text('Count: 1'), findsNothing);
|
|
868
|
-
|
|
869
|
-
await tester.tap(find.byType(ElevatedButton));
|
|
870
|
-
await tester.pump();
|
|
871
|
-
|
|
872
|
-
expect(find.text('Count: 0'), findsNothing);
|
|
873
|
-
expect(find.text('Count: 1'), findsOneWidget);
|
|
874
|
-
});
|
|
875
|
-
|
|
876
|
-
testWidgets('UserCard displays user info', (WidgetTester tester) async {
|
|
877
|
-
await tester.pumpWidget(
|
|
878
|
-
MaterialApp(
|
|
879
|
-
home: Scaffold(
|
|
880
|
-
body: UserCard(
|
|
881
|
-
name: 'John Doe',
|
|
882
|
-
email: 'john@example.com',
|
|
883
|
-
),
|
|
884
|
-
),
|
|
885
|
-
),
|
|
886
|
-
);
|
|
887
|
-
|
|
888
|
-
expect(find.text('John Doe'), findsOneWidget);
|
|
889
|
-
expect(find.text('john@example.com'), findsOneWidget);
|
|
890
|
-
});
|
|
891
|
-
}
|
|
892
|
-
```
|
|
893
|
-
|
|
894
|
-
## 性能优化
|
|
895
|
-
|
|
896
|
-
### 列表优化
|
|
897
|
-
```dart
|
|
898
|
-
// ✅ 使用 ListView.builder
|
|
899
|
-
ListView.builder(
|
|
900
|
-
itemCount: items.length,
|
|
901
|
-
itemBuilder: (context, index) {
|
|
902
|
-
return ItemWidget(items[index]);
|
|
903
|
-
},
|
|
904
|
-
);
|
|
905
|
-
|
|
906
|
-
// ❌ 避免直接使用 ListView
|
|
907
|
-
ListView(
|
|
908
|
-
children: items.map((item) => ItemWidget(item)).toList(),
|
|
909
|
-
);
|
|
910
|
-
|
|
911
|
-
// const 构造函数
|
|
912
|
-
class MyWidget extends StatelessWidget {
|
|
913
|
-
const MyWidget({Key? key}) : super(key: key);
|
|
914
|
-
|
|
915
|
-
@override
|
|
916
|
-
Widget build(BuildContext context) {
|
|
917
|
-
return const Text('Static text');
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
```
|
|
921
|
-
|
|
922
|
-
### 图片优化
|
|
923
|
-
```dart
|
|
924
|
-
// 缓存网络图片
|
|
925
|
-
CachedNetworkImage(
|
|
926
|
-
imageUrl: 'https://example.com/image.jpg',
|
|
927
|
-
placeholder: (context, url) => CircularProgressIndicator(),
|
|
928
|
-
errorWidget: (context, url, error) => Icon(Icons.error),
|
|
929
|
-
);
|
|
930
|
-
|
|
931
|
-
// 图片压缩
|
|
932
|
-
Image.network(
|
|
933
|
-
'https://example.com/image.jpg',
|
|
934
|
-
cacheWidth: 300,
|
|
935
|
-
cacheHeight: 300,
|
|
936
|
-
);
|
|
937
|
-
```
|
|
938
|
-
|
|
939
|
-
## 平台对比
|
|
940
|
-
|
|
941
|
-
| 特性 | Flutter | React Native |
|
|
942
|
-
|------|---------|--------------|
|
|
943
|
-
| 语言 | Dart | JavaScript |
|
|
944
|
-
| 性能 | 接近原生 | 较好 |
|
|
945
|
-
| UI 渲染 | Skia 引擎 | 原生组件 |
|
|
946
|
-
| 热重载 | ✅ | ✅ |
|
|
947
|
-
| 学习曲线 | 中等 | 平缓 |
|
|
948
|
-
| 生态 | 快速增长 | 成熟 |
|
|
949
|
-
|
|
950
|
-
## 工具清单
|
|
951
|
-
|
|
952
|
-
| 工具 | 用途 |
|
|
953
|
-
|------|------|
|
|
954
|
-
| Flutter SDK | 开发框架 |
|
|
955
|
-
| Dart DevTools | 调试工具 |
|
|
956
|
-
| Provider | 状态管理 |
|
|
957
|
-
| Riverpod | 状态管理 |
|
|
958
|
-
| Dio | 网络请求 |
|
|
959
|
-
| sqflite | SQLite 数据库 |
|
|
960
|
-
| shared_preferences | 键值存储 |
|
|
961
|
-
| flutter_test | 测试框架 |
|
|
962
|
-
|
|
963
|
-
---
|