142 lines
4.9 KiB
Dart
142 lines
4.9 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
||
import '../../core/services/app_initializer.dart';
|
||
import 'network_provider.dart';
|
||
|
||
// ── 认证 ──────────────────────────────────────────────────────────────────────
|
||
|
||
/// 登录状态管理
|
||
///
|
||
/// 同时继承 [ChangeNotifier],作为 go_router [GoRouter.refreshListenable] 使用,
|
||
/// 登录 / 退出时 go_router 自动重新执行 redirect,无需手动触发。
|
||
///
|
||
/// ## 当前状态
|
||
///
|
||
/// Demo 实现,无持久化。storage_sdk 就绪后替换为:
|
||
/// - `build`:从安全存储读取 token,有则视为已登录
|
||
/// - `login` / `logout`:同步更新安全存储
|
||
class AuthNotifier extends ChangeNotifier {
|
||
bool _isLoggedIn = false;
|
||
|
||
bool get isLoggedIn => _isLoggedIn;
|
||
|
||
void login() {
|
||
_isLoggedIn = true;
|
||
notifyListeners();
|
||
}
|
||
|
||
void logout() {
|
||
_isLoggedIn = false;
|
||
notifyListeners();
|
||
}
|
||
}
|
||
|
||
/// 登录状态 Provider
|
||
///
|
||
/// 使用 [Provider] 持有 [AuthNotifier] 单例。
|
||
/// go_router 通过 [GoRouter.refreshListenable] 直接监听 [AuthNotifier](ChangeNotifier),
|
||
/// Riverpod 侧不需要响应式更新(导航由 go_router 接管)。
|
||
final authNotifierProvider = Provider<AuthNotifier>(
|
||
(ref) => AuthNotifier(),
|
||
);
|
||
|
||
// ── 主题 ──────────────────────────────────────────────────────────────────────
|
||
|
||
/// 主题模式 Notifier — 控制应用全局亮 / 暗主题
|
||
///
|
||
/// 启动时从持久化存储读取上次保存的主题模式,无则默认跟随系统。
|
||
/// 切换时先更新内存状态,再写入持久化存储。
|
||
///
|
||
/// ## storage_sdk 接入步骤
|
||
///
|
||
/// 1. 在 `build()` 解开 TODO:读取存储值作为初始模式
|
||
/// 2. 在 `setMode()` 解开 TODO:每次切换后写入存储
|
||
/// 3. 若存储接口是异步的,将 `Notifier<ThemeMode>` 改为
|
||
/// `AsyncNotifier<ThemeMode>`,`build()` 改为 `Future<ThemeMode>`
|
||
class ThemeModeNotifier extends Notifier<ThemeMode> {
|
||
@override
|
||
ThemeMode build() {
|
||
// TODO: storage_sdk 就绪后从持久化读取初始值:
|
||
// final saved = ref.read(themeStorageProvider).readThemeMode();
|
||
// return saved ?? ThemeMode.system;
|
||
return ThemeMode.system;
|
||
}
|
||
|
||
void setMode(ThemeMode mode) {
|
||
state = mode;
|
||
// TODO: storage_sdk 就绪后写入持久化:
|
||
// ref.read(themeStorageProvider).saveThemeMode(mode);
|
||
}
|
||
}
|
||
|
||
/// 主题模式 Provider
|
||
///
|
||
/// ## Setting 页切换(只需一行)
|
||
///
|
||
/// ```dart
|
||
/// ref.read(themeModeProvider.notifier).setMode(ThemeMode.system);
|
||
/// ref.read(themeModeProvider.notifier).setMode(ThemeMode.light);
|
||
/// ref.read(themeModeProvider.notifier).setMode(ThemeMode.dark);
|
||
/// ```
|
||
///
|
||
/// ## 持久化(storage_sdk TODO)
|
||
///
|
||
/// 读取和写入的 TODO 均在 [ThemeModeNotifier] 内,接入 storage_sdk 后解开即可。
|
||
final themeModeProvider = NotifierProvider<ThemeModeNotifier, ThemeMode>(
|
||
ThemeModeNotifier.new,
|
||
);
|
||
|
||
// ── 启动初始化 ────────────────────────────────────────────────────────────────
|
||
|
||
/// AppInitializer Provider
|
||
///
|
||
/// 集中声明所有启动初始化任务,app.dart 只需一行 `.run()`。
|
||
///
|
||
/// ## 任务分类规则
|
||
///
|
||
/// 问自己:「这个任务不完成,用户能正常看到首页吗?」
|
||
/// - **不能** → 放 critical(谨慎,每多一个都拖慢启动)
|
||
/// - **能** → 放 deferred(绝大多数情况)
|
||
///
|
||
/// ## 当前任务清单
|
||
///
|
||
/// | 阶段 | 任务 | 说明 |
|
||
/// |---|---|---|
|
||
/// | Critical | NetworkMonitor | 后续 HTTP、WebSocket 都依赖网络状态 |
|
||
/// | Deferred | (待扩展) | 推送注册、登录态恢复、缓存预热等 |
|
||
final appInitializerProvider = Provider<AppInitializer>((ref) {
|
||
return AppInitializer(
|
||
onLog: (message, {tag}) {
|
||
// ignore: avoid_print
|
||
print('[${tag ?? 'AppInit'}] $message');
|
||
},
|
||
critical: [
|
||
// 网络监听必须最先就绪(后续 HTTP、WebSocket 都依赖它)
|
||
InitTask(
|
||
name: 'NetworkMonitor',
|
||
task: () => ref.read(networkMonitorProvider).initialize(),
|
||
),
|
||
],
|
||
deferred: [
|
||
// TODO: 推送注册
|
||
// InitTask(
|
||
// name: 'PushNotification',
|
||
// task: () => ref.read(pushServiceProvider).register(),
|
||
// ),
|
||
//
|
||
// TODO: 登录态恢复(从安全存储读取 token → 自动登录)
|
||
// InitTask(
|
||
// name: 'AuthRestore',
|
||
// task: () => ref.read(authRestoreUseCaseProvider).execute(),
|
||
// ),
|
||
//
|
||
// TODO: 缓存预热
|
||
// InitTask(
|
||
// name: 'CacheWarmup',
|
||
// task: () => ref.read(cacheServiceProvider).warmup(),
|
||
// ),
|
||
],
|
||
);
|
||
});
|