Files
customer-im-client-dev/apps/im_app/lib/app/di/app_providers.dart
2026-03-09 09:06:39 +08:00

147 lines
5.5 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
// TODO: 接入 cipher_guard_sdk 后,在此处完成 RSA 密钥注入:
// 1. 从安全存储keychain / secure storage读取公私钥对只读一次
// 2. cipherSdk.setActiveKeyPair(publicKey: pubPem, privateKey: privPem)
// 须在 notifyListeners() 之前完成,确保路由跳转后 onEncryptRequest 回调触发时密钥已就绪。
notifyListeners();
}
void logout() {
_isLoggedIn = false;
// TODO: 接入 cipher_guard_sdk 后,退出登录时清除内存密钥:
// cipherSdk.clearActiveKeyPair()
// cipherSdk.clearDerivedKeyCache()
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(),
// ),
],
);
});