import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:im_app/core/foundation/device_info.dart'; import 'package:im_app/core/services/app_initializer.dart'; import 'package:im_app/app/di/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((ref) => AuthNotifier()); // ── 主题 ────────────────────────────────────────────────────────────────────── /// 主题模式 Notifier — 控制应用全局亮 / 暗主题 /// /// 启动时从持久化存储读取上次保存的主题模式,无则默认跟随系统。 /// 切换时先更新内存状态,再写入持久化存储。 /// /// ## storage_sdk 接入步骤 /// /// 1. 在 `build()` 解开 TODO:读取存储值作为初始模式 /// 2. 在 `setMode()` 解开 TODO:每次切换后写入存储 /// 3. 若存储接口是异步的,将 `Notifier` 改为 /// `AsyncNotifier`,`build()` 改为 `Future` class ThemeModeNotifier extends Notifier { @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.new, ); // ── 启动初始化 ──────────────────────────────────────────────────────────────── /// AppInitializer Provider /// /// 集中声明所有启动初始化任务,app.dart 只需一行 `.run()`。 /// /// ## 任务分类规则 /// /// 问自己:「这个任务不完成,用户能正常看到首页吗?」 /// - **不能** → 放 critical(谨慎,每多一个都拖慢启动) /// - **能** → 放 deferred(绝大多数情况) /// /// ## 当前任务清单 /// /// | 阶段 | 任务 | 说明 | /// |---|---|---| /// | Critical | NetworkMonitor | 后续 HTTP、WebSocket 都依赖网络状态 | /// | Deferred | (待扩展) | 推送注册、登录态恢复、缓存预热等 | final appInitializerProvider = Provider((ref) { return AppInitializer( onLog: (message, {tag}) { // ignore: avoid_print print('[${tag ?? 'AppInit'}] $message'); }, critical: [ // 网络监听必须最先就绪(后续 HTTP、WebSocket 都依赖它) InitTask( name: 'NetworkMonitor', task: () => ref.read(networkMonitorProvider).initialize(), ), // 预取设备 ID / 设备名,platformHeaders 同步读取 InitTask( name: 'DeviceInfo', task: DeviceInfo.init, ), ], 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(), // ), ], ); });