12 KiB
微信式会话页与我的页 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: 扩展会话列表项测试,明确“非卡片流”的结构约束
@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:
cd /Users/kris/code/boss/android
./gradlew testDebugUnitTest --tests com.hyzq.boss.BossUiConversationRowTest --no-daemon
Expected: FAIL,原因是当前 buildConversationRow 仍保留卡片样式或 padding 不符合新约束。
- Step 3: 新增根页测试,锁定“我的”页头部和菜单列表结构
@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:
cd /Users/kris/code/boss/android
./gradlew testDebugUnitTest --tests com.hyzq.boss.BossUiRootSurfaceTest --no-daemon
Expected: FAIL,原因是当前 renderMeRoot / buildSimpleProfileHeader 仍不满足新的微信式结构断言。
- Step 5: 提交测试基线
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
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从卡片改成白底列表项
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:
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: 自查复用面
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 重写
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 真正落到主界面
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: 补充点击区测试,保证菜单行和会话行整行可点
@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:
cd /Users/kris/code/boss/android
./gradlew testDebugUnitTest --tests com.hyzq.boss.BossUiRootSurfaceTest --no-daemon
Expected: PASS,根页结构、菜单项和点击区断言全部通过。
- Step 4: 提交 MainActivity 收口
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: 保留并整理当前“关于页显示已安装版本号”的修复
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:
cd /Users/kris/code/boss/android
./gradlew testDebugUnitTest --tests com.hyzq.boss.WechatSurfaceMapperTest --no-daemon
Expected: PASS,aboutActivity_prefersInstalledPackageVersionOverServerVersion 通过。
- Step 3: 运行完整本地验证
Run:
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:
-
lintPASS -
buildPASS -
两个 health 接口返回
ok -
Android 单测 PASS
-
release 构建成功输出 APK
-
Step 4: 用 OPPO
PLB110做真机回归
Run:
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: 同步文档并提交
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"