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