- BLE: 修复 BlueZ LocalName 与 Includes 冲突,串行注册与退避 - HTTP: 语音对话补 Live2D talking 标志与 session;Web 补 X-Session-Id - Flutter: 角色/对话/模型页 + API,Gradle/依赖升级,麦克风权限 - 文档: 新增 docs/STATUS.md,校准 CLAUDE/PROGRESS/README - 清理: 移除根目录截图与临时模型,运维脚本迁入 scripts/device
209 lines
6.4 KiB
Dart
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,
|
|
);
|
|
}
|
|
}
|