前端改动: - 新建设置页面 (主题切换/关于/隐私政策/用户协议/儿童隐私保护) - SettingsBloc 注册到 MultiRepositoryProvider 全局可访问 - MoodBloc 修复编译错误 + 接入 /diary/stats/mood API - MoodPage 添加错误状态展示和重试按钮 - AchievementBloc + 页面改造接入 /diary/achievements API - StickerBloc + 页面改造接入 /diary/sticker-packs API - TemplateBloc + 页面改造接入 /diary/templates API - ProfilePage 设置入口改为跳转 /settings - 添加 /settings 路由 后端改动: - 扩展 mood_stats_service 测试 (连续天数算法/心情计数/边界场景) - 新增 class_service 测试 (班级码生成/唯一性/错误映射) - 新增 achievement_service 测试 (DTO 结构/序列化/map 构建) - 新增 sticker_service 测试 (DTO 序列化/错误处理) - 扩展 dto.rs 测试 (achievement/mood_stats/sticker/template/notification) - 清理 2 个 unused import warning 验证: - cargo check 0 error 0 warning - flutter analyze 0 error
94 lines
2.9 KiB
Dart
94 lines
2.9 KiB
Dart
// 暖记 App 根组件 — MaterialApp + BLoC Provider 注入
|
||
//
|
||
// 依赖注入结构:
|
||
// MultiRepositoryProvider
|
||
// ├─ ApiClient
|
||
// ├─ AuthRepository
|
||
// ├─ JournalRepository (RemoteJournalRepository)
|
||
// └─ ClassRepository
|
||
// └─ BlocProvider<AuthBloc>
|
||
// └─ MaterialApp.router
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
|
||
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/remote_journal_repository.dart';
|
||
import 'data/repositories/class_repository.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);
|
||
final journalRepository = RemoteJournalRepository(api: apiClient);
|
||
final classRepository = ClassRepository(api: apiClient);
|
||
final settingsBloc = SettingsBloc();
|
||
final authBloc = AuthBloc(authRepository: authRepository);
|
||
|
||
// 启动时检查认证状态
|
||
authBloc.add(const AppStarted());
|
||
|
||
// 认证成功后注入 JWT token 到 ApiClient
|
||
authBloc.stream.listen((state) {
|
||
if (state is Authenticated) {
|
||
// TODO: 从 SecureStorage 读取 token 并设置
|
||
// apiClient.setToken(token);
|
||
} else {
|
||
apiClient.clearToken();
|
||
}
|
||
});
|
||
|
||
return MultiRepositoryProvider(
|
||
providers: [
|
||
RepositoryProvider<ApiClient>.value(value: apiClient),
|
||
RepositoryProvider<AuthRepository>.value(value: authRepository),
|
||
RepositoryProvider<JournalRepository>.value(value: journalRepository),
|
||
RepositoryProvider<ClassRepository>.value(value: classRepository),
|
||
RepositoryProvider<SettingsBloc>.value(value: settingsBloc),
|
||
],
|
||
child: BlocProvider<AuthBloc>.value(
|
||
value: authBloc,
|
||
child: ListenableBuilder(
|
||
listenable: settingsBloc,
|
||
builder: (context, _) => _AppView(
|
||
router: createAppRouter(authBloc),
|
||
themeMode: settingsBloc.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,
|
||
);
|
||
}
|
||
}
|