依据 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>
1605 lines
23 KiB
Markdown
1605 lines
23 KiB
Markdown
# 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 客户端。** |