@ohos-cpf/3rdloop 0.0.12 → 0.0.13

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.
Files changed (45) hide show
  1. package/package.json +1 -1
  2. package/vendor/Server/Routes/controllers/LoopEngineController.js +36 -3
  3. package/vendor/Server/Routes/controllers/OrchestratorController.js +193 -9
  4. package/vendor/Server/Skills/flutter-build-test/SKILL.md +252 -0
  5. package/vendor/Server/Skills/flutter-build-test/assets/BUILDENV_TEMPLATE.md +42 -0
  6. package/vendor/Server/Skills/flutter-build-test/assets/BUILD_REPORT_TEMPLATE.md +64 -0
  7. package/vendor/Server/Skills/flutter-build-test/assets/README_SECTION_TEMPLATE.md +78 -0
  8. package/vendor/Server/Skills/flutter-build-test/references/BUILD_TROUBLESHOOTING.md +128 -0
  9. package/vendor/Server/Skills/flutter-build-test/references/DOC_UPDATE_GUIDE.md +119 -0
  10. package/vendor/Server/Skills/flutter-build-test/references/FLVM_GUIDE.md +89 -0
  11. package/vendor/Server/Skills/flutter-build-test/scripts/build-matrix.cjs +374 -0
  12. package/vendor/Server/Skills/flutter-build-test/scripts/locate-example.cjs +189 -0
  13. package/vendor/Server/Skills/flutter-build-test/scripts/update-buildenv.cjs +171 -0
  14. package/vendor/Server/Skills/flutter-code-use/SKILL.md +316 -0
  15. package/vendor/Server/Skills/flutter-code-use/references/event-channel.md +440 -0
  16. package/vendor/Server/Skills/flutter-code-use/references/federated.md +295 -0
  17. package/vendor/Server/Skills/flutter-code-use/references/ffi-binding-translate.md +130 -0
  18. package/vendor/Server/Skills/flutter-code-use/references/ffi-compile-from-source.md +169 -0
  19. package/vendor/Server/Skills/flutter-code-use/references/ffi-fetch-at-build.md +161 -0
  20. package/vendor/Server/Skills/flutter-code-use/references/ffi-prebuilt-bundle.md +175 -0
  21. package/vendor/Server/Skills/flutter-code-use/references/ffi-rhttp-guide.md +235 -0
  22. package/vendor/Server/Skills/flutter-code-use/references/ffi-rust-cross-compile.md +514 -0
  23. package/vendor/Server/Skills/flutter-code-use/references/ffi.md +220 -0
  24. package/vendor/Server/Skills/flutter-code-use/references/method-channel.md +643 -0
  25. package/vendor/Server/Skills/flutter-code-use/references/monorepo.md +188 -0
  26. package/vendor/Server/Skills/flutter-code-use/references/ohos-api-pitfalls.md +717 -0
  27. package/vendor/Server/Skills/flutter-code-use/references/platform-view.md +448 -0
  28. package/vendor/Server/Skills/flutter-code-use/references/pure-dart.md +180 -0
  29. package/vendor/Server/Skills/flutter-code-use/references/texture.md +459 -0
  30. package/vendor/Server/Skills/flutter-demo-code-generator/SKILL.md +270 -0
  31. package/vendor/Server/Skills/flutter-demo-code-generator/assets/PAGE_TEMPLATES.md +544 -0
  32. package/vendor/Server/Skills/flutter-demo-code-generator/references/CODE_STANDARDS.md +328 -0
  33. package/vendor/Server/Skills/flutter-demo-code-generator/references/DEMO_DOC_PARSING.md +126 -0
  34. package/vendor/Server/Skills/flutter-demo-code-generator/references/EXAMPLES.md +629 -0
  35. package/vendor/Server/Skills/flutter-demo-code-generator/scripts/validate-flutter-demo.cjs +268 -0
  36. package/vendor/Server/Skills/flutter-demo-doc-generator/SKILL.md +227 -0
  37. package/vendor/Server/Skills/flutter-demo-doc-generator/assets/DEMO_DOC_TEMPLATE.md +78 -0
  38. package/vendor/Server/Skills/flutter-demo-doc-generator/references/COVERAGE_REPORT_PARSING.md +174 -0
  39. package/vendor/Server/Skills/flutter-demo-doc-generator/references/EXAMPLES.md +162 -0
  40. package/vendor/Server/Skills/flutter-demo-doc-generator/references/MCP_TOOL_GUIDE.md +123 -0
  41. package/vendor/Server/Skills/flutter-demo-doc-generator/references/OUTPUT_FORMAT.md +190 -0
  42. package/vendor/Server/Skills/flutter-demo-doc-generator/references/QUALITY_CHECKLIST.md +83 -0
  43. package/vendor/Server/Skills/flutter-demo-doc-generator/scripts/validate-skill.cjs +259 -0
  44. package/vendor/Server/Skills/flutter-library-demo-coverage/SKILL.md +175 -0
  45. package/vendor/VERSION +3 -3
@@ -0,0 +1,629 @@
1
+ # 示例:flutter_video_player Demo 代码生成
2
+
3
+ 本文档展示使用 `flutter-demo-code-generator` 技能,基于 `flutter_video_player` 库的测试 Demo 描述文档,生成实际 Dart 页面代码的完整示例(节选 Demo 001 和 Demo 002)。
4
+
5
+ ---
6
+
7
+ ## 输入:Demo 描述文档片段
8
+
9
+ | 序号 | 测试 Demo 名称 | 对应函数接口 |
10
+ |-----|--------------|------------|
11
+ | 1 | 环境检测与版本查询 Demo | `isHardwareDecodingSupported(): bool`、`getSDKVersion(): String` |
12
+ | 2 | 控制器初始化与资源释放 Demo | `VideoPlayerController(config)`、`initialize(): Future<void>`、`dispose(): Future<void>` |
13
+
14
+ ---
15
+
16
+ ## 输出示例一:Demo 001 页面代码
17
+
18
+ **文件路径**:`lib/pages/001_check_support/check_support_page.dart`
19
+
20
+ ```dart
21
+ /// Demo 001: Check Support And SDK Version
22
+ ///
23
+ /// 功能说明:展示如何在使用播放器前检测当前设备是否支持硬件解码,
24
+ /// 并查询 SDK 版本号,帮助开发者了解使用前置条件检查的标准流程。
25
+ /// 对应接口:
26
+ /// - isHardwareDecodingSupported(): bool
27
+ /// - getSDKVersion(): String
28
+
29
+ import 'dart:developer' as dev;
30
+
31
+ import 'package:flutter/material.dart';
32
+ import 'package:flutter_video_player/flutter_video_player.dart';
33
+
34
+ // ─── 日志 Tag ────────────────────────────────────────────────────────────
35
+ const String _kTag = 'FlutterVideoPlayer_CheckSupportPage';
36
+
37
+ /// CheckSupportPage - 环境检测与版本查询示例
38
+ ///
39
+ /// 展示 flutter_video_player 的设备能力检测和版本查询流程。
40
+ class CheckSupportPage extends StatefulWidget {
41
+ const CheckSupportPage({super.key});
42
+
43
+ @override
44
+ State<CheckSupportPage> createState() => _CheckSupportPageState();
45
+ }
46
+
47
+ class _CheckSupportPageState extends State<CheckSupportPage> {
48
+ // ─── 状态变量 ─────────────────────────────────────────────────────────
49
+ String _hwDecodeResult = '';
50
+ String _sdkVersionResult = '';
51
+
52
+ @override
53
+ void initState() {
54
+ super.initState();
55
+ dev.log('Page appeared', name: _kTag);
56
+ }
57
+
58
+ @override
59
+ void dispose() {
60
+ dev.log('Page disposed', name: _kTag);
61
+ super.dispose();
62
+ }
63
+
64
+ // ─── 核心功能方法 ──────────────────────────────────────────────────────
65
+
66
+ /// 检测当前设备是否支持硬件解码。
67
+ ///
68
+ /// 调用 [isHardwareDecodingSupported] 并将结果展示在页面上。
69
+ void _checkHardwareDecoding() {
70
+ dev.log('_checkHardwareDecoding called', name: _kTag);
71
+ try {
72
+ // 调用库接口:同步返回布尔值
73
+ final bool supported = isHardwareDecodingSupported();
74
+ dev.log('_checkHardwareDecoding result: $supported', name: _kTag);
75
+ setState(() {
76
+ _hwDecodeResult = supported
77
+ ? '当前设备支持硬件解码 ✅'
78
+ : '当前设备不支持硬件解码 ❌';
79
+ });
80
+ } catch (e, stack) {
81
+ dev.log(
82
+ '_checkHardwareDecoding failed',
83
+ name: _kTag,
84
+ error: e,
85
+ stackTrace: stack,
86
+ );
87
+ setState(() => _hwDecodeResult = '检测失败:$e');
88
+ }
89
+ }
90
+
91
+ /// 查询 SDK 版本号。
92
+ ///
93
+ /// 调用 [getSDKVersion] 并将版本号字符串展示在页面上。
94
+ void _querySdkVersion() {
95
+ dev.log('_querySdkVersion called', name: _kTag);
96
+ try {
97
+ final String version = getSDKVersion();
98
+ dev.log('_querySdkVersion result: $version', name: _kTag);
99
+ setState(() => _sdkVersionResult = 'SDK 版本: $version');
100
+ } catch (e, stack) {
101
+ dev.log(
102
+ '_querySdkVersion failed',
103
+ name: _kTag,
104
+ error: e,
105
+ stackTrace: stack,
106
+ );
107
+ setState(() => _sdkVersionResult = '查询失败:$e');
108
+ }
109
+ }
110
+
111
+ // ─── UI 构建 ─────────────────────────────────────────────────────────
112
+
113
+ @override
114
+ Widget build(BuildContext context) {
115
+ return Scaffold(
116
+ appBar: AppBar(
117
+ title: const Text('[001] 环境检测与版本查询'),
118
+ ),
119
+ body: SingleChildScrollView(
120
+ padding: const EdgeInsets.all(16),
121
+ child: Column(
122
+ crossAxisAlignment: CrossAxisAlignment.stretch,
123
+ children: [
124
+ // 说明卡片
125
+ Card(
126
+ child: Padding(
127
+ padding: const EdgeInsets.all(12),
128
+ child: Text(
129
+ '在使用播放器前,可通过以下接口检测设备能力和 SDK 版本。'
130
+ '这些信息有助于开发者根据设备环境做出适当的适配决策。',
131
+ style: Theme.of(context).textTheme.bodyMedium,
132
+ ),
133
+ ),
134
+ ),
135
+ const SizedBox(height: 16),
136
+
137
+ // 硬件解码检测区域
138
+ const Text(
139
+ '硬件解码能力检测',
140
+ style: TextStyle(fontWeight: FontWeight.bold),
141
+ ),
142
+ const SizedBox(height: 8),
143
+ ElevatedButton(
144
+ onPressed: _checkHardwareDecoding,
145
+ child: const Text('检测硬件解码支持'),
146
+ ),
147
+ const SizedBox(height: 8),
148
+ _buildResultBox(_hwDecodeResult, '(点击上方按钮检测)'),
149
+ const SizedBox(height: 24),
150
+
151
+ // SDK 版本查询区域
152
+ const Text(
153
+ 'SDK 版本查询',
154
+ style: TextStyle(fontWeight: FontWeight.bold),
155
+ ),
156
+ const SizedBox(height: 8),
157
+ ElevatedButton(
158
+ onPressed: _querySdkVersion,
159
+ child: const Text('查询 SDK 版本号'),
160
+ ),
161
+ const SizedBox(height: 8),
162
+ _buildResultBox(_sdkVersionResult, '(点击上方按钮查询)'),
163
+ ],
164
+ ),
165
+ ),
166
+ );
167
+ }
168
+
169
+ /// 构建结果展示框
170
+ Widget _buildResultBox(String result, String placeholder) {
171
+ return Container(
172
+ width: double.infinity,
173
+ padding: const EdgeInsets.all(12),
174
+ decoration: BoxDecoration(
175
+ color: Colors.grey[100],
176
+ borderRadius: BorderRadius.circular(8),
177
+ border: Border.all(color: Colors.grey[300]!),
178
+ ),
179
+ child: Text(result.isEmpty ? placeholder : result),
180
+ );
181
+ }
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ## 输出示例二:Demo 002 页面代码
188
+
189
+ **文件路径**:`lib/pages/002_controller_lifecycle/controller_lifecycle_page.dart`
190
+
191
+ ```dart
192
+ /// Demo 002: Controller Lifecycle Management
193
+ ///
194
+ /// 功能说明:展示 VideoPlayerController 的完整生命周期管理流程,包括
195
+ /// 使用 PlayerConfig 构造实例、调用 initialize() 异步加载资源
196
+ /// 以及最终调用 dispose() 释放资源。
197
+ /// 对应接口:
198
+ /// - VideoPlayerController(config: PlayerConfig)
199
+ /// - PlayerConfig({required url, autoPlay, initialVolume})
200
+ /// - initialize(): Future<void>
201
+ /// - dispose(): Future<void>
202
+
203
+ import 'dart:developer' as dev;
204
+
205
+ import 'package:flutter/material.dart';
206
+ import 'package:flutter_video_player/flutter_video_player.dart';
207
+
208
+ // ─── 日志 Tag ────────────────────────────────────────────────────────────
209
+ const String _kTag = 'FlutterVideoPlayer_ControllerLifecyclePage';
210
+
211
+ /// 控制器状态枚举
212
+ enum _ControllerStatus { idle, loading, ready, disposed }
213
+
214
+ /// ControllerLifecyclePage - 控制器初始化与资源释放示例
215
+ ///
216
+ /// 展示 flutter_video_player 的 VideoPlayerController 从创建到销毁的
217
+ /// 完整生命周期,以及异步 initialize() 的正确使用姿势。
218
+ class ControllerLifecyclePage extends StatefulWidget {
219
+ const ControllerLifecyclePage({super.key});
220
+
221
+ @override
222
+ State<ControllerLifecyclePage> createState() =>
223
+ _ControllerLifecyclePageState();
224
+ }
225
+
226
+ class _ControllerLifecyclePageState extends State<ControllerLifecyclePage> {
227
+ // ─── 状态变量 ─────────────────────────────────────────────────────────
228
+ _ControllerStatus _status = _ControllerStatus.idle;
229
+ String _statusText = '未初始化';
230
+ String _logText = '';
231
+
232
+ /// 双计数器(诊断异步链路)
233
+ int _initCallCount = 0;
234
+ int _initDoneCount = 0;
235
+
236
+ // ─── 输入控制器 ────────────────────────────────────────────────────────
237
+ final TextEditingController _urlController = TextEditingController(
238
+ text: 'https://example.com/sample.mp4',
239
+ );
240
+
241
+ // ─── 非响应式:库实例 ───────────────────────────────────────────────────
242
+ VideoPlayerController? _controller;
243
+
244
+ @override
245
+ void initState() {
246
+ super.initState();
247
+ dev.log('Page appeared', name: _kTag);
248
+ }
249
+
250
+ @override
251
+ void dispose() {
252
+ dev.log('Page disposed, releasing resources', name: _kTag);
253
+ // 释放库控制器资源(若页面销毁时控制器仍存在)
254
+ _controller?.dispose();
255
+ _controller = null;
256
+ // 释放 TextField 控制器
257
+ _urlController.dispose();
258
+ super.dispose();
259
+ }
260
+
261
+ // ─── 核心功能方法 ──────────────────────────────────────────────────────
262
+
263
+ /// 初始化 VideoPlayerController。
264
+ ///
265
+ /// 构造 [PlayerConfig] 并传入 [VideoPlayerController],
266
+ /// 调用 [initialize()] 异步加载视频资源,完成后更新 UI 状态。
267
+ Future<void> _initController() async {
268
+ dev.log('_initController called, url: ${_urlController.text}', name: _kTag);
269
+ setState(() {
270
+ _initCallCount++;
271
+ _status = _ControllerStatus.loading;
272
+ _statusText = '加载中...';
273
+ });
274
+ try {
275
+ final config = PlayerConfig(
276
+ url: _urlController.text.trim(),
277
+ autoPlay: false,
278
+ initialVolume: 1.0,
279
+ );
280
+ final controller = VideoPlayerController(config);
281
+ await controller.initialize();
282
+ dev.log('_initController succeeded', name: _kTag);
283
+ if (!mounted) return;
284
+ setState(() {
285
+ _controller = controller;
286
+ _initDoneCount++;
287
+ _status = _ControllerStatus.ready;
288
+ _statusText = '已就绪';
289
+ _logText = '✅ 控制器初始化成功\n'
290
+ ' URL: ${_urlController.text.trim()}';
291
+ });
292
+ } catch (e, stack) {
293
+ dev.log('_initController failed', name: _kTag, error: e, stackTrace: stack);
294
+ if (!mounted) return;
295
+ setState(() {
296
+ _status = _ControllerStatus.idle;
297
+ _statusText = '初始化失败';
298
+ _logText = '❌ 初始化失败:$e';
299
+ });
300
+ }
301
+ }
302
+
303
+ /// 释放 VideoPlayerController 资源。
304
+ ///
305
+ /// 调用 [dispose()] 释放底层资源,将控制器引用置空,更新 UI 状态。
306
+ Future<void> _disposeController() async {
307
+ dev.log('_disposeController called', name: _kTag);
308
+ if (_controller == null) {
309
+ dev.log('_disposeController skipped: controller is null', name: _kTag);
310
+ return;
311
+ }
312
+ try {
313
+ await _controller!.dispose();
314
+ dev.log('_disposeController succeeded', name: _kTag);
315
+ if (!mounted) return;
316
+ setState(() {
317
+ _controller = null;
318
+ _status = _ControllerStatus.disposed;
319
+ _statusText = '已释放';
320
+ _logText = '✅ 控制器资源已释放';
321
+ });
322
+ } catch (e, stack) {
323
+ dev.log(
324
+ '_disposeController failed',
325
+ name: _kTag,
326
+ error: e,
327
+ stackTrace: stack,
328
+ );
329
+ if (!mounted) return;
330
+ setState(() => _logText = '❌ 释放失败:$e');
331
+ }
332
+ }
333
+
334
+ // ─── UI 构建 ─────────────────────────────────────────────────────────
335
+
336
+ @override
337
+ Widget build(BuildContext context) {
338
+ final bool isIdle = _status == _ControllerStatus.idle ||
339
+ _status == _ControllerStatus.disposed;
340
+ final bool isLoading = _status == _ControllerStatus.loading;
341
+ final bool isReady = _status == _ControllerStatus.ready;
342
+
343
+ return Scaffold(
344
+ appBar: AppBar(
345
+ title: const Text('[002] 控制器初始化与资源释放'),
346
+ ),
347
+ body: SingleChildScrollView(
348
+ padding: const EdgeInsets.all(16),
349
+ child: Column(
350
+ crossAxisAlignment: CrossAxisAlignment.stretch,
351
+ children: [
352
+ // 说明卡片
353
+ Card(
354
+ child: Padding(
355
+ padding: const EdgeInsets.all(12),
356
+ child: Text(
357
+ '展示 VideoPlayerController 的完整生命周期:'
358
+ '构造配置 → 异步初始化 → 释放资源。'
359
+ '通过双计数器验证异步链路的完整性。',
360
+ style: Theme.of(context).textTheme.bodyMedium,
361
+ ),
362
+ ),
363
+ ),
364
+ const SizedBox(height: 16),
365
+
366
+ // URL 输入框
367
+ TextField(
368
+ controller: _urlController,
369
+ decoration: const InputDecoration(
370
+ labelText: '视频 URL',
371
+ border: OutlineInputBorder(),
372
+ hintText: 'https://example.com/video.mp4',
373
+ ),
374
+ enabled: isIdle,
375
+ ),
376
+ const SizedBox(height: 12),
377
+
378
+ // 操作按钮行
379
+ Row(
380
+ children: [
381
+ Expanded(
382
+ child: ElevatedButton(
383
+ onPressed: isIdle ? _initController : null,
384
+ child: const Text('初始化控制器'),
385
+ ),
386
+ ),
387
+ const SizedBox(width: 12),
388
+ Expanded(
389
+ child: ElevatedButton(
390
+ onPressed: isReady ? _disposeController : null,
391
+ style: ElevatedButton.styleFrom(
392
+ backgroundColor: Colors.red[400],
393
+ foregroundColor: Colors.white,
394
+ ),
395
+ child: const Text('释放控制器'),
396
+ ),
397
+ ),
398
+ ],
399
+ ),
400
+ const SizedBox(height: 16),
401
+
402
+ // Loading 指示器
403
+ if (isLoading)
404
+ const Center(
405
+ child: Padding(
406
+ padding: EdgeInsets.all(8),
407
+ child: CircularProgressIndicator(),
408
+ ),
409
+ ),
410
+
411
+ // 当前状态展示
412
+ _buildStatusRow('当前状态', _statusText),
413
+ const SizedBox(height: 8),
414
+
415
+ // 双计数器诊断区域
416
+ Card(
417
+ child: Padding(
418
+ padding: const EdgeInsets.all(12),
419
+ child: Column(
420
+ crossAxisAlignment: CrossAxisAlignment.start,
421
+ children: [
422
+ const Text(
423
+ '异步链路诊断',
424
+ style: TextStyle(fontWeight: FontWeight.bold),
425
+ ),
426
+ const SizedBox(height: 8),
427
+ Text('初始化调用次数: $_initCallCount'),
428
+ Text('初始化完成次数: $_initDoneCount'),
429
+ const SizedBox(height: 4),
430
+ if (_initCallCount > 0 && _initDoneCount == 0 && !isLoading)
431
+ const Text(
432
+ '⚠️ 调用了但未完成,可能初始化出错',
433
+ style: TextStyle(color: Colors.orange),
434
+ ),
435
+ if (_initDoneCount > 0 && _initCallCount == _initDoneCount)
436
+ const Text(
437
+ '✅ 异步链路正常',
438
+ style: TextStyle(color: Colors.green),
439
+ ),
440
+ ],
441
+ ),
442
+ ),
443
+ ),
444
+ const SizedBox(height: 8),
445
+
446
+ // 日志输出区域
447
+ if (_logText.isNotEmpty)
448
+ Container(
449
+ width: double.infinity,
450
+ padding: const EdgeInsets.all(12),
451
+ decoration: BoxDecoration(
452
+ color: Colors.grey[100],
453
+ borderRadius: BorderRadius.circular(8),
454
+ border: Border.all(color: Colors.grey[300]!),
455
+ ),
456
+ child: SelectableText(
457
+ _logText,
458
+ style: const TextStyle(fontFamily: 'monospace', fontSize: 13),
459
+ ),
460
+ ),
461
+ ],
462
+ ),
463
+ ),
464
+ );
465
+ }
466
+
467
+ /// 构建状态行
468
+ Widget _buildStatusRow(String label, String value) {
469
+ return Row(
470
+ children: [
471
+ Text('$label:', style: const TextStyle(fontWeight: FontWeight.w500)),
472
+ const SizedBox(width: 8),
473
+ Expanded(child: Text(value)),
474
+ ],
475
+ );
476
+ }
477
+ }
478
+ ```
479
+
480
+ ---
481
+
482
+ ## 输出示例三:主导航页面代码
483
+
484
+ **文件路径**:`lib/pages/demo_home_page.dart`
485
+
486
+ ```dart
487
+ /// flutter_video_player Demo 主导航页面
488
+ ///
489
+ /// 展示所有可用的 Demo 列表,点击后跳转到对应 Demo 页面。
490
+
491
+ import 'dart:developer' as dev;
492
+
493
+ import 'package:flutter/material.dart';
494
+
495
+ import '001_check_support/check_support_page.dart';
496
+ import '002_controller_lifecycle/controller_lifecycle_page.dart';
497
+ import '003_playback_control/playback_control_page.dart';
498
+ import '004_volume_control/volume_control_page.dart';
499
+
500
+ const String _kTag = 'FlutterVideoPlayer_DemoHome';
501
+
502
+ class _DemoEntry {
503
+ const _DemoEntry({
504
+ required this.id,
505
+ required this.title,
506
+ required this.description,
507
+ required this.builder,
508
+ });
509
+
510
+ final String id;
511
+ final String title;
512
+ final String description;
513
+ final WidgetBuilder builder;
514
+ }
515
+
516
+ final List<_DemoEntry> _demoList = [
517
+ _DemoEntry(
518
+ id: '001',
519
+ title: '环境检测与版本查询',
520
+ description: '检测设备硬件解码支持情况,查询 SDK 版本号',
521
+ builder: (_) => const CheckSupportPage(),
522
+ ),
523
+ _DemoEntry(
524
+ id: '002',
525
+ title: '控制器初始化与资源释放',
526
+ description: '展示 VideoPlayerController 完整生命周期:初始化 → 就绪 → 释放',
527
+ builder: (_) => const ControllerLifecyclePage(),
528
+ ),
529
+ _DemoEntry(
530
+ id: '003',
531
+ title: '播放控制与进度管理',
532
+ description: '展示 play/pause/seekTo 及进度监听的完整使用流程',
533
+ builder: (_) => const PlaybackControlPage(),
534
+ ),
535
+ _DemoEntry(
536
+ id: '004',
537
+ title: '音量控制',
538
+ description: '通过 setVolume/volume 调节并读取当前播放音量',
539
+ builder: (_) => const VolumeControlPage(),
540
+ ),
541
+ ];
542
+
543
+ /// DemoHomePage - flutter_video_player Demo 示例主导航页
544
+ class DemoHomePage extends StatelessWidget {
545
+ const DemoHomePage({super.key});
546
+
547
+ @override
548
+ Widget build(BuildContext context) {
549
+ return Scaffold(
550
+ appBar: AppBar(
551
+ title: const Text('flutter_video_player Demo 示例'),
552
+ centerTitle: true,
553
+ ),
554
+ body: ListView.separated(
555
+ padding: const EdgeInsets.all(16),
556
+ itemCount: _demoList.length,
557
+ separatorBuilder: (_, __) => const SizedBox(height: 8),
558
+ itemBuilder: (context, index) {
559
+ final demo = _demoList[index];
560
+ return _DemoCard(
561
+ demo: demo,
562
+ onTap: () {
563
+ dev.log(
564
+ 'Navigate to demo: ${demo.id} - ${demo.title}',
565
+ name: _kTag,
566
+ );
567
+ Navigator.push(
568
+ context,
569
+ MaterialPageRoute(builder: demo.builder),
570
+ );
571
+ },
572
+ );
573
+ },
574
+ ),
575
+ );
576
+ }
577
+ }
578
+
579
+ class _DemoCard extends StatelessWidget {
580
+ const _DemoCard({required this.demo, required this.onTap});
581
+
582
+ final _DemoEntry demo;
583
+ final VoidCallback onTap;
584
+
585
+ @override
586
+ Widget build(BuildContext context) {
587
+ return Card(
588
+ child: ListTile(
589
+ leading: CircleAvatar(
590
+ child: Text(demo.id, style: const TextStyle(fontSize: 12)),
591
+ ),
592
+ title: Text(
593
+ '[${demo.id}] ${demo.title}',
594
+ style: const TextStyle(fontWeight: FontWeight.w500),
595
+ ),
596
+ subtitle: Text(
597
+ demo.description,
598
+ maxLines: 2,
599
+ overflow: TextOverflow.ellipsis,
600
+ ),
601
+ trailing: const Icon(Icons.arrow_forward_ios, size: 16),
602
+ onTap: onTap,
603
+ ),
604
+ );
605
+ }
606
+ }
607
+ ```
608
+
609
+ ---
610
+
611
+ ## 关键生成规则说明
612
+
613
+ 上述示例展示了以下技能规则的应用:
614
+
615
+ 1. **文件命名**:目录名 `001_check_support`、文件名 `check_support_page.dart`、类名 `CheckSupportPage`,全部遵循 Dart 命名规范。
616
+
617
+ 2. **日志常量**:每个文件顶部声明 `const String _kTag = 'FlutterVideoPlayer_XxxPage'`,所有 `dev.log` 调用均使用该常量。
618
+
619
+ 3. **双计数器诊断**:`_initCallCount`(调用次数)和 `_initDoneCount`(完成次数)均通过 `setState()` 更新,确保 UI 实时反映异步状态,同时在 UI 中展示诊断信息。
620
+
621
+ 4. **mounted 检查**:在所有 `async` 方法的 `await` 后、调用 `setState()` 前,均有 `if (!mounted) return` 检查,防止页面销毁后触发 setState 导致的内存错误。
622
+
623
+ 5. **资源释放**:`dispose()` 中释放了库控制器(`_controller?.dispose()`)和 TextField 控制器(`_urlController.dispose()`),并置空引用防止悬挂指针。
624
+
625
+ 6. **const 优化**:所有静态 Widget(标题 Text、SizedBox、Card 内的固定 Text 等)均使用 `const` 修饰,减少不必要重建。
626
+
627
+ 7. **错误处理**:所有异步调用均包裹在 `try/catch (e, stack)` 中,`dev.log` 同时传递 `error` 和 `stackTrace` 参数,方便调试定位。
628
+
629
+ 8. **接口真实性**:生成前应通过 `script_flutter_extract_interfaces` 提取 `flutter_video_player` 的接口规格,确认 `isHardwareDecodingSupported`、`VideoPlayerController`、`PlayerConfig` 等签名与源码一致后再编码。