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

7.2 KiB
Raw Blame History

我的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 依赖:

class SettingsViewModel extends Notifier<SettingsState> { ... }

final settingsViewModelProvider = NotifierProvider<SettingsViewModel, SettingsState>(
  SettingsViewModel.new,
);

DI 链路:

settingsViewModelProvider
  └─ fetchProfileUseCaseProvider   → networkSdkApiProvider
  └─ logoutUseCaseProvider
       ├─ authRepositoryProvider   → networkSdkApiProvider
       ├─ socketManagerProvider
       └─ storageSdkProvider

6. 路由

新增 Shell 外全屏路由(parentNavigatorKey: _rootKeyTabBar 在子页面隐藏:

/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 ***XXXXbodySmall
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)

_IconBox36pt 圆角正方形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.bioGET /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_runnerUpdateProfileRequest 使用 @ApiRequest,需执行:
    cd apps/im_app && dart run build_runner build --delete-conflicting-outputs