docs: add wechat ui polish plan

This commit is contained in:
kris
2026-03-29 23:47:59 +08:00
parent ffefc62b35
commit 6402096639

View File

@@ -0,0 +1,343 @@
# 微信式会话页与我的页 UI 收口 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 把原生 Android 的 `会话` 根页和 `我的` 根页统一收口到同一套微信式产品语言,同时保持现有会话、返回、群聊、附件和登录链路不回退。
**Architecture:** 这次只重写原生 UI helper 和 `MainActivity` 的两处根页渲染绑定,不改数据模型或 API。实现顺序按 TDD 走:先补 helper 和根页渲染测试,再做最小实现,再跑 Android 单测、release 构建和 OPPO 真机回归。
**Tech Stack:** Java, Android AppCompat, Robolectric/JUnit, Gradle, ADB, Next.js verification scripts
---
### Task 1: 为会话页和我的页补 UI 基线测试
**Files:**
- Modify: `android/app/src/test/java/com/hyzq/boss/BossUiConversationRowTest.java`
- Create: `android/app/src/test/java/com/hyzq/boss/BossUiRootSurfaceTest.java`
- Test: `android/app/src/test/java/com/hyzq/boss/BossUiConversationRowTest.java`
- Test: `android/app/src/test/java/com/hyzq/boss/BossUiRootSurfaceTest.java`
- [ ] **Step 1: 扩展会话列表项测试,明确“非卡片流”的结构约束**
```java
@Test
public void buildConversationRow_usesWechatListSpacingInsteadOfCardChrome() {
Context context = ApplicationProvider.getApplicationContext();
WechatSurfaceMapper.ConversationRow row = new WechatSurfaceMapper.ConversationRow(
"北区试产线回归",
"归档确认",
"现场摄像头关键帧",
"09:26",
2,
"置顶",
2,
false,
"M",
"W",
new WechatSurfaceMapper.GroupAvatarMember[0]
);
LinearLayout view = BossUi.buildConversationRow(context, row, null);
assertEquals(Color.WHITE, ((ColorDrawable) view.getBackground()).getColor());
assertEquals(BossUi.dp(context, 16), view.getPaddingLeft());
assertEquals(BossUi.dp(context, 12), view.getPaddingTop());
}
```
- [ ] **Step 2: 运行单测,确认它先失败**
Run:
```bash
cd /Users/kris/code/boss/android
./gradlew testDebugUnitTest --tests com.hyzq.boss.BossUiConversationRowTest --no-daemon
```
Expected: FAIL原因是当前 `buildConversationRow` 仍保留卡片样式或 padding 不符合新约束。
- [ ] **Step 3: 新增根页测试,锁定“我的”页头部和菜单列表结构**
```java
@Test
public void renderMeRoot_usesWechatProfileHeaderAndFlatMenuRows() {
MainActivity activity = Robolectric.buildActivity(MainActivity.class).create().start().resume().get();
activity.runOnUiThread(() -> {
activity.sessionData = new StubJSONObject()
.withString("displayName", "Kris")
.withString("account", "17600003315")
.withString("role", "最高管理员");
activity.setActiveTab("me", false);
});
Shadows.shadowOf(Looper.getMainLooper()).idle();
LinearLayout content = activity.findViewById(R.id.screen_content);
assertTrue(findText(content, "Kris"));
assertTrue(findText(content, "17600003315"));
assertTrue(findText(content, "账号与安全"));
assertTrue(findText(content, "AI 账号"));
}
```
- [ ] **Step 4: 运行新的根页测试,确认它先失败**
Run:
```bash
cd /Users/kris/code/boss/android
./gradlew testDebugUnitTest --tests com.hyzq.boss.BossUiRootSurfaceTest --no-daemon
```
Expected: FAIL原因是当前 `renderMeRoot` / `buildSimpleProfileHeader` 仍不满足新的微信式结构断言。
- [ ] **Step 5: 提交测试基线**
```bash
cd /Users/kris/code/boss
git add android/app/src/test/java/com/hyzq/boss/BossUiConversationRowTest.java android/app/src/test/java/com/hyzq/boss/BossUiRootSurfaceTest.java
git commit -m "test: lock wechat root surface expectations"
```
### Task 2: 重写 BossUi 的会话行、资料区和菜单行 helper
**Files:**
- Modify: `android/app/src/main/java/com/hyzq/boss/BossUi.java`
- Modify: `android/app/src/test/java/com/hyzq/boss/BossUiConversationRowTest.java`
- Modify: `android/app/src/test/java/com/hyzq/boss/BossUiRootSurfaceTest.java`
- Test: `android/app/src/test/java/com/hyzq/boss/BossUiConversationRowTest.java`
- Test: `android/app/src/test/java/com/hyzq/boss/BossUiRootSurfaceTest.java`
- [ ] **Step 1: 实现新的会话列表行和我的页基础 helper**
```java
public static LinearLayout buildWechatMenuRow(
Context context,
String title,
@Nullable String subtitle,
@Nullable String meta,
@Nullable String badge,
@Nullable View.OnClickListener listener
) {
LinearLayout row = buildListRow(context, title, subtitle, meta, badge, listener);
row.setBackgroundColor(Color.WHITE);
row.setPadding(dp(context, 18), dp(context, 15), dp(context, 18), dp(context, 15));
row.setElevation(0f);
return row;
}
public static LinearLayout buildSimpleProfileHeader(
Context context,
String name,
String subtitle,
@Nullable String detail
) {
LinearLayout header = new LinearLayout(context);
header.setOrientation(LinearLayout.HORIZONTAL);
header.setBackgroundColor(Color.WHITE);
header.setPadding(dp(context, 20), dp(context, 18), dp(context, 20), dp(context, 18));
return header;
}
```
- [ ] **Step 2: 把 `buildConversationRow` 从卡片改成白底列表项**
```java
public static LinearLayout buildConversationRow(
Context context,
WechatSurfaceMapper.ConversationRow row,
@Nullable View.OnClickListener listener
) {
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.HORIZONTAL);
container.setBackgroundColor(Color.WHITE);
container.setPadding(dp(context, 16), dp(context, 12), dp(context, 16), dp(context, 12));
if (listener != null) {
container.setClickable(true);
container.setFocusable(true);
container.setOnClickListener(listener);
}
return container;
}
```
- [ ] **Step 3: 运行 helper 相关单测,确认现在全部通过**
Run:
```bash
cd /Users/kris/code/boss/android
./gradlew testDebugUnitTest --tests com.hyzq.boss.BossUiConversationRowTest --tests com.hyzq.boss.BossUiRootSurfaceTest --no-daemon
```
Expected: PASS`BossUiConversationRowTest``BossUiRootSurfaceTest` 全绿。
- [ ] **Step 4: 自查复用面**
```bash
cd /Users/kris/code/boss
rg -n "buildSimpleProfileHeader|buildWechatMenuRow|buildConversationRow" android/app/src/main/java/com/hyzq/boss -S
```
Expected: 输出覆盖 `MainActivity / ConversationInfoActivity / GroupInfoActivity / GroupCreateActivity / AboutActivity` 等现有入口,确认 helper 改动会统一带到深层页。
- [ ] **Step 5: 提交 helper 重写**
```bash
cd /Users/kris/code/boss
git add android/app/src/main/java/com/hyzq/boss/BossUi.java android/app/src/test/java/com/hyzq/boss/BossUiConversationRowTest.java android/app/src/test/java/com/hyzq/boss/BossUiRootSurfaceTest.java
git commit -m "style: align conversations and me root surfaces"
```
### Task 3: 收口 MainActivity 根页渲染和点击区
**Files:**
- Modify: `android/app/src/main/java/com/hyzq/boss/MainActivity.java`
- Modify: `android/app/src/test/java/com/hyzq/boss/BossUiRootSurfaceTest.java`
- Test: `android/app/src/test/java/com/hyzq/boss/BossUiRootSurfaceTest.java`
- [ ] **Step 1: 调整会话页和我的页根渲染,让新 helper 真正落到主界面**
```java
private void renderConversationsRoot() {
topTitle.setText("会话");
topSubtitle.setVisibility(View.GONE);
screenContent.removeAllViews();
for (int i = 0; i < conversationsData.length(); i++) {
JSONObject item = conversationsData.optJSONObject(i);
if (item == null) continue;
WechatSurfaceMapper.ConversationRow row = WechatSurfaceMapper.toConversationRow(item);
screenContent.addView(BossUi.buildConversationRow(this, row, v -> openConversation(item)));
}
}
private void renderMeRoot() {
topTitle.setText("我的");
topSubtitle.setVisibility(View.GONE);
screenContent.removeAllViews();
screenContent.addView(BossUi.buildSimpleProfileHeader(this, displayName, account, roleLabel));
for (WechatSurfaceMapper.MeMenuItem item : WechatSurfaceMapper.rootMeMenuItems()) {
screenContent.addView(BossUi.buildWechatMenuRow(this, item.title, item.description, null, null, v -> openMeItem(item.key)));
}
}
```
- [ ] **Step 2: 补充点击区测试,保证菜单行和会话行整行可点**
```java
@Test
public void renderConversationsRoot_keepsConversationRowsClickable() {
MainActivity activity = buildConversationReadyActivity();
LinearLayout content = activity.findViewById(R.id.screen_content);
View firstRow = content.getChildAt(1);
assertTrue(firstRow.isClickable());
}
```
- [ ] **Step 3: 跑根页测试,确认主界面结构和点击区正确**
Run:
```bash
cd /Users/kris/code/boss/android
./gradlew testDebugUnitTest --tests com.hyzq.boss.BossUiRootSurfaceTest --no-daemon
```
Expected: PASS根页结构、菜单项和点击区断言全部通过。
- [ ] **Step 4: 提交 MainActivity 收口**
```bash
cd /Users/kris/code/boss
git add android/app/src/main/java/com/hyzq/boss/MainActivity.java android/app/src/test/java/com/hyzq/boss/BossUiRootSurfaceTest.java
git commit -m "style: polish native conversations and me roots"
```
### Task 4: 合并现有关于页版本号修复并完成全链验证
**Files:**
- Modify: `android/app/src/main/java/com/hyzq/boss/AboutActivity.java`
- Modify: `android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java`
- Modify: `README.md`
- Modify: `docs/architecture/current_runtime_and_deploy_status_cn.md`
- Test: `android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java`
- [ ] **Step 1: 保留并整理当前“关于页显示已安装版本号”的修复**
```java
private static String resolveInstalledVersionLabel(
@Nullable JSONObject user,
JSONObject ota,
@Nullable String packageVersionName
) {
if (packageVersionName != null && !packageVersionName.isEmpty()) {
return packageVersionName;
}
if (user != null) {
String userVersion = user.optString("version", "");
if (!userVersion.isEmpty()) {
return userVersion;
}
}
return ota.optString("currentVersion", "-");
}
```
- [ ] **Step 2: 跑关于页测试,确认已安装版本优先级正确**
Run:
```bash
cd /Users/kris/code/boss/android
./gradlew testDebugUnitTest --tests com.hyzq.boss.WechatSurfaceMapperTest --no-daemon
```
Expected: PASS`aboutActivity_prefersInstalledPackageVersionOverServerVersion` 通过。
- [ ] **Step 3: 运行完整本地验证**
Run:
```bash
cd /Users/kris/code/boss
npm run lint
npm run build
curl -sS http://127.0.0.1:3000/api/health
curl -sS http://127.0.0.1:4317/health
cd android && ./gradlew testDebugUnitTest --no-daemon
cd /Users/kris/code/boss/android && ./gradlew clean assembleRelease --no-daemon
```
Expected:
- `lint` PASS
- `build` PASS
- 两个 health 接口返回 `ok`
- Android 单测 PASS
- release 构建成功输出 APK
- [ ] **Step 4: 用 OPPO `PLB110` 做真机回归**
Run:
```bash
adb devices -l
adb -t 501 install -r /Users/kris/code/boss/android/app/build/outputs/apk/release/app-release.apk
adb -t 501 shell am start -W -n com.hyzq.boss/.MainActivity
```
Manual checks:
- 会话首页视觉不再是厚卡片流
- 点击任意会话能进入聊天并返回
- 我的首页顶部是微信式资料区
- 我的 > 关于 正确显示已安装版本号
- 底部 `会话 / 设备 / 我的` 切换正常
- [ ] **Step 5: 同步文档并提交**
```bash
cd /Users/kris/code/boss
git add android/app/src/main/java/com/hyzq/boss/AboutActivity.java android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java README.md docs/architecture/current_runtime_and_deploy_status_cn.md
git commit -m "docs: record native root ui polish validation"
```