# 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()` 调用,只保留 `DisposableEffect` 的 `onDispose { save() }`。对于 toggle 类(立即生效),单独 `prefs.edit().putBoolean(...).apply()`。 ### B3. OverviewScreen recentConnections 缺 key `OverviewScreen.kt:169` 的 `items(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:** 拆分为 `NodeActionSheet`、`ImportSheet`、`ProxyNodeList`、`TailscalePeerList` 独立 Composable。 ### I4. fetchTrafficStats / fetchConnections 重复 `OverviewScreen.kt:289` 和 `ConnectionsScreen.kt:141` 各自实现了 Clash API 的 `/connections` 解析,逻辑几乎相同。 **Suggestion:** 抽取到 `data/ClashApi.kt` 统一调用。