Files
sing-android/REVIEW.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

2.5 KiB
Raw Blame History

Code Review — Android Compose Migration — 2026-04-02

Summary

XML layouts + Fragments 全部迁移到 Jetpack Compose。12 个新文件,删除 2596 行 XML/Fragment 代码。Linear 深色主题落地,组件库复用良好。

整体评价

做得好:

  • 色板、字体、组件库完全按 REDESIGN.md 规范
  • LaunchedEffect + mutableStateOf 状态管理干净
  • SectionCard, KeyValueRow, ToggleRow, NavigationRow 复用率高
  • Bottom sheet 替代 expand交互更现代
  • LogsScreen 增量读取 (RandomAccessFile + delta) 设计巧妙
  • ConfigScreen 分组列表紧凑inline dropdown 比 Spinner 更好

Bugs

B1. LogsScreen 重复定义 InlineDivider

ui/screens/LogsScreen.kt:126-128 定义了私有 InlineDivider,但 ui/components/Components.kt:162-168 已有公共版本。

Fix: 删除 LogsScreen 中的私有版本import 公共组件。

B2. ConfigScreen 双重 save

每个 onValueChange 调用 save()DisposableEffect(Unit)onDispose 也调 save()。每次输入字符都写全量 SharedPreferences不必要。

Fix: 去掉 onValueChange 里的 save() 调用,只保留 DisposableEffectonDispose { save() }。对于 toggle 类(立即生效),单独 prefs.edit().putBoolean(...).apply()

B3. OverviewScreen recentConnections 缺 key

OverviewScreen.kt:169items(recentConnections.take(5)) 没有 key 参数,列表更新时 Compose 无法高效 diff导致不必要的重组。

Fix: 添加 key = { it.host } 或用 index。

Improvements

I1. 字符串硬编码

所有 UI 文字直接写在 Compose 代码里("Paste URI", "Subscription URL", "Not connected" 等)。strings.xml 已被清空。

Impact: 不影响功能,但阻碍了国际化。后续统一迁移到 stringResource()

I2. fragment-ktx 依赖可移除

Compose 迁移后不再需要 androidx.fragment:fragment-ktx。build.gradle.kts 中已移除,确认无残留引用即可。

I3. NodesScreen 函数过长

NodesScreen.kt 单个 Composable 约 400 行,包含 bottom sheet、import 逻辑、tab 切换。

Suggestion: 拆分为 NodeActionSheetImportSheetProxyNodeListTailscalePeerList 独立 Composable。

I4. fetchTrafficStats / fetchConnections 重复

OverviewScreen.kt:289ConnectionsScreen.kt:141 各自实现了 Clash API 的 /connections 解析,逻辑几乎相同。

Suggestion: 抽取到 data/ClashApi.kt 统一调用。