Files
sing-android/REDESIGN.md
Sing Dev 1106f61cf0 Add CommandReceiver for adb control, fix tailscale routing
- CommandReceiver: exported broadcast receiver for adb CLI control
  - start/stop/status/set_config commands
  - Usage: adb shell am broadcast -a com.sing.vpn.CMD -n com.sing.vpn/.CommandReceiver --es cmd start
- SingConfig: add controlplane.tailscale.com → direct route rule
  to prevent tailnet control traffic from going through proxy
2026-04-02 15:31:15 +08:00

308 lines
15 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.
# Android UI Redesign — Linear Style
## Design Language
参考 Linear.app 的设计语言:极简、高信息密度、深色主题、无多余装饰。
告别"VPN 大圆按钮"的传统模板,走向工具型产品的质感。
## 核心原则
1. **信息密度优先** — 一屏展示最多有效信息,不浪费空间在装饰元素上
2. **深色主题** — Linear 标志性的深灰背景 + 高对比度文字
3. **微妙的层次** — 通过 subtle 的背景色差区分区域,不用卡片阴影
4. **Monospace 数据** — IP、延迟、流量等技术数据用等宽字体
5. **无圆角按钮** — 操作通过 inline 文字按钮或 icon 触发
6. **状态用颜色** — 绿色=在线/连接,黄色=警告,红色=断开/错误,紫色=品牌色
## 色板
```
Background: #0D0D0D (接近纯黑)
Surface: #1A1A1A (卡片/列表背景)
Surface Hover: #222222 (hover/pressed 状态)
Border: #2A2A2A (subtle 分割线)
Text Primary: #EDEDEF (主要文字,略带暖色)
Text Secondary: #7C7C82 (次要文字)
Text Tertiary: #4E4E52 (最弱文字)
Accent Purple: #8B5CF6 (品牌色,交互高亮)
Green: #22C55E (在线/成功)
Yellow: #EAB308 (警告/中等延迟)
Red: #EF4444 (断开/错误/高延迟)
Blue: #3B82F6 (信息/链接)
```
## 字体
```
Sans: Inter / system sans-serif (UI 文字)
Mono: JetBrains Mono / system monospace (数据)
Size: 12sp 默认11sp 次要14sp 标题20sp 页面标题
Weight: 400 normal500 medium (标题/强调)
```
## Navigation
保持底部 3 tab但视觉重新设计
```
┌────────────────────────────────────┐
│ (content area) │
├────────────────────────────────────┤
│ ◉ Overview ◎ Nodes ◎ Config │ ← 底部导航icon + label
└────────────────────────────────────┘
```
- Tab 名称: Overview / Nodes / Config (更专业)
- Icon: 线性风格1.5dp stroke
- Active: accent purple icon + white label
- Inactive: text_tertiary
## Screen 1: Overview (原 Home)
不再是大圆按钮。改为信息面板 + 顶部状态栏。
```
┌────────────────────────────────────┐
│ Sing ● Online │ ← 顶栏: 品牌名 + 状态 dot + 文字
├────────────────────────────────────┤
│ │
│ ┌────────────────────────────────┐ │
│ │ CONNECTION │ │ ← section label (text_tertiary, 11sp, uppercase)
│ │ │ │
│ │ Node Tokyo-01 │ │ ← key-value pairs
│ │ Server 1.2.3.4:443 │ │
│ │ Protocol VLESS + Reality │ │
│ │ Uptime 02:34:17 │ │
│ └────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────┐ │
│ │ TRAFFIC │ │
│ │ │ │
│ │ ↑ 1.2 GB ↓ 8.7 GB │ │ ← 大字号流量统计
│ │ ↑ 2.4 MB/s ↓ 12 MB/s │ │ ← 实时速率
│ │ │ │
│ │ Connections 47 active │ │
│ └────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────┐ │
│ │ RECENT CONNECTIONS │ │
│ │ │ │
│ │ youtube.com proxy 12ms │ │ ← 最近连接列表 (内嵌)
│ │ api.github.com proxy 45ms │ │
│ │ baidu.com direct 3ms │ │
│ │ ads.doubleclick block -- │ │
│ │ │ │
│ │ View all → │ │
│ └────────────────────────────────┘ │
│ │
│ ┌──────────────┐ │
│ │ Disconnect │ │ ← 底部操作按钮 (text button, red when connected)
│ └──────────────┘ │
│ │
├────────────────────────────────────┤
│ ◉ Overview ◎ Nodes ◎ Config │
└────────────────────────────────────┘
```
**断开状态:**
```
┌────────────────────────────────────┐
│ Sing ○ Offline │
├────────────────────────────────────┤
│ │
│ │
│ Not connected │ ← 居中灰色文字
│ Tokyo-01 selected │ ← 当前选中节点
│ │
│ ┌──────────────┐ │
│ │ Connect │ │ ← accent purple 按钮
│ └──────────────┘ │
│ │
├────────────────────────────────────┤
│ ◉ Overview ◎ Nodes ◎ Config │
└────────────────────────────────────┘
```
## Screen 2: Nodes (节点列表)
Linear 风格的列表 — 高密度、无卡片、hover 高亮。
```
┌────────────────────────────────────┐
│ Nodes 3 nodes │ ← 标题 + 计数
│ ┌────────┐ ┌──────────┐ ⟳ + │ ← tab pills: Proxy | Tailscale | 测速 | 添加
│ │ Proxy │ │Tailscale │ │
│ └────────┘ └──────────┘ │
├────────────────────────────────────┤
│ │
│ ● Tokyo-01 12ms │ ← active dot(green) + name + delay(green)
│ vless | 1.2.3.4:443 │ ← subtitle (text_secondary, 11sp)
│────────────────────────────────────│ ← subtle border, not divider
│ ○ Singapore-02 156ms │ ← inactive dot(border only) + delay(yellow)
│ trojan | 5.6.7.8:443 │
│────────────────────────────────────│
│ ○ HK-Premium 328ms │ ← delay(red)
│ ss | 9.10.11.12:8388 │
│────────────────────────────────────│
│ │
│ Tailscale tab: │
│ ● station 100.64.0.1 │ ← online dot + hostname + IP
│ linux | online │
│────────────────────────────────────│
│ ○ phone 100.64.0.2 │ ← offline dot
│ android | 3h ago │
│ │
├────────────────────────────────────┤
│ ◎ Overview ◉ Nodes ◎ Config │
└────────────────────────────────────┘
```
**Node 操作** — 长按弹出 bottom sheet (不是 expand):
```
┌────────────────────────────────────┐
│ Tokyo-01 │
│ vless + reality | 1.2.3.4:443 │
├────────────────────────────────────┤
│ ● Set Active │
│ ⟳ Test Latency │
│ ✎ Edit │
│ 🗑 Delete (red) │
└────────────────────────────────────┘
```
**添加节点** — 底部 sheet:
```
┌────────────────────────────────────┐
│ Import Nodes │
├────────────────────────────────────┤
│ 📋 Paste URI │ ← vless://, vmess://, ss://, trojan://
│ 🔗 Subscription URL │
│ {} JSON Import │
│ ✎ Manual │
└────────────────────────────────────┘
```
## Screen 3: Config (原 Settings)
分组列表,每组有 subtle header。不用 Material TextInputLayout用更紧凑的 inline 样式。
```
┌────────────────────────────────────┐
│ Config │
├────────────────────────────────────┤
│ │
│ ROUTING │ ← section header (11sp, text_tertiary)
│ Mode Rule-based ▾ │ ← inline dropdown, not spinner
│ │
│ DNS │
│ Remote tls://8.8.8.8 ✎ │ ← value + edit icon
│ Local 223.5.5.5 ✎ │
│ │
│ GENERAL │
│ Auto-connect ──● │ ← toggle, accent purple when on
│ IPv6 ●── │
│ Block Ads ──● │
│ │
│ RULES │
│ Proxy domains 3 rules │ ← tap → detail screen
│ Direct domains 2 rules
│ Block domains 0 rules
│ │
│ TAILSCALE │
│ Enabled ──● │
│ Auth key •••••••••• ✎ │
│ Hostname my-phone ✎ │
│ Accept routes ●── │
│ │
│ TOOLS │
│ Active Connections
│ Logs
│ │
│ ABOUT │
│ Version 0.5 │
│ Engine mini-sing │
│ │
├────────────────────────────────────┤
│ ◎ Overview ◎ Nodes ◉ Config │
└────────────────────────────────────┘
```
## Implementation Plan
### Phase 1: 基础框架 (迁移到 Compose)
XML 布局要实现 Linear 风格太费劲,建议迁移到 Jetpack Compose。理由
- 深色主题 + 自定义组件在 Compose 里实现更自然
- 动画/过渡效果更容易
- 代码量更少Compose 比 XML + Fragment 减少约 40%
- 现在是重写 UI 的最佳时机
**改动:**
1. `build.gradle.kts`: 添加 Compose 依赖 + BOM
2. `Theme.kt`: 定义 Linear 风格色板 + 字体
3. `MainActivity.kt`: 改为 `setContent {}` + Compose Navigation
4. 删除所有 XML layouts
### Phase 2: 三个主屏
1. `OverviewScreen.kt` — 状态面板 + 流量统计 + 最近连接
2. `NodesScreen.kt` — 节点列表 + tab + 底部 sheet 操作
3. `ConfigScreen.kt` — 分组配置列表
### Phase 3: 二级页面
1. `ConnectionsScreen.kt` — 全部活跃连接
2. `LogsScreen.kt` — 实时日志
3. `EditNodeSheet.kt` — 编辑/添加节点的 bottom sheet
4. `EditRulesScreen.kt` — 编辑自定义规则
### Phase 4: 细节打磨
1. 过渡动画(页面切换、连接状态变化)
2. 实时数据更新(流量速率曲线?)
3. 触感反馈haptic on connect/disconnect
4. 图标替换为自定义 linear-style icon set
## Component Library
复用组件抽取:
```kotlin
// 基础组件
@Composable fun SectionHeader(title: String) // "ROUTING", "DNS" etc.
@Composable fun KeyValueRow(key: String, value: String) // inline key-value
@Composable fun ToggleRow(label: String, checked: Boolean, onToggle: (Boolean) -> Unit)
@Composable fun NavigationRow(label: String, detail: String, onClick: () -> Unit)
@Composable fun StatusDot(color: Color, size: Dp = 8.dp)
// 节点相关
@Composable fun NodeRow(node: Node, isActive: Boolean, delay: Int?, onClick: () -> Unit)
@Composable fun PeerRow(peer: TailscalePeer, onClick: () -> Unit)
// 连接相关
@Composable fun ConnectionRow(conn: Connection)
@Composable fun TrafficCard(upload: Long, download: Long, uploadRate: Long, downloadRate: Long)
```
## 文件变更预估
| 操作 | 文件 |
|------|------|
| 新建 | `ui/theme/Theme.kt`, `ui/theme/Color.kt`, `ui/theme/Type.kt` |
| 新建 | `ui/components/*.kt` (6-8 个基础组件) |
| 新建 | `ui/screens/OverviewScreen.kt` |
| 新建 | `ui/screens/NodesScreen.kt` |
| 新建 | `ui/screens/ConfigScreen.kt` |
| 新建 | `ui/screens/ConnectionsScreen.kt` |
| 新建 | `ui/screens/LogsScreen.kt` |
| 新建 | `ui/sheets/NodeActionSheet.kt` |
| 新建 | `ui/sheets/ImportSheet.kt` |
| 重写 | `MainActivity.kt` (Compose entry) |
| 保留 | 所有非 UI 代码 (VPN service, config, JNI, etc.) |
| 删除 | 所有 `res/layout/*.xml` |
| 删除 | 所有 Fragment 类 (`HomeFragment.kt` 等) |
| 更新 | `build.gradle.kts` (Compose deps) |
| 更新 | `colors.xml` → 仅保留 splash 需要的 |
| 更新 | `themes.xml` → 仅保留 splash + Compose bridge |