// 暖记 App 根组件 — MaterialApp + BLoC Provider 注入 // // 依赖注入结构: // MultiRepositoryProvider // ├─ ApiClient // ├─ AuthRepository // ├─ JournalRepository (IsarJournalRepository — 离线优先) // ├─ RemoteJournalRepository (供 SyncEngine 使用) // └─ ClassRepository // └─ BlocProvider // └─ MaterialApp.router import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart' show ListenableProvider; import 'core/theme/app_theme.dart'; import 'core/routing/app_router.dart'; import 'data/remote/api_client.dart'; import 'data/repositories/auth_repository.dart'; import 'data/repositories/journal_repository.dart'; import 'data/repositories/isar_journal_repository.dart'; import 'data/repositories/remote_journal_repository.dart'; import 'data/repositories/class_repository.dart'; import 'data/services/sync_engine.dart'; import 'features/auth/bloc/auth_bloc.dart'; import 'features/profile/bloc/settings_bloc.dart'; /// 暖记 App — 根组件 class NuanjiApp extends StatelessWidget { const NuanjiApp({super.key}); @override Widget build(BuildContext context) { // 创建全局依赖(App 生命周期内单例) final apiClient = ApiClient(); final authRepository = AuthRepository(apiClient: apiClient); // 离线优先:Isar 为主要本地仓库,Remote 供 SyncEngine 推送 // Web 平台:Isar 3.x 不支持 Web,直接使用远程仓库 final journalRepository = kIsWeb ? RemoteJournalRepository(api: apiClient) : IsarJournalRepository(); final remoteJournalRepository = RemoteJournalRepository(api: apiClient); final syncEngine = SyncEngine(apiClient: apiClient); final classRepository = ClassRepository(api: apiClient); final settingsBloc = SettingsBloc(); final authBloc = AuthBloc(authRepository: authRepository); // 启动时检查认证状态 authBloc.add(const AppStarted()); // 异步恢复 SyncEngine 持久化队列(fire-and-forget,不阻塞 UI) syncEngine.restorePendingQueue(); // 认证状态监听:登出时清除 token // 注意:登录时 token 由 AuthRepository.login() 直接注入 ApiClient authBloc.stream.listen((state) { if (state is! Authenticated) { apiClient.clearToken(); } }); return MultiRepositoryProvider( providers: [ RepositoryProvider.value(value: apiClient), RepositoryProvider.value(value: authRepository), RepositoryProvider.value(value: journalRepository), RepositoryProvider.value(value: remoteJournalRepository), RepositoryProvider.value(value: syncEngine), RepositoryProvider.value(value: classRepository), ], child: ListenableProvider.value( value: settingsBloc, child: Builder( builder: (context) { final settings = context.watch(); return BlocProvider.value( value: authBloc, child: _AppView( router: createAppRouter(authBloc), themeMode: settings.state.themeMode, ), ); }, ), ), ); } } /// App 视图 — MaterialApp.router 包装 class _AppView extends StatelessWidget { final GoRouter router; final ThemeMode themeMode; const _AppView({required this.router, this.themeMode = ThemeMode.system}); @override Widget build(BuildContext context) { return MaterialApp.router( title: '暖记', debugShowCheckedModeBanner: false, theme: AppTheme.light(), darkTheme: AppTheme.dark(), themeMode: themeMode, routerConfig: router, ); } }