Files
ShowenV2/clients/flutter/lib/main.dart
XiuchengWu 6f7e24db63 feat: M2.1 客户端骨架、BLE 修复、仓库整理与现状板
- BLE: 修复 BlueZ LocalName 与 Includes 冲突,串行注册与退避
- HTTP: 语音对话补 Live2D talking 标志与 session;Web 补 X-Session-Id
- Flutter: 角色/对话/模型页 + API,Gradle/依赖升级,麦克风权限
- 文档: 新增 docs/STATUS.md,校准 CLAUDE/PROGRESS/README
- 清理: 移除根目录截图与临时模型,运维脚本迁入 scripts/device
2026-07-09 12:41:34 +08:00

209 lines
6.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'providers/character_provider.dart';
import 'providers/chat_provider.dart';
import 'providers/device_provider.dart';
import 'providers/debug_provider.dart';
import 'providers/ble_provider.dart';
import 'providers/model_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/characters_screen.dart';
import 'screens/chat_screen.dart';
import 'screens/debug_screen.dart';
import 'screens/home_screen.dart';
import 'screens/models_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<HttpApiService>.value(value: httpApiService),
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(),
),
ChangeNotifierProvider<CharacterProvider>(
create: (context) => CharacterProvider(
httpApiService: httpApiService,
debugProvider: context.read<DebugProvider>(),
),
),
ChangeNotifierProvider<ChatProvider>(
create: (context) => ChatProvider(
httpApiService: httpApiService,
debugProvider: context.read<DebugProvider>(),
),
),
ChangeNotifierProvider<ModelProvider>(
create: (context) => ModelProvider(
httpApiService: httpApiService,
debugProvider: context.read<DebugProvider>(),
),
),
],
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: '/characters',
name: 'characters',
builder: (context, state) => const CharactersScreen(),
),
],
),
StatefulShellBranch(
routes: [
GoRoute(
path: '/chat',
name: 'chat',
builder: (context, state) => const ChatScreen(),
),
],
),
StatefulShellBranch(
routes: [
GoRoute(
path: '/playback',
name: 'playback',
builder: (context, state) => const PlaybackScreen(),
),
],
),
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(),
routes: [
GoRoute(
path: 'models',
name: 'models',
builder: (context, state) => const ModelsScreen(),
),
GoRoute(
path: 'trigger',
name: 'trigger',
builder: (context, state) => const TriggerScreen(),
),
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,
);
}
}