- 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
15 KiB
15 KiB
Android UI Redesign — Linear Style
Design Language
参考 Linear.app 的设计语言:极简、高信息密度、深色主题、无多余装饰。 告别"VPN 大圆按钮"的传统模板,走向工具型产品的质感。
核心原则
- 信息密度优先 — 一屏展示最多有效信息,不浪费空间在装饰元素上
- 深色主题 — Linear 标志性的深灰背景 + 高对比度文字
- 微妙的层次 — 通过 subtle 的背景色差区分区域,不用卡片阴影
- Monospace 数据 — IP、延迟、流量等技术数据用等宽字体
- 无圆角按钮 — 操作通过 inline 文字按钮或 icon 触发
- 状态用颜色 — 绿色=在线/连接,黄色=警告,红色=断开/错误,紫色=品牌色
色板
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 normal,500 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 的最佳时机
改动:
build.gradle.kts: 添加 Compose 依赖 + BOMTheme.kt: 定义 Linear 风格色板 + 字体MainActivity.kt: 改为setContent {}+ Compose Navigation- 删除所有 XML layouts
Phase 2: 三个主屏
OverviewScreen.kt— 状态面板 + 流量统计 + 最近连接NodesScreen.kt— 节点列表 + tab + 底部 sheet 操作ConfigScreen.kt— 分组配置列表
Phase 3: 二级页面
ConnectionsScreen.kt— 全部活跃连接LogsScreen.kt— 实时日志EditNodeSheet.kt— 编辑/添加节点的 bottom sheetEditRulesScreen.kt— 编辑自定义规则
Phase 4: 细节打磨
- 过渡动画(页面切换、连接状态变化)
- 实时数据更新(流量速率曲线?)
- 触感反馈(haptic on connect/disconnect)
- 图标替换为自定义 linear-style icon set
Component Library
复用组件抽取:
// 基础组件
@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 |