Files
customer-im-client-dev/Doc/mine_tab_architecture.md
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

165 lines
5.7 KiB
Markdown
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.
# 我的MineTab — 架构文档
> 对应 Gitea issues #5#13
> 参考实现:`im-client-ios-swift-demo` Features/Settings + Features/Profile
---
## 1. 功能范围
| Issue | 功能 | 状态 |
|-------|------|------|
| #5 | Tab 重命名 & 个人资料卡片 | ✅ 已实现 |
| #6 | 编辑个人资料(昵称/bio/头像) | ✅ 框架已建CDN 上传待 #6 后续) |
| #7 | 退出登录 | ✅ 已实现 |
| #8 | 主题持久化 | ⏳ TODO解开 ThemeModeNotifier 注释) |
| #9 | 语言设置 | ✅ UI 框架l10n_sdk 待接入) |
| #10 | 黑名单管理 | ✅ 页面框架API 待实现) |
| #11 | 聊天文件夹 | ⏳ TODO stub |
| #12 | 网络诊断 | ✅ 已实现4步诊断 |
| #13 | 关于 / 版本 | ✅ 已实现 |
---
## 2. 目录结构
```
features/settings/
├── di/
│ └── settings_providers.dart # UseCase DI 装配
├── presentation/
│ ├── settings_view_model.dart # 我的页 ViewModel (NotifierProvider)
│ ├── edit_profile_view_model.dart # 编辑资料 ViewModel
│ ├── network_diagnostics_view_model.dart # 网络诊断 ViewModel
│ └── theme_view_model.dart # 主题 ViewModel (@riverpod)
├── usecases/
│ ├── fetch_profile_usecase.dart # GET /app/api/user/profile
│ ├── update_profile_usecase.dart # POST /app/api/user/update-profile
│ ├── logout_usecase.dart # POST /app/api/auth/logout + WS + DB
│ └── set_theme_usecase.dart # 幂等主题切换
└── view/
├── settings_page.dart # 我的主页
├── edit_profile_page.dart # 编辑资料页
├── language_page.dart # 语言选择页
├── blocklist_page.dart # 黑名单页(框架)
├── network_diagnostics_page.dart # 网络诊断页
├── about_page.dart # 关于页
├── theme_view.dart # 主题选择页
└── widgets/
├── settings_section_header.dart
└── theme_option_tile.dart
data/remote/
├── get_profile_request.dart # GET /app/api/user/profile已有
└── update_profile_request.dart # POST /app/api/user/update-profile新增
```
---
## 3. 数据流
### 3.1 资料加载
```
SettingsPage (build)
└─ ref.watch(settingsViewModelProvider)
└─ SettingsViewModel.build()
└─ Future.microtask(loadProfile)
└─ FetchProfileUseCase.execute()
└─ NetworksSdkApi.executeRequest(GetProfileRequest())
└─ GET /app/api/user/profile (JWT token in header)
└─ ProfileResponse → SettingsState {nickname, avatarUrl, maskedContact, uid}
```
### 3.2 退出登录
```
SettingsPage._confirmLogout()
└─ AlertDialog confirm
└─ SettingsViewModel.logout()
├─ LogoutUseCase.execute()
│ ├─ AuthRepository.logout() → POST /app/api/auth/logout
│ ├─ SocketManager.disconnect() → 断开 WebSocket
│ └─ StorageSdkLifecycle.closeDatabase()
└─ AuthNotifier.logout() → go_router 重定向 /login
```
### 3.3 编辑资料保存
```
EditProfilePage → 保存按钮
└─ EditProfileViewModel.save()
└─ UpdateProfileUseCase.execute(nickname, bio, profilePicUrl)
└─ NetworksSdkApi.executeRequest(UpdateProfileRequest)
└─ POST /app/api/user/update-profile
└─ SettingsViewModel.loadProfile() (刷新资料卡)
```
---
## 4. API 端点
| 操作 | Method | Path |
|------|--------|------|
| 获取当前用户资料 | GET | `/app/api/user/profile` |
| 更新用户资料 | POST | `/app/api/user/update-profile` |
| 退出登录 | POST | `/app/api/auth/logout` |
| 黑名单列表(待实现) | GET | `/app/api/account/block/list` |
| 解除拉黑(待实现) | POST | `/app/api/account/block/remove` |
| 聊天文件夹(待实现) | POST | `/app/api/account/store/get-store` |
---
## 5. Provider 设计
所有 Settings ViewModel 使用 `Notifier<T>` + 手动 `NotifierProvider`**不使用 `@riverpod` 代码生成**,避免额外 build_runner 依赖:
```dart
class SettingsViewModel extends Notifier<SettingsState> { ... }
final settingsViewModelProvider = NotifierProvider<SettingsViewModel, SettingsState>(
SettingsViewModel.new,
);
```
DI 链路:
```
settingsViewModelProvider
└─ fetchProfileUseCaseProvider → networkSdkApiProvider
└─ logoutUseCaseProvider
├─ authRepositoryProvider → networkSdkApiProvider
├─ socketManagerProvider
└─ storageSdkProvider
```
---
## 6. 路由
新增 Shell 外全屏路由(`parentNavigatorKey: _rootKey`TabBar 在子页面隐藏:
```
/settings/edit-profile EditProfilePage
/settings/blocklist BlocklistPage
/settings/language LanguagePage
/settings/network-diagnostics NetworkDiagnosticsPage
/settings/about AboutPage
/settings/theme ThemeView原有
```
认证守卫 `auth_guard.dart` switch 已补全上述路由。
---
## 7. 待完成事项
- **#6 头像上传**:接入 CDN upload参考 iOS CDN 流程)
- **#8 主题持久化**:解开 `ThemeModeNotifier.build()``setMode()` 中的 TODO
- **#10 黑名单 API**:实现 `FetchBlocklistUseCase` + `UnblockUseCase`
- **#11 聊天文件夹**`ChatCategoryViewModel` + `account/store` API
- **build_runner**`UpdateProfileRequest` 使用 `@ApiRequest`,需执行:
```bash
cd apps/im_app && dart run build_runner build --delete-conflicting-outputs
```