From 9e0b5b223f689d874f24ed3df4d07f50d54ef505 Mon Sep 17 00:00:00 2001 From: kris Date: Fri, 27 Mar 2026 13:28:15 +0800 Subject: [PATCH] android: preserve device detail summary context --- .../com/hyzq/boss/DeviceDetailActivity.java | 27 ++-------- .../com/hyzq/boss/WechatSurfaceMapper.java | 54 +++++++++++++++++++ .../hyzq/boss/WechatSurfaceMapperTest.java | 50 +++++++++++++++++ 3 files changed, 108 insertions(+), 23 deletions(-) diff --git a/android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.java b/android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.java index 2af9e09..a622e56 100644 --- a/android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.java +++ b/android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.java @@ -57,11 +57,12 @@ public class DeviceDetailActivity extends BossScreenActivity { deviceName = device.optString("name", deviceId); configureScreen(deviceName, device.optString("endpoint", "设备详情")); + WechatSurfaceMapper.DeviceDetailSummary summary = WechatSurfaceMapper.toDeviceDetailSummary(device); appendContent(BossUi.buildListRow( this, - device.optString("name", "设备"), - buildDeviceSubtitle(device), - buildDeviceMeta(device), + summary.title.isEmpty() ? "设备" : summary.title, + summary.subtitle, + summary.meta, null, null )); @@ -71,26 +72,6 @@ public class DeviceDetailActivity extends BossScreenActivity { setRefreshing(false); } - private String buildDeviceSubtitle(JSONObject device) { - String note = device.optString("note", ""); - if (!note.isEmpty()) { - return note; - } - return "状态 " + device.optString("status", "unknown") + " · 账号 " + device.optString("account", "-"); - } - - private @Nullable String buildDeviceMeta(JSONObject device) { - String endpoint = device.optString("endpoint", ""); - if (!endpoint.isEmpty()) { - return endpoint; - } - JSONArray projects = device.optJSONArray("projects"); - if (projects == null || projects.length() == 0) { - return null; - } - return "项目 " + joinArray(projects); - } - private void openSkills() { Intent intent = new Intent(this, SkillInventoryActivity.class); intent.putExtra(SkillInventoryActivity.EXTRA_DEVICE_ID, deviceId); diff --git a/android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java b/android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java index c5e8267..0d20044 100644 --- a/android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java +++ b/android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java @@ -1,6 +1,7 @@ package com.hyzq.boss; import org.json.JSONObject; +import org.json.JSONArray; import java.util.Arrays; import java.util.List; @@ -52,6 +53,15 @@ public final class WechatSurfaceMapper { ); } + public static DeviceDetailSummary toDeviceDetailSummary(JSONObject item) { + JSONObject source = item == null ? new JSONObject() : item; + return new DeviceDetailSummary( + source.optString("title", source.optString("name", "")), + buildSubtitle(source), + buildDetailMeta(source) + ); + } + public static String[] rootTabLabels() { return ROOT_TAB_LABELS.toArray(new String[0]); } @@ -89,6 +99,38 @@ public final class WechatSurfaceMapper { return status + " · " + account; } + private static String buildDetailMeta(JSONObject source) { + StringBuilder builder = new StringBuilder(); + appendSegment(builder, source.optString("note", "")); + appendSegment(builder, source.optString("endpoint", "")); + JSONArray projects = source.optJSONArray("projects"); + if (projects != null && projects.length() > 0) { + StringBuilder projectBuilder = new StringBuilder(); + for (int i = 0; i < projects.length(); i++) { + String project = projects.optString(i); + if (project.isEmpty()) continue; + if (projectBuilder.length() > 0) { + projectBuilder.append(", "); + } + projectBuilder.append(project); + } + if (projectBuilder.length() > 0) { + appendSegment(builder, "项目 " + projectBuilder); + } + } + return builder.length() == 0 ? null : builder.toString(); + } + + private static void appendSegment(StringBuilder builder, String value) { + if (value == null || value.isEmpty()) { + return; + } + if (builder.length() > 0) { + builder.append(" · "); + } + builder.append(value); + } + public static final class ConversationRow { public final String title; public final String preview; @@ -112,4 +154,16 @@ public final class WechatSurfaceMapper { this.subtitle = subtitle; } } + + public static final class DeviceDetailSummary { + public final String title; + public final String subtitle; + public final String meta; + + public DeviceDetailSummary(String title, String subtitle, String meta) { + this.title = title; + this.subtitle = subtitle; + this.meta = meta; + } + } } diff --git a/android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java b/android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java index 7710b1c..215b91f 100644 --- a/android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java +++ b/android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java @@ -53,6 +53,23 @@ public class WechatSurfaceMapperTest { assertEquals("异常 · 17600003315", row.subtitle); } + @Test + public void deviceDetailSummary_keepsEssentialContextAlongsideNoteEndpointAndProjects() throws Exception { + JSONObject item = new StubJSONObject() + .withString("name", "Mac Studio") + .withString("status", "online") + .withString("account", "17600003315") + .withString("note", "书房主机") + .withString("endpoint", "https://boss.hyzq.net/device/mac-studio") + .withArray("projects", "master-agent", "android-app"); + + WechatSurfaceMapper.DeviceDetailSummary summary = WechatSurfaceMapper.toDeviceDetailSummary(item); + + assertEquals("Mac Studio", summary.title); + assertEquals("在线 · 17600003315", summary.subtitle); + assertEquals("书房主机 · https://boss.hyzq.net/device/mac-studio · 项目 master-agent, android-app", summary.meta); + } + @Test public void rootMeMenuTitles_matchApprovedSimpleMenu() throws Exception { assertArrayEquals( @@ -116,6 +133,11 @@ public class WechatSurfaceMapperTest { return this; } + StubJSONObject withArray(String key, String... entries) { + values.put(key, new StubJSONArray(entries)); + return this; + } + @Override public String optString(String key, String defaultValue) { Object value = values.get(key); @@ -133,5 +155,33 @@ public class WechatSurfaceMapperTest { Object value = values.get(key); return value instanceof Boolean ? (Boolean) value : defaultValue; } + + @Override + public org.json.JSONArray optJSONArray(String key) { + Object value = values.get(key); + return value instanceof org.json.JSONArray ? (org.json.JSONArray) value : null; + } + } + + private static final class StubJSONArray extends org.json.JSONArray { + private final String[] entries; + + StubJSONArray(String... entries) { + this.entries = entries == null ? new String[0] : entries; + } + + @Override + public int length() { + return entries.length; + } + + @Override + public String optString(int index) { + if (index < 0 || index >= entries.length) { + return ""; + } + String value = entries[index]; + return value == null ? "" : value; + } } }