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>
167 lines
4.9 KiB
Dart
167 lines
4.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'providers/device_provider.dart';
|
|
import 'providers/debug_provider.dart';
|
|
import 'providers/ble_provider.dart';
|
|
import 'providers/player_provider.dart';
|
|
import 'providers/wifi_provider.dart';
|
|
import 'screens/app_shell.dart';
|
|
import 'screens/ble_provision_screen.dart';
|
|
import 'screens/debug_screen.dart';
|
|
import 'screens/home_screen.dart';
|
|
import 'screens/network_screen.dart';
|
|
import 'screens/playback_screen.dart';
|
|
import 'screens/settings_screen.dart';
|
|
import 'screens/trigger_screen.dart';
|
|
import 'services/device_storage_service.dart';
|
|
import 'services/http_api_service.dart';
|
|
import 'services/web_socket_service.dart';
|
|
import 'theme/app_theme.dart';
|
|
|
|
Future<void> main() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
final deviceStorageService = DeviceStorageService();
|
|
final lastDevice = await deviceStorageService.getLastDevice();
|
|
final initialDeviceIp = lastDevice?.ip ?? '127.0.0.1';
|
|
final initialDevicePort = lastDevice?.port ?? 5000;
|
|
|
|
final httpApiService = HttpApiService(
|
|
baseUrl: 'http://$initialDeviceIp:$initialDevicePort',
|
|
);
|
|
final webSocketService = WebSocketService();
|
|
|
|
runApp(
|
|
MultiProvider(
|
|
providers: [
|
|
Provider<WebSocketService>.value(value: webSocketService),
|
|
ChangeNotifierProvider<DebugProvider>(
|
|
create: (_) => DebugProvider(webSocketService: webSocketService),
|
|
),
|
|
ChangeNotifierProvider<DeviceProvider>(
|
|
create: (context) => DeviceProvider(
|
|
httpApiService: httpApiService,
|
|
webSocketService: webSocketService,
|
|
deviceStorageService: deviceStorageService,
|
|
debugProvider: context.read<DebugProvider>(),
|
|
initialDeviceIp: initialDeviceIp,
|
|
initialDevicePort: initialDevicePort,
|
|
initialDeviceName: lastDevice?.name,
|
|
)..initialize(),
|
|
),
|
|
ChangeNotifierProvider<BleProvider>(
|
|
create: (context) => BleProvider(
|
|
debugProvider: context.read<DebugProvider>(),
|
|
),
|
|
),
|
|
ChangeNotifierProvider<PlayerProvider>(
|
|
create: (context) => PlayerProvider(
|
|
httpApiService: httpApiService,
|
|
webSocketService: webSocketService,
|
|
debugProvider: context.read<DebugProvider>(),
|
|
)..bootstrap(),
|
|
),
|
|
ChangeNotifierProvider<WifiProvider>(
|
|
create: (context) => WifiProvider(
|
|
httpApiService: httpApiService,
|
|
webSocketService: webSocketService,
|
|
debugProvider: context.read<DebugProvider>(),
|
|
)..bootstrap(),
|
|
),
|
|
],
|
|
child: const ShowenApp(),
|
|
),
|
|
);
|
|
}
|
|
|
|
final GoRouter _router = GoRouter(
|
|
initialLocation: '/',
|
|
routes: [
|
|
StatefulShellRoute.indexedStack(
|
|
builder: (context, state, navigationShell) =>
|
|
AppShell(navigationShell: navigationShell),
|
|
branches: [
|
|
StatefulShellBranch(
|
|
routes: [
|
|
GoRoute(
|
|
path: '/',
|
|
name: 'home',
|
|
builder: (context, state) => const HomeScreen(),
|
|
),
|
|
],
|
|
),
|
|
StatefulShellBranch(
|
|
routes: [
|
|
GoRoute(
|
|
path: '/playback',
|
|
name: 'playback',
|
|
builder: (context, state) => const PlaybackScreen(),
|
|
),
|
|
],
|
|
),
|
|
StatefulShellBranch(
|
|
routes: [
|
|
GoRoute(
|
|
path: '/trigger',
|
|
name: 'trigger',
|
|
builder: (context, state) => const TriggerScreen(),
|
|
),
|
|
],
|
|
),
|
|
StatefulShellBranch(
|
|
routes: [
|
|
GoRoute(
|
|
path: '/network',
|
|
name: 'network',
|
|
builder: (context, state) => const NetworkScreen(),
|
|
routes: [
|
|
GoRoute(
|
|
path: 'ble-provision',
|
|
name: 'ble-provision',
|
|
builder: (context, state) => const BleProvisionScreen(),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
StatefulShellBranch(
|
|
routes: [
|
|
GoRoute(
|
|
path: '/settings',
|
|
name: 'settings',
|
|
builder: (context, state) => const SettingsScreen(),
|
|
),
|
|
],
|
|
),
|
|
StatefulShellBranch(
|
|
routes: [
|
|
GoRoute(
|
|
path: '/debug',
|
|
name: 'debug',
|
|
builder: (context, state) => const DebugScreen(),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
|
|
class ShowenApp extends StatelessWidget {
|
|
const ShowenApp({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp.router(
|
|
title: 'ShowenV2',
|
|
debugShowCheckedModeBanner: false,
|
|
themeMode: ThemeMode.dark,
|
|
darkTheme: AppTheme.dark(),
|
|
theme: AppTheme.dark(),
|
|
routerConfig: _router,
|
|
);
|
|
}
|
|
}
|