Files
ts-mobile-go/docs/TS Mobile UI UX 重构设计规范.md
sansenandClaude Fable 5 8716b391f6 工程改进:跨语言契约固化、日志脱敏、状态模型收敛
依据 docs/项目工程改进方案.md 实施(第五梯队 CI/协作除外)。

安全性
- Release 剥离 Log.v/d/i/w(-assumenosideeffects),保留 Log.e
- 全量频道/成员 dump、消息正文、发送者 UID 改为 BuildConfig.DEBUG 保护
  (实测 release dex 中 "Channel: id=" / "Client: id=" / selfId= 等均为 0 命中)

构建产物体积
- .gitignore 补 *.a(保留 .opus/lib 四个 ABI 预编译库)、.opus/install、
  app/libs/*.aar、dnn/torch
- git rm --cached 除名 AAR、.gradle、.opus/{build,install}、dnn/torch
  跟踪体积 50MB → 17.4MB,工作区文件不受影响

跨语言契约(本方案核心)
- 新增 go/teamspeak/contract.go:字段名常量 + BridgeContractVersion 单一事实来源
- 新增契约测试:反射断言常量与 struct tag 一致;Go/Kotlin 共用 golden 样本
- 新增 BridgeContract.kt:启动校验 AAR 契约版本,不匹配则阻止连接
- 修正文档:channel_order 是前驱频道 ID(链表指针)而非排序权重,
  按它数值排序会打乱频道树;ChannelInfo.order 在 Go 侧不存在

状态模型
- ConnectionState 增 Idle 取代 null 编码,connectionState 不再可空
- applyClients 改为按频道差分更新,避免全量刷新导致频道树整体重组
- 频道数据 freshness 统一由 Repository 维护,修复 ViewModel 与 Repository
  两份时间戳不同步导致的重复刷新

UI
- 修复 collectAsState() 在参数位置调用导致的 isSelf 快照失效
- 消除 9 处 !! 断言(ChannelListScreen)
- 硬编码 24.5/14.5dp 与 depth*24 收敛到 UiTokens.Spacing,缩进加 4 层上限

测试
- Kotlin 测试 7 → 106;Go 契约测试新增 24 个用例
- 各覆盖 InputValidator、消息送达确认、僵尸会话过滤、频道差分、
  频道顺序语义、错误分类

其他修复
- classifyError 提取为纯函数并补测试;修复 too many clones (id=521)
  未识别导致英文原文直接暴露给用户

版本号提升至 1.0.13(versionCode 13)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-10 14:58:15 +08:00

1605 lines
23 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.
# TS Mobile UI / UX 重构设计规范
## 1. 文档目标
本文档用于指导 TS Mobile Android 客户端下一阶段 UI / UX 重构。
重构目标不是简单地:
- 修改颜色
- 增加圆角
- 增加动画
- 更换 Material 组件
- 美化现有页面
而是重新建立一套符合 TeamSpeak 使用模型的移动端信息架构。
核心目标:
> 让用户始终清楚自己连接到了哪个服务器、当前处于哪个频道、频道里有哪些成员,以及当前语音和聊天状态。
------
# 2. 核心产品模型
TeamSpeak 与普通聊天软件最大的区别之一,是:
> 用户连接服务器后,会直接处于某个频道上下文中。
因此 TS Mobile 不应该建立:
```text
服务器
↓
进入频道
```
这样的用户流程。
正确模型:
```text
未连接
↓
连接服务器
↓
已连接 + 已进入频道
↓
服务器工作空间
```
连接成功后:
```text
Server
└── Current Channel
├── Chat
├── Members
└── Voice
```
因此:
**Current Channel 是整个 App 最重要的上下文状态。**
------
# 3. 顶层状态模型
建议 UI 层只暴露三个主要状态:
```text
Disconnected
↓
Connecting
↓
Connected
```
其中:
### Disconnected
没有连接服务器。
显示:
- Logo
- Server Address
- Nickname
- Password
- Recent Servers
- Connect
### Connecting
连接服务器过程中。
这是连接流程中的 Loading 状态,而不是独立产品页面。
可以显示:
```text
Connecting...
server.example.com:9987
```
### Connected
连接成功后直接进入当前频道。
```text
Server
Current Channel
Chat / Channels
Voice
Members
```
不应该存在:
```text
Connected but no channel
```
这样的普通 UI 状态。
------
# 4. 产品信息架构
最终信息架构:
```text
TS Mobile
│
├── Connection
│ ├── Connect
│ ├── Connecting
│ └── Disconnected
│
└── Server Space
│
├── Server Header
│
├── Current Channel
│
├── Chat
│
├── Channels
│ ├── Channel Tree
│ └── Channel Members
│
├── Voice
│
└── Server Drawer
├── Server Info
├── Voice Settings
├── Notifications
├── Appearance
└── Disconnect
```
------
# 5. Server Space
连接成功后,整个 App 进入一个统一的:
> Server Space
而不是分别进入:
```text
ChannelScreen
ChatScreen
VoiceScreen
```
这些功能都属于当前 Server Space。
推荐结构:
```text
┌────────────────────────────┐
│ Server Header │
├────────────────────────────┤
│ │
│ │
│ Current Content │
│ │
│ │
├────────────────────────────┤
│ Current Channel │
├────────────────────────────┤
│ Chat Channels │
└────────────────────────────┘
```
------
# 6. Server Header
Server Header 负责展示服务器上下文。
推荐:
```text
┌────────────────────────────┐
│ ☰ My Server ⋮ │
│ ● Connected · 12 online│
└────────────────────────────┘
```
包含:
- Server Name
- Connection Status
- Online Count
- Navigation / Drawer
- More
不建议长期显示:
```text
server.example.com:9987
```
服务器地址属于 Server Detail。
------
# 7. Current Channel Context Bar
这是本次重构最重要的 UI 组件之一。
它不是普通 Card。
它是:
> 当前通信上下文。
推荐:
```text
┌────────────────────────────┐
│ # General 12 │
│ ● ● ● ● +8 │
└────────────────────────────┘
```
显示:
- Channel Name
- Channel Type
- Member Count
- 少量成员头像
- 当前语音状态
例如:
```text
# General
12 members
● ● ● ● +8
```
用户切换频道后:
```text
# General
```
直接变成:
```text
# Gaming
```
同时:
- Chat 改变
- Members 改变
- Voice Context 改变
------
# 8. Chat / Channels 导航
推荐保留底部双 Tab:
```text
┌────────────────────────────┐
│ │
│ Main Content │
│ │
├────────────────────────────┤
│ # General 12 │
├────────────────────────────┤
│ Chat Channels │
└────────────────────────────┘
```
但需要明确:
> Chat / Channels 是视图,不是产品实体。
真正的实体关系:
```text
Server
└── Current Channel
├── Chat
└── Members / Channel Tree
```
------
# 9. Chat
Chat 是当前频道的文字消息流。
推荐布局:
```text
┌────────────────────────────┐
│ # General 12 │
├────────────────────────────┤
│ │
│ Alex │
│ Hello │
│ │
│ Tom │
│ Anyone playing? │
│ │
│ Alex │
│ Let's go │
│ │
├────────────────────────────┤
│ + Message... ↑ │
└────────────────────────────┘
```
------
# 10. Chat 消息设计
不建议过度模仿:
- WhatsApp
- Telegram
- Discord
TeamSpeak 更适合:
> 紧凑型实时频道消息流。
连续消息建议合并:
```text
Alex
Hello
Anyone playing?
Let's go
```
而不是:
```text
Alex Hello
Alex Anyone playing?
Alex Let's go
```
这样可以明显减少垂直空间消耗。
------
# 11. Chat 输入框
推荐:
```text
┌────────────────────────────┐
│ + Message... ↑ │
└────────────────────────────┘
```
输入区域保持较大的触控高度。
不要把:
- Emoji
- 文件
- 图片
- 语音
- 更多
- 格式化
全部放到一级 UI。
TeamSpeak 的文字聊天不是核心功能。
------
# 12. Channels
Channels 页面负责:
> 浏览服务器结构 + 查看成员。
推荐:
```text
CHANNELS
▼ Lobby 5
● Alice
● Bob
▼ General 12
● Tom
● Alex
● Mike
▶ Gaming 8
▶ Music 3
▶ AFK 2
```
频道节点应该保持紧凑。
------
# 13. Channel Item
频道 Item 推荐包含:
```text
[展开] [频道类型] [名称] [人数]
```
例如:
```text
▼ 🎙 General 12
```
避免在频道 Item 内塞入过多状态。
详细信息通过:
> Channel Detail
查看。
------
# 14. Current Channel 与 Channel Tree 的关系
频道树中的当前频道应该具有明显但克制的选中状态。
例如:
```text
▶ Lobby
▼ General 12
● Alex
● Tom
▶ Gaming 8
```
当前频道:
```text
General
```
可以使用:
- Surface 提升
- Primary 色边
- Icon 高亮
但不要使用非常强烈的纯色块。
------
# 15. Member Item
成员列表推荐:
```text
[Avatar] Alex
● Online
```
如果正在说话:
```text
[Avatar] Alex
● Speaking
```
但正常状态不要一直显示文字。
推荐使用:
```text
Avatar
+
Status Indicator
+
Nickname
```
------
# 16. Member 状态系统
至少定义:
```text
Online
Idle
Away
Muted
Deafened
Speaking
Server Muted
Disconnected
```
其中:
> Speaking
是最重要的实时状态。
可以通过:
- Avatar Ring
- 状态点
- 小型音量指示器
表达。
避免大面积动态动画。
------
# 17. Member Action
成员操作统一进入 Action Menu。
推荐:
```text
Alex
Interaction
Poke
Information
Copy Nickname
Copy UID
Management
Move
Kick from Channel
Kick from Server
```
危险操作单独处理。
例如:
```text
Kick from Server
```
需要二次确认。
------
# 18. Voice
Voice 不应该成为独立一级页面。
它属于:
```text
Current Channel
└── Voice
```
因此:
```text
Current Channel = General
```
意味着:
```text
Voice Context = General
```
切换:
```text
General → Gaming
```
Voice Context 同时切换。
------
# 19. Voice UI
推荐将语音设计成一个状态组件。
### Connected
```text
┌────────────────────────────┐
│ 🎙 General 12 │
│ ● Connected │
│ │
│ [ PTT ] │
│ │
│ Mic Speaker│
└────────────────────────────┘
```
### Speaking
```text
┌────────────────────────────┐
│ 🎙 General 12 │
│ │
│ [ SPEAKING ] │
│ │
└────────────────────────────┘
```
PTT 是语音 UI 的核心操作。
------
# 20. PTT 状态
PTT 至少存在:
```text
Idle
↓
Pressed
↓
Speaking
```
反馈必须:
- 快
- 明确
- 稳定
- 低干扰
不建议加入复杂粒子效果或大面积动画。
------
# 21. Server Drawer
Server Drawer 的职责:
> 管理当前服务器。
不是简单的服务器详情卡。
推荐:
```text
┌────────────────────────────┐
│ Server │
│ │
│ My Server │
│ ● Connected │
│ │
├────────────────────────────┤
│ Server Info │
│ server.example.com:9987 │
│ 12 / 64 online │
├────────────────────────────┤
│ Voice │
│ Notifications │
│ Appearance │
│ Settings │
├────────────────────────────┤
│ │
│ Disconnect │
└────────────────────────────┘
```
------
# 22. Server Detail
Server Detail 可以展示:
```text
Server Name
Address
Port
Version
Online Users
Max Users
Connection Quality
```
但这些信息不应该占用主界面。
------
# 23. Connection Screen
连接页是唯一真正意义上的“未连接 UI”。
推荐:
```text
TS Mobile
Connect to your TeamSpeak server
Server address
┌────────────────────────────┐
│ server.example.com │
└────────────────────────────┘
Port
┌────────────────────────────┐
│ 9987 │
└────────────────────────────┘
Nickname
┌────────────────────────────┐
│ Player │
└────────────────────────────┘
[ Connect ]
Recent Servers
```
------
# 24. Recent Servers
如果存在历史连接:
```text
Recent Servers
┌────────────────────────────┐
│ My Server │
│ server.example.com:9987 │
│ › │
└────────────────────────────┘
┌────────────────────────────┐
│ Community Server │
│ ts.example.net:9987 │
│ › │
└────────────────────────────┘
```
最近连接应该成为高频入口。
首次使用才重点展示完整 Connect Form。
------
# 25. Connecting
Connecting 不建议做成长期存在的独立页面。
推荐:
```text
TS Mobile
◯
Connecting...
server.example.com:9987
Cancel
```
连接完成:
```text
直接进入 Server Space
```
而不是:
```text
Connecting
→ Connected
→ Select Channel
```
------
# 26. Disconnect
Disconnect 后:
```text
Server Space
↓
Disconnected
↓
Connection Screen
```
重新连接:
```text
Connect
↓
Connecting
↓
Current Channel
```
------
# 27. Channel Switch
用户点击频道:
```text
General
```
切换:
```text
Gaming
```
本质上只是:
```text
currentChannelId
```
发生变化。
UI 同步更新:
```text
Current Channel
Chat
Members
Voice
```
不应该把它理解为:
```text
Navigation → New Page
```
而应该是:
```text
Context → New Channel
```
------
# 28. Bottom Sheet / Dialog / Drawer 职责
项目中已经存在多种 Sheet、Dialog、Card。
需要建立明确规则。
### Page
用于主要任务。
```text
Connect
Chat
Channels
```
### Drawer
用于全局导航和 Server 控制。
```text
Server
Settings
Disconnect
```
### Bottom Sheet
用于当前上下文详情。
```text
Channel Detail
Member Detail
Voice Detail
```
### Dialog
用于:
```text
确认
危险操作
输入
```
避免出现:
```text
BottomSheet
↓
Dialog
↓
BottomSheet
```
这种复杂交互链。
------
# 29. Design Token
建议继续强化现有:
```text
Color
Shapes
Theme
Type
UiTokens
```
体系。
统一定义:
```text
Spacing
xs = 4dp
sm = 8dp
md = 12dp
lg = 16dp
xl = 24dp
```
------
# 30. Radius
建议:
```text
List Item 8~12dp
Card 12~16dp
Floating Card 16~20dp
Bottom Sheet 24dp
Avatar Circle
```
不要所有组件统一 24dp。
圆角本身应该承担层级表达作用。
------
# 31. 控件尺寸
建议建立固定 Control Token:
```text
Small Button
40dp
Normal Button
48dp
Input
52dp
List Item
52~56dp
Avatar Small
32dp
Avatar Medium
40dp
Avatar Large
56dp
```
避免大量:
```text
14.5dp
17dp
24.5dp
```
这种局部修正值。
如果确实需要特殊值,应有明确视觉原因。
------
# 32. Typography
推荐建立:
```text
Title
16~20sp / Bold
Body
14~16sp / Regular
Secondary
12~14sp / Regular
Caption
11~12sp / Regular
```
移动端不要大量使用过小文字。
尤其:
- Channel Name
- Nickname
- Message
必须优先保证可读性。
------
# 33. Semantic Colors
不要让每个组件自己定义颜色。
统一语义:
```text
Primary
Accent
Success
Warning
Error
Muted
Disabled
Speaking
```
例如:
```text
Connected
→ Success
Speaking
→ Accent
Reconnecting
→ Warning
Disconnected
→ Error
```
------
# 34. 状态视觉规范
状态优先级:
```text
Connected
↓
Current Channel
↓
Speaking
↓
Other User States
```
越重要的状态,视觉反馈越明显。
但不要同时让多个状态都高亮。
------
# 35. 动画规范
动画不应该成为 UI 主体。
优先:
```text
状态变化动画
```
而不是:
```text
页面切换动画
```
推荐:
- Channel selected
- Speaking
- PTT pressed
- Connection state
- Reconnect banner
使用短时、低幅度动画。
------
# 36. 视觉风格
最终建议采用:
```text
Modern
Flat
Native
Compact
Readable
Low Decoration
```
不是:
```text
Discord Clone
```
也不是:
```text
Material 3 Demo
```
而是:
> Modern Native Communication Client
------
# 37. 推荐视觉层级
整体控制为:
```text
Background
↓
Surface
↓
Elevated Surface
↓
Primary Action
```
例如:
```text
Background
页面背景
Surface
Chat / Channel List
Elevated Surface
Current Channel / Voice
Primary
Connect / PTT / Send
```
不要给每一个组件增加独立背景。
------
# 38. 主页面最终结构
最终推荐:
```text
┌─────────────────────────────┐
│ ☰ My Server ⋮ │
│ ● Connected · 12 online │
├─────────────────────────────┤
│ │
│ # General 12 │
│ ● ● ● ● +8 │
│ │
├─────────────────────────────┤
│ │
│ │
│ Chat Content │
│ │
│ │
├─────────────────────────────┤
│ + Message... ↑ │
├─────────────────────────────┤
│ Chat Channels │
└─────────────────────────────┘
```
Channels:
```text
┌─────────────────────────────┐
│ ☰ My Server ⋮ │
│ ● Connected · 12 online │
├─────────────────────────────┤
│ # General 12 │
├─────────────────────────────┤
│ CHANNELS │
│ │
│ ▼ Lobby 5 │
│ ● Alice │
│ ● Bob │
│ │
│ ▼ General 12 │
│ ● Alex │
│ ● Tom │
│ │
│ ▶ Gaming 8 │
│ ▶ Music 3 │
│ ▶ AFK 2 │
├─────────────────────────────┤
│ Chat Channels │
└─────────────────────────────┘
```
------
# 39. UI 组件层级
建议最终组件结构:
```text
App
│
└── ServerSpace
│
├── ServerHeader
│
├── CurrentChannelBar
│
├── Content
│ ├── ChatView
│ │ ├── MessageList
│ │ └── MessageInput
│ │
│ └── ChannelsView
│ ├── ChannelTree
│ └── MemberList
│
├── VoiceStatus
│
├── BottomNavigation
│
└── ServerDrawer
```
------
# 40. 推荐代码重构方向
现有代码已经有:
```text
AppTopBar
MessageInputBar
VoiceCard
VoiceControlBar
ServerDetailCard
ClientActionMenu
```
下一阶段建议进一步抽象为:
```text
ui/components/
│
├── server/
│ ├── ServerHeader
│ ├── ServerDrawer
│ └── ServerStatus
│
├── channel/
│ ├── CurrentChannelBar
│ ├── ChannelTree
│ ├── ChannelItem
│ └── ChannelDetail
│
├── client/
│ ├── ClientItem
│ ├── ClientAvatar
│ ├── ClientStatus
│ └── ClientActionMenu
│
├── chat/
│ ├── MessageList
│ ├── MessageItem
│ └── MessageInput
│
└── voice/
├── VoiceStatus
├── PTTButton
└── VoiceControl
```
这样比继续按照 Screen 切组件更加容易维护。
------
# 41. ViewModel 状态建议
UI 最终应该围绕一个核心 Server Space 状态:
```text
ServerSpaceState
connectionState
server
currentChannel
channels
clients
chatMessages
voiceState
```
其中:
```text
currentChannel
```
是核心状态。
UI 不应该自己维护多个互相独立的:
```text
selectedChannel
voiceChannel
chatChannel
memberChannel
```
否则很容易出现状态不同步。
应该:
```text
currentChannelId
```
作为统一来源。
------
# 42. P0 重构优先级
## P0-1
重新定义 Server Space。
目标:
```text
Connected
↓
Current Channel
```
作为整个 App 的核心模型。
------
## P0-2
重构:
```text
CurrentChannelBar
```
让它成为全局 Context Bar。
------
## P0-3
重新整理:
```text
Chat
Channels
```
两个 Tab 的关系。
------
## P0-4
重构:
```text
Voice
PTT
Voice Status
```
让它们绑定 Current Channel。
------
## P0-5
统一:
```text
Server Header
Server Drawer
```
------
# 43. P1
完成:
```text
Channel Tree
Member Item
Member Detail
Channel Detail
Recent Servers
Server Settings
```
并统一 Sheet / Dialog / Drawer。
------
# 44. P2
最后处理:
```text
Animation
Gesture
Motion
Micro Interaction
Advanced Voice Feedback
```
------
# 45. 最终设计原则
TS Mobile 的 UI 应该始终遵循以下五条原则:
## 1. Server 是工作空间
连接服务器以后,用户进入 Server Space。
## 2. Current Channel 是核心上下文
所有通信行为围绕当前频道。
## 3. Chat / Channels 是视图
它们不是两个独立产品页面。
## 4. Voice / Members / Chat 都绑定 Current Channel
切换频道意味着整个通信上下文切换。
## 5. UI 优先表达状态,而不是装饰
用户第一眼应该知道:
```text
Server
Current Channel
Members
Voice State
Chat
```
而不是看到:
```text
圆角
阴影
动画
渐变
装饰
```
------
# 46. 最终目标
最终用户打开 TS Mobile 后:
```text
第一次使用
↓
连接服务器
↓
直接进入服务器默认 / 当前频道
↓
看到当前频道
↓
可以聊天
↓
可以查看频道树
↓
可以看到成员
↓
可以进行语音通信
```
整个过程中不应该出现多余的:
```text
服务器主页
选择频道
进入频道
频道主页
聊天主页
语音主页
```
而应该保持一个稳定的模型:
```text
Server
+
Current Channel
+
Current View
```
其中:
```text
Current View =
Chat
or
Channels
```
这是 TS Mobile 最适合移动端的 UI / UX 核心架构。
------
# 47. 一句话定义
如果最终需要给这个 UI 架构定一句设计原则:
> **TS Mobile 不是“服务器列表 + 聊天 + 频道 + 语音”的功能集合,而是一个以 Server 为工作空间、以 Current Channel 为核心上下文的移动 TeamSpeak 客户端。**