Files
customer-im-client-dev/Doc/mine_tab_architecture.md
pp-bot 8d5059add1 docs(mine-tab): 更新架构文档 — 编辑资料完整实现(#49/#50)
- §3 补充头像上传(3.3)和保存(3.4)数据流
- §8 新增编辑资料 UI 规格表
- §9 更新待完成事项(#6 已关闭)

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

240 lines
8.5 KiB
Markdown
Raw Permalink 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 重设计),#49#50编辑资料完整实现
> 参考实现:`im-client-ios-swift-demo` Features/Settings + Features/Profile
---
## 1. 功能范围
| Issue | 功能 | 状态 |
|-------|------|------|
| #5 | Tab 重命名 & 个人资料卡片 | ✅ 已实现 |
| #6 | 编辑个人资料(昵称/bio/头像) | ✅ 全量实现(#49/#50 补全头像上传) |
| #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 编辑资料 — 头像上传(#49
```
EditProfilePage._showAvatarSourceSheet()
└─ BottomSheet → 相册 / 拍照
└─ EditProfileViewModel.pickAndUploadAvatar(ImageSource)
├─ ImagePicker.pickImage(source, maxWidth:900, maxHeight:900, quality:85)
├─ ImageCropper.cropImage(1:1, IOSUiSettings / AndroidUiSettings)
├─ state.isUploadingAvatar = true
├─ NetworksSdkApi.executeRequest(UploadFileRequest(filePath))
│ └─ POST /app/api/upload/file FormData multipart
│ └─ UploadResult.url
└─ state.avatarUrl = url UI 实时预览更新)
```
### 3.4 编辑资料保存(#50
```
EditProfilePage → 保存按钮nickname.isNotEmpty && !isUploadingAvatar
└─ EditProfileViewModel.save()
└─ UpdateProfileUseCase.execute(nickname, bio, profilePicUrl)
└─ NetworksSdkApi.executeRequest(UpdateProfileRequest)
└─ POST /app/api/user/update-profile
└─ SettingsViewModel.loadProfile() (刷新资料卡)
└─ Navigator.pop()
```
---
## 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. 编辑资料 UI 设计(#49 / #50
| 元素 | 规格 |
|------|------|
| 头像 | 88pt 圆形;无头像时 8 色渐变占位;右下 28pt 相机角标primary色 |
| 上传进度 | CircularProgressIndicator 环绕头像isUploadingAvatar=true 时显示 |
| 选图 Sheet | BottomSheet从相册选取 / 拍照16pt 圆角,拖动条 |
| 昵称字段 | Card 分组,`x/50` 右侧计数maxLength:50 |
| 简介字段 | Card 分组,`x/200` 右侧计数maxLines:null自动展开maxLength:200 |
| 保存按钮 | AppBar 右侧 TextButton昵称为空或上传中时 disabled |
| 错误 Banner | errorContainer 色圆角卡片,⚠️ 图标 + 文本 |
---
## 9. 待完成事项
- **#8 主题持久化**:解开 `ThemeModeNotifier.build()``setMode()` 中的 TODO
- **#10 黑名单 API**:实现 `FetchBlocklistUseCase` + `UnblockUseCase`
- **#11 聊天文件夹**`ChatCategoryViewModel` + `account/store` API