Files
customer-im-client-dev/Doc/mine_tab_architecture.md
pp-bot db10d1fcd2 feat(mine): 我的 Tab UI 重设计(#39~#41)
- ProfileHeroCard:72pt 渐变头像(8色 uid%8 主题)、@J{uid} handle、bio 简介、掩码手机号
- AppBar:compact,右侧 QR 图标 + 编辑铅笔
- 彩色图标行(_IconBox 36pt 圆角)+ 4 卡片组对齐 iOS SettingsView
  - 账户:我的钱包 / 账户安全
  - 工具:收藏 / 最近呼叫 / 链接设备 / 聊天文件夹
  - 偏好设置:通知和声音 / 隐私设置 / 黑名单 / 语言 / 主题
  - 关于:用户协议 / 隐私政策 / 版本号
- SettingsState 增加 bio 字段(#41),loadProfile 同步赋值
- Doc/mine_tab_architecture.md 补充 UI 重设计章节(§7)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 20:14:34 +09:00

215 lines
7.2 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#39#41UI 重设计)
> 参考实现:`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. UI 重设计(#39 / #40 / #41
### 7.1 ProfileHeroCard (#39 / #41)
| 元素 | 规格 |
|------|------|
| 头像 | 72pt 圆形;无头像时 8 色渐变占位uid%8 |
| 昵称 | fontWeight w700titleMedium |
| Handle | `@J{uid}`bodySmall onSurfaceVariant |
| 手机号 | 掩码 `+CC ***XXXX`bodySmall |
| Bio | 非空显示,为空显示「添加一句话简介」(斜体,半透明) |
| AppBar | compact右侧QR 图标 + 编辑铅笔 |
渐变色方案(`_ProfileHeroCard._gradients[uid.abs() % 8]`
```
0: [#4776E6, #8E54E9] 1: [#11998E, #38EF7D]
2: [#FC466B, #3F5EFB] 3: [#F7971E, #FFD200]
4: [#56CCF2, #2F80ED] 5: [#EB3349, #F45C43]
6: [#1FA2FF, #12D8FA] 7: [#9D50BB, #6E48AA]
```
### 7.2 彩色图标行与分组卡片 (#40)
`_IconBox`36pt 圆角正方形8pt白色图标iOS Settings 风格。
| 卡片组 | 菜单项 | 颜色 |
|--------|--------|------|
| 账户 | 我的钱包 | #FFAA5B |
| | 账户安全 | #8A5CF6 |
| 工具 | 收藏 | #FFAF45 |
| | 最近呼叫 | #4CB050 |
| | 链接设备 | #5667FF |
| | 聊天文件夹 | #F2994A |
| 偏好设置 | 通知和声音 | #FF8B5E |
| | 隐私设置 | #0BB8A9 |
| | 黑名单 | #FF4B4B |
| | 语言 | #5667FF |
| | 主题 | #8A5CF6 |
| 关于 | 用户协议 | gray |
| | 隐私政策 | gray |
| | 版本号(静态)| gray无 chevron |
### 7.3 SettingsState bio 字段 (#41)
- `SettingsState.bio: String`(默认 `''`
- `SettingsViewModel.loadProfile()` 赋值 `bio: profile.bio`
- 数据来源:`ProfileResponse.bio``GET /app/api/user/profile`
---
## 8. 待完成事项
- **#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
```