从 im-client-ios-swift-demo 搬运 Settings 逻辑,对齐 Gitea issue #5–#13 ## 基础设施 - AuthNotifier 新增 currentUid 字段,login() 接受 uid 参数 (#5) - LoginViewModel 登录成功后传入 user.uid - ApiPaths 补充 account/block/store 系列路径 - Tab 重命名"设置"→"我的",icon 改为 person_outline (#5) - AppRouteName 新增5条子路由 (edit-profile/blocklist/language/network-diagnostics/about) - app_router + auth_guard 同步注册新路由 ## Settings Feature - SettingsViewModel 重写为 NotifierProvider(去除 @riverpod 依赖) - build() 自动触发 loadProfile() - logout() 完整流程:API → WS 断开 → DB 关闭 → AuthNotifier - 6 个 navigateTo* 方法 - SettingsPage 完整 UI:资料卡 / 偏好设置 / 工具 / 关于 / 退出登录按钮 (#5 #7) - FetchProfileUseCase: GET /app/api/user/profile (#5) - LogoutUseCase: logout + disconnect + closeDatabase (#7) - UpdateProfileUseCase + UpdateProfileRequest: POST /app/api/user/update-profile (#6) - EditProfilePage + EditProfileViewModel: 昵称/bio 编辑 (#6) - LanguagePage: 语言选择 UI 框架,l10n_sdk 待接入 (#9) - BlocklistPage: 黑名单框架,API 待实现 (#10) - NetworkDiagnosticsPage + ViewModel: 四步诊断(连通/TCP/DNS/HTTPS)(#12) - AboutPage: 版本号 + 服务条款/隐私政策入口 (#13) - settings_providers.dart: 扩展 DI 装配 ## 文档 - Doc/mine_tab_architecture.md: 架构说明、数据流、路由、待完成事项 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
53 lines
1.9 KiB
Dart
53 lines
1.9 KiB
Dart
import 'package:go_router/go_router.dart';
|
||
|
||
import 'package:im_app/app/di/app_providers.dart';
|
||
import 'package:im_app/app/router/app_route_name.dart';
|
||
|
||
/// 登录守卫
|
||
///
|
||
/// 在 [GoRouter.redirect] 中调用,返回 null 表示放行,返回路径表示重定向目标。
|
||
/// 接收 [AuthNotifier] 而非 [Ref],避免守卫内部依赖 Riverpod,便于单测。
|
||
///
|
||
/// ## 穷举保护
|
||
///
|
||
/// 使用 [AppRouteName] 枚举 + switch 分析路由权限,Dart 编译器保证穷举:
|
||
/// 在 [AppRouteName] 新增枚举值后,此处 switch 未补 case 则编译报错。
|
||
///
|
||
/// ## 路由权限规则
|
||
///
|
||
/// | 路由 | 未登录 | 已登录 |
|
||
/// |------|--------|--------|
|
||
/// | login | 放行 | 重定向 → chat |
|
||
/// | 其余 | 重定向 → login | 放行 |
|
||
///
|
||
/// ## storage_sdk 接入后
|
||
///
|
||
/// 将 [AuthNotifier] 内的 Demo 状态替换为持久化 token,守卫本身无需改动。
|
||
String? authGuard(AuthNotifier authNotifier, GoRouterState state) {
|
||
final isLoggedIn = authNotifier.isLoggedIn;
|
||
final route = AppRouteName.fromPath(state.matchedLocation);
|
||
|
||
// 路径不在枚举中(理论上不应出现)→ 按受保护处理
|
||
if (route == null) return isLoggedIn ? null : AppRouteName.login.path;
|
||
|
||
switch (route) {
|
||
case AppRouteName.login:
|
||
// 已登录还在登录页 → 跳聊天页
|
||
return isLoggedIn ? AppRouteName.chat.path : null;
|
||
case AppRouteName.chat:
|
||
case AppRouteName.chatDetail:
|
||
case AppRouteName.chatDetailById:
|
||
case AppRouteName.contact:
|
||
case AppRouteName.settings:
|
||
case AppRouteName.settingsTheme:
|
||
case AppRouteName.settingsEditProfile:
|
||
case AppRouteName.settingsBlocklist:
|
||
case AppRouteName.settingsLanguage:
|
||
case AppRouteName.settingsNetworkDiagnostics:
|
||
case AppRouteName.settingsAbout:
|
||
case AppRouteName.chatDBTest:
|
||
// 受保护路由 → 未登录跳登录页
|
||
return isLoggedIn ? null : AppRouteName.login.path;
|
||
}
|
||
}
|