Files
customer-im-client-dev/apps/im_app/lib/app/router/app_route_name.dart
pp-bot aeeda6f059 feat(mine): 我的 Tab 全量实现 (#5~#13)
从 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>
2026-03-23 17:20:51 +09:00

104 lines
4.3 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.
/// 应用路由枚举
///
/// 每个枚举值对应一个注册路由及其绝对路径。
///
/// ## 为什么用枚举而不是常量类
///
/// `auth_guard.dart` 对路由做 switch 分析Dart 的枚举 switch 是穷举的:
/// 新增路由时若没在 switch 里补 case编译器直接报错而不是等运行时漏掉。
///
/// ## 使用方式
///
/// ```dart
/// // 无参数导航
/// context.push(AppRouteName.settingsTheme.path);
/// context.go(AppRouteName.chat.path);
///
/// // 带参数导航extra 传对象,适合列表点入详情等已有数据的场景)
/// context.push(
/// AppRouteName.chatDetail.path,
/// extra: (conversationId: '42', title: '技术支持'),
/// );
///
/// // 带路径参数导航(路径中内嵌 id适合需要直接链接或分享的场景
/// context.push(AppRouteName.chatDetailByIdPath('99'));
///
/// // 路由表定义
/// GoRoute(path: AppRouteName.chat.path, ...)
/// ```
///
/// ## 注意:子路由 path 是相对路径片段
///
/// go_router 在子路由中使用相对路径片段(不含父路径前缀),
/// 这是框架规定,不是硬编码字符串:
/// ```dart
/// GoRoute(
/// path: AppRouteName.settings.path, // '/settings'
/// routes: [
/// GoRoute(path: AppRouteName.settingsTheme.segment, ...), // 'theme'
/// ],
/// )
/// ```
/// 导航时仍用 `AppRouteName.settingsTheme.path`,与枚举保持一致。
///
/// 子路由声明使用 [segment](相对路径片段),避免在路由表中硬编码字符串:
/// ```dart
/// GoRoute(path: AppRouteName.settingsTheme.segment, ...) // 'theme'
/// ```
///
/// ## 注意:含路径参数的路由
///
/// [chatDetailById] 的 [path] 包含占位符 `:id`,不能直接用于导航。
/// 导航时使用 [chatDetailByIdPath] 传入实际 id
/// ```dart
/// context.push(AppRouteName.chatDetailByIdPath('99'));
/// ```
enum AppRouteName {
// ── Tab 根路由 ────────────────────────────────────────────────────────────
chat('/chat'),
contact('/contact'),
settings('/settings'),
// ── Chat 子路由 ──────────────────────────────────────────────────────────
// extra: ({String conversationId, String title})
chatDetail('/chat/detail'),
// 路径参数形式:导航用 AppRouteName.chatDetailByIdPath(id),不直接用 .path
chatDetailById('/chat/:id'),
chatDBTest('/chat/dbTest'),
// ── Settings 子路由 ───────────────────────────────────────────────────────
settingsTheme('/settings/theme'),
settingsEditProfile('/settings/edit-profile'),
settingsBlocklist('/settings/blocklist'),
settingsLanguage('/settings/language'),
settingsNetworkDiagnostics('/settings/network-diagnostics'),
settingsAbout('/settings/about'),
// ── 全屏页面(无底部导航栏)──────────────────────────────────────────────
login('/login');
const AppRouteName(this.path);
/// 绝对路径,用于 [context.push] / [context.go] 导航及顶层路由表声明
///
/// 注意:[chatDetailById] 的 path 含占位符 `:id`,导航时用 [chatDetailByIdPath]。
final String path;
/// 相对路径片段path 的最后一段),用于 go_router 子路由的 [GoRoute.path] 声明
///
/// 例:`AppRouteName.settingsTheme.segment` → `'theme'`
String get segment => path.split('/').last;
/// 从绝对路径查找枚举值,路径未注册时返回 null
///
/// 注意:含路径参数的路由(如 `/chat/99`)无法匹配,返回 null
/// auth_guard 会按受保护路由处理(未登录重定向到登录页)。
static AppRouteName? fromPath(String path) =>
AppRouteName.values.where((r) => r.path == path).firstOrNull;
/// 生成 [chatDetailById] 的实际导航路径,将 `:id` 替换为真实 id
///
/// 例:`AppRouteName.chatDetailByIdPath('99')` → `'/chat/99'`
static String chatDetailByIdPath(String id) => '/chat/$id';
}