Patch folder realtime threads locally

This commit is contained in:
kris
2026-04-10 22:01:21 +08:00
parent 0781a56aad
commit a084688e35
7 changed files with 145 additions and 0 deletions

View File

@@ -32,6 +32,7 @@ public class ConversationFolderActivity extends BossScreenActivity {
private ArrayList<String> targetProjectIds;
private String targetProjectLabel;
private @Nullable BossRealtimeClient realtimeClient;
private @Nullable JSONObject currentFolderPayload;
private final Handler uiHandler = new Handler(Looper.getMainLooper());
private final Map<String, Long> recentRealtimeEventTimestamps = new LinkedHashMap<>();
private final Set<String> trackedProjectIds = new LinkedHashSet<>();
@@ -144,9 +145,48 @@ public class ConversationFolderActivity extends BossScreenActivity {
if (isDuplicateRealtimeEvent(eventFingerprint, now)) {
return;
}
if (tryApplyFolderRealtimePatch(event)) {
return;
}
runOnUiThread(this::scheduleRealtimeReload);
}
private boolean tryApplyFolderRealtimePatch(BossRealtimeEvent event) {
if (event == null || currentFolderPayload == null) {
return false;
}
if (!"conversation.updated".equals(event.eventName)
&& !"project.messages.updated".equals(event.eventName)) {
return false;
}
String affectedProjectId = event.payload.optString("projectId", "").trim();
if (affectedProjectId.isEmpty() || !trackedProjectIds.contains(affectedProjectId)) {
return false;
}
JSONObject threadConversationItem = event.payload.optJSONObject("threadConversationItem");
if (threadConversationItem == null) {
return false;
}
String patchedFolderKey = threadConversationItem.optString("folderKey", "").trim();
if (folderKey == null || folderKey.isEmpty() || !folderKey.equals(patchedFolderKey)) {
return false;
}
runOnUiThread(() -> {
if (currentFolderPayload == null) {
scheduleRealtimeReload();
return;
}
JSONObject mergedFolder = replaceThreadConversationItem(
currentFolderPayload,
affectedProjectId,
threadConversationItem
);
currentFolderPayload = mergedFolder;
renderFolder(mergedFolder);
});
return true;
}
private void scheduleRealtimeReload() {
if (realtimeReloadScheduled) {
return;
@@ -201,12 +241,14 @@ public class ConversationFolderActivity extends BossScreenActivity {
private void renderFolder(@Nullable JSONObject folder) {
replaceContent();
if (folder == null) {
currentFolderPayload = null;
trackedProjectIds.clear();
appendContent(BossUi.buildEmptyCard(this, "未找到项目线程。"));
setRefreshing(false);
return;
}
currentFolderPayload = copyJson(folder);
String resolvedFolderName = folder.optString("folderLabel", folderName == null ? "项目线程" : folderName);
folderDeviceId = folder.optString("deviceId", folderDeviceId == null ? "" : folderDeviceId).trim();
int threadCount = folder.optInt("threadCount", 0);
@@ -273,6 +315,47 @@ public class ConversationFolderActivity extends BossScreenActivity {
}
}
private JSONObject replaceThreadConversationItem(JSONObject folder, String affectedProjectId, JSONObject threadConversationItem) {
JSONObject mergedFolder = copyJson(folder);
JSONArray existingThreads = mergedFolder.optJSONArray("threads");
JSONArray mergedThreads = new JSONArray();
boolean replaced = false;
if (existingThreads != null) {
for (int i = 0; i < existingThreads.length(); i++) {
JSONObject item = existingThreads.optJSONObject(i);
if (item == null) {
continue;
}
if (affectedProjectId.equals(item.optString("projectId", "").trim())) {
mergedThreads.put(copyJson(threadConversationItem));
replaced = true;
continue;
}
mergedThreads.put(copyJson(item));
}
}
if (!replaced) {
mergedThreads.put(copyJson(threadConversationItem));
}
try {
mergedFolder.put("threads", mergedThreads);
mergedFolder.put("threadCount", mergedThreads.length());
} catch (org.json.JSONException ignored) {
}
return mergedFolder;
}
private JSONObject copyJson(@Nullable JSONObject source) {
if (source == null) {
return new JSONObject();
}
try {
return new JSONObject(source.toString());
} catch (org.json.JSONException ignored) {
return new JSONObject();
}
}
private String parseFolderDeviceId(@Nullable String candidateFolderKey) {
if (candidateFolderKey == null) {
return "";