Compact imported single-thread conversation copy
This commit is contained in:
@@ -59,7 +59,9 @@ public final class WechatSurfaceMapper {
|
||||
JSONObject avatar = source.optJSONObject("avatar");
|
||||
boolean isGroup = source.optBoolean("isGroup", groupAvatarMembers.size() > 1);
|
||||
String conversationType = source.optString("conversationType", "");
|
||||
String threadTitle = source.optString("threadTitle", source.optString("title", source.optString("projectTitle", "")));
|
||||
String threadTitle = trimLocalWorkspacePrefix(
|
||||
source.optString("threadTitle", source.optString("title", source.optString("projectTitle", "")))
|
||||
);
|
||||
if ("folder_archive".equals(conversationType)) {
|
||||
threadTitle = source.optString(
|
||||
"projectTitle",
|
||||
@@ -70,7 +72,7 @@ public final class WechatSurfaceMapper {
|
||||
return new ConversationRow(
|
||||
threadTitle,
|
||||
source.optString("folderLabel", ""),
|
||||
source.optString("lastMessagePreview", source.optString("preview", "")),
|
||||
compactImportedThreadPreview(source.optString("lastMessagePreview", source.optString("preview", ""))),
|
||||
source.optString("timeLabel", source.optString("latestReplyLabel", "")),
|
||||
source.optInt("unreadCount", 0),
|
||||
pinnedLabel,
|
||||
@@ -408,7 +410,7 @@ public final class WechatSurfaceMapper {
|
||||
);
|
||||
putIfNotEmpty(folder, "projectTitle", projectTitle);
|
||||
putIfNotEmpty(folder, "threadTitle", projectTitle);
|
||||
String recentThread = latest.optString("threadTitle", "").trim();
|
||||
String recentThread = trimLocalWorkspacePrefix(latest.optString("threadTitle", "").trim());
|
||||
putIfNotEmpty(
|
||||
folder,
|
||||
"folderLabel",
|
||||
@@ -422,11 +424,16 @@ public final class WechatSurfaceMapper {
|
||||
safePut(folder, "searchAliases", searchAliases);
|
||||
safePut(folder, "searchTargetProjectIds", searchTargetProjectIds);
|
||||
}
|
||||
putIfNotEmpty(folder, "preview", firstNonBlank(latest.optString("preview", ""), latest.optString("lastMessagePreview", "")));
|
||||
String compactPreview = compactImportedThreadPreview(
|
||||
firstNonBlank(latest.optString("preview", ""), latest.optString("lastMessagePreview", ""))
|
||||
);
|
||||
putIfNotEmpty(folder, "preview", compactPreview);
|
||||
putIfNotEmpty(
|
||||
folder,
|
||||
"lastMessagePreview",
|
||||
firstNonBlank(latest.optString("lastMessagePreview", ""), latest.optString("preview", ""))
|
||||
compactImportedThreadPreview(
|
||||
firstNonBlank(latest.optString("lastMessagePreview", ""), latest.optString("preview", ""))
|
||||
)
|
||||
);
|
||||
safePut(folder, "activityIconCount", Math.max(0, Math.min(4, sumInt(items, "activityIconCount"))));
|
||||
if (hasPinnedLabel(items)) {
|
||||
@@ -637,6 +644,26 @@ public final class WechatSurfaceMapper {
|
||||
}
|
||||
}
|
||||
|
||||
private static String compactImportedThreadPreview(String value) {
|
||||
String preview = value == null ? "" : value.trim();
|
||||
if (preview.matches("^已从设备.+导入线程《.+》[。.]?$")) {
|
||||
return "已导入线程";
|
||||
}
|
||||
return preview;
|
||||
}
|
||||
|
||||
private static String trimLocalWorkspacePrefix(String value) {
|
||||
String label = value == null ? "" : value.trim();
|
||||
if (label.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
String normalized = label.replace('\\', '/');
|
||||
return normalized
|
||||
.replaceFirst("^/Users/[^/]+/code/", "")
|
||||
.replaceFirst("^/home/[^/]+/code/", "")
|
||||
.replaceFirst("^[A-Za-z]:/Users/[^/]+/code/", "");
|
||||
}
|
||||
|
||||
private static String firstNonBlank(String... values) {
|
||||
if (values == null) {
|
||||
return "";
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.hyzq.boss;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@@ -12,6 +15,8 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(sdk = 34)
|
||||
public class WechatSurfaceMapperTest {
|
||||
@Test
|
||||
public void toConversationRow_mapsWechatConversationFieldsFromThreadPayload() throws Exception {
|
||||
@@ -79,6 +84,59 @@ public class WechatSurfaceMapperTest {
|
||||
assertEquals("", row.avatarPrimary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalizeConversationHomeFeed_compactsImportedFolderPreviewAndTrimsWorkspacePrefix() throws Exception {
|
||||
JSONArray source = new JSONArray()
|
||||
.put(new JSONObject()
|
||||
.put("conversationType", "single_device")
|
||||
.put("projectId", "wenshen-thread-1")
|
||||
.put("folderKey", "mac-studio:/users/kris/code/wenshenapp")
|
||||
.put("projectTitle", "wenshenapp")
|
||||
.put("threadTitle", "/Users/kris/code/wenshenapp/docs/superpowers/specs/2026-04-06-context-cleanup-design.md")
|
||||
.put("folderLabel", "wenshenapp")
|
||||
.put("preview", "已从设备 Mac Studio 导入线程《wenshenapp · 019d60》。")
|
||||
.put("lastMessagePreview", "已从设备 Mac Studio 导入线程《wenshenapp · 019d60》。")
|
||||
.put("latestReplyAt", "2026-04-06T17:35:00+08:00")
|
||||
.put("latestReplyLabel", "17:35"))
|
||||
.put(new JSONObject()
|
||||
.put("conversationType", "single_device")
|
||||
.put("projectId", "wenshen-thread-2")
|
||||
.put("folderKey", "mac-studio:/users/kris/code/wenshenapp")
|
||||
.put("projectTitle", "wenshenapp")
|
||||
.put("threadTitle", "补齐 Android 会话可读性")
|
||||
.put("folderLabel", "wenshenapp")
|
||||
.put("preview", "最近消息:补齐 Android 会话可读性")
|
||||
.put("lastMessagePreview", "最近消息:补齐 Android 会话可读性")
|
||||
.put("latestReplyAt", "2026-04-06T16:30:00+08:00")
|
||||
.put("latestReplyLabel", "16:30"));
|
||||
|
||||
JSONArray normalized = WechatSurfaceMapper.normalizeConversationHomeFeed(source);
|
||||
JSONObject folder = normalized.optJSONObject(0);
|
||||
|
||||
assertNotNull(folder);
|
||||
assertEquals("folder_archive", folder.optString("conversationType", ""));
|
||||
assertEquals("2 个线程 · 最近:wenshenapp/docs/superpowers/specs/2026-04-06-context-cleanup-design.md", folder.optString("folderLabel", ""));
|
||||
assertEquals("已导入线程", folder.optString("preview", ""));
|
||||
assertEquals("已导入线程", folder.optString("lastMessagePreview", ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toConversationRow_compactsImportedPreviewAndTrimsWorkspacePrefixForSingleThread() throws Exception {
|
||||
JSONObject item = new JSONObject()
|
||||
.put("conversationType", "single_device")
|
||||
.put("projectTitle", "zhanglaoshi")
|
||||
.put("threadTitle", "/Users/kris/code/zhanglaoshi/docs/superpowers/specs/2026-04-06-single-thread-cleanup-design.md")
|
||||
.put("folderLabel", "zhanglaoshi")
|
||||
.put("preview", "已从设备 Mac Studio 导入线程《zhanglaoshi · 019d61》。")
|
||||
.put("lastMessagePreview", "已从设备 Mac Studio 导入线程《zhanglaoshi · 019d61》。")
|
||||
.put("latestReplyLabel", "17:35");
|
||||
|
||||
WechatSurfaceMapper.ConversationRow row = WechatSurfaceMapper.toConversationRow(item);
|
||||
|
||||
assertEquals("zhanglaoshi/docs/superpowers/specs/2026-04-06-single-thread-cleanup-design.md", row.threadTitle);
|
||||
assertEquals("已导入线程", row.lastMessagePreview);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toDeviceRow_mapsLegacyWechatThreeLineSummary() throws Exception {
|
||||
JSONObject item = new StubJSONObject()
|
||||
|
||||
Reference in New Issue
Block a user