feat: M1.1 完成 + M1.2 启动 — 全量更新

M1.1 收尾:
- 24项 P0/P1/P2 bug 修复 (Rust 107 tests + Flutter 15 tests)
- Flutter App v0.3: cupertino_icons 修复, 单元测试, 调试面板, APK 52.6MB
- 示例插件完善: manifest.json + 请求/响应示范 + 7个测试
- API 文档重写 (以 routes.rs 为唯一权威)
- MILESTONES.md 更新至 100%

M1.2 启动:
- P0: 插件管理 API 闭环 (handle_manager_message Custom 分支 + broadcast_plugin_states)
- ServiceManager 集成测试 8/8 (tests/m1_2_service_manager.rs)
- M1.2 测试计划 (docs/M1.2_TEST_PLAN.md, 18个E2E场景)
- 动态插件系统: auto_rollback + version_manager GC + 路径穿越防护

总计: Rust 115/115 测试, Flutter 15/15 测试, 零 warning

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
showen
2026-03-14 18:12:42 +08:00
parent 8ed9cb2d9d
commit d30c111c71
68 changed files with 8115 additions and 1201 deletions

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import '../providers/ble_provider.dart';
import '../providers/device_provider.dart';
import '../providers/wifi_provider.dart';
import '../theme/app_colors.dart';
@@ -33,6 +34,7 @@ class _NetworkScreenState extends State<NetworkScreen> {
@override
Widget build(BuildContext context) {
final bleProvider = context.watch<BleProvider>();
final wifiProvider = context.watch<WifiProvider>();
final deviceProvider = context.watch<DeviceProvider>();
final wifiStatus = wifiProvider.status;
@@ -40,9 +42,12 @@ class _NetworkScreenState extends State<NetworkScreen> {
return Scaffold(
appBar: AppBar(title: const Text('网络设置')),
body: ListView(
padding: const EdgeInsets.all(AppSpacing.md),
children: [
body: RefreshIndicator(
onRefresh: _handleRefresh,
child: ListView(
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.all(AppSpacing.md),
children: [
StatusCard(
title: 'WiFi 状态',
value: wifiStatus.connected ? (wifiStatus.ssid ?? '已连接') : '未连接',
@@ -107,6 +112,75 @@ class _NetworkScreenState extends State<NetworkScreen> {
),
],
),
if (bleProvider.isConnected) ...[
const SizedBox(height: AppSpacing.lg),
Card(
child: Padding(
padding: const EdgeInsets.all(AppSpacing.md),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('BLE 控制', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: AppSpacing.sm),
Text(
bleProvider.selectedDevice?.name ?? '已连接 BLE 设备',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: AppSpacing.md),
Row(
children: [
Expanded(
child: ControlButton(
label: '播放',
icon: Icons.play_arrow_rounded,
onPressed: bleProvider.isSendingCommand
? null
: () => _sendBleCommand('play'),
),
),
const SizedBox(width: AppSpacing.md),
Expanded(
child: ControlButton(
label: '暂停',
icon: Icons.pause_rounded,
onPressed: bleProvider.isSendingCommand
? null
: () => _sendBleCommand('pause'),
),
),
],
),
const SizedBox(height: AppSpacing.md),
Row(
children: [
Expanded(
child: ControlButton(
label: '上一个',
icon: Icons.skip_previous_rounded,
isFilled: false,
onPressed: bleProvider.isSendingCommand
? null
: () => _sendBleCommand('prev'),
),
),
const SizedBox(width: AppSpacing.md),
Expanded(
child: ControlButton(
label: '下一个',
icon: Icons.skip_next_rounded,
isFilled: false,
onPressed: bleProvider.isSendingCommand
? null
: () => _sendBleCommand('next'),
),
),
],
),
],
),
),
),
],
const SizedBox(height: AppSpacing.lg),
Text('扫描结果', style: Theme.of(context).textTheme.headlineSmall),
const SizedBox(height: AppSpacing.md),
@@ -179,11 +253,19 @@ class _NetworkScreenState extends State<NetworkScreen> {
child: const Text('进入 BLE 配网页面'),
),
),
],
],
),
),
);
}
Future<void> _handleRefresh() async {
await Future.wait<void>([
context.read<WifiProvider>().bootstrap(),
context.read<DeviceProvider>().refresh(),
]);
}
void _handleConnectWifi() {
final ssid = _ssidController.text.trim();
if (ssid.isEmpty) {
@@ -198,4 +280,23 @@ class _NetworkScreenState extends State<NetworkScreen> {
password: _passwordController.text,
);
}
Future<void> _sendBleCommand(String command) async {
try {
await context.read<BleProvider>().sendCommand(command);
if (!mounted) {
return;
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('已发送 BLE 指令: $command')),
);
} catch (error) {
if (!mounted) {
return;
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('BLE 指令发送失败: $error')),
);
}
}
}