Skip duplicate chat payloads and batch layouts

This commit is contained in:
kris
2026-04-10 22:45:19 +08:00
parent 05dc9d8788
commit 164a7568a7
2 changed files with 120 additions and 40 deletions

View File

@@ -371,6 +371,9 @@ public class ProjectDetailActivity extends BossScreenActivity {
if (projectMessagesPayload == null) {
return false;
}
if (trySkipUnchangedRealtimeMessagesPatch(projectMessagesPayload)) {
return true;
}
if (tryAppendRealtimeMessagesPatch(projectMessagesPayload)) {
return true;
}
@@ -386,6 +389,33 @@ public class ProjectDetailActivity extends BossScreenActivity {
return true;
}
private boolean trySkipUnchangedRealtimeMessagesPatch(JSONObject projectMessagesPayload) {
if (currentRenderedProjectPayload == null || projectMessagesPayload == null) {
return false;
}
JSONObject currentProject = currentRenderedProjectPayload.optJSONObject("project");
JSONObject nextProject = projectMessagesPayload.optJSONObject("project");
if (currentProject == null || nextProject == null) {
return false;
}
if (!TextUtils.equals(
currentProject.optString("id", "").trim(),
nextProject.optString("id", "").trim()
)) {
return false;
}
JSONArray currentMessages = currentProject.optJSONArray("messages");
JSONArray nextMessages = nextProject.optJSONArray("messages");
if (currentMessages == null || nextMessages == null) {
return false;
}
if (!TextUtils.equals(currentMessages.toString(), nextMessages.toString())) {
return false;
}
currentRenderedProjectPayload = copyJson(projectMessagesPayload);
return true;
}
private boolean tryAppendRealtimeMessagesPatch(JSONObject projectMessagesPayload) {
if (currentRenderedProjectPayload == null
|| contentLayout == null
@@ -434,13 +464,15 @@ public class ProjectDetailActivity extends BossScreenActivity {
selectionState = ProjectChatUiState.reconcileSelection(selectionState, nextIds);
renderNearBottom = isChatNearBottom();
for (int i = currentIds.size(); i < nextMessages.length(); i++) {
JSONObject message = nextMessages.optJSONObject(i);
if (message == null) {
continue;
runWithSuppressedContentLayout(() -> {
for (int i = currentIds.size(); i < nextMessages.length(); i++) {
JSONObject message = nextMessages.optJSONObject(i);
if (message == null) {
continue;
}
appendContent(buildMessageView(message));
}
appendContent(buildMessageView(message));
}
});
currentRenderedProjectPayload = copyJson(projectMessagesPayload);
setRefreshing(false);
updateSelectionUi();
@@ -638,45 +670,47 @@ public class ProjectDetailActivity extends BossScreenActivity {
updateProjectHeader(title, buildProjectSubtitle(projectFolderName, devices));
renderQuickActions();
replaceContent();
pendingOutgoingBubble = null;
if (currentPendingDispatchPlan != null) {
appendContent(buildPendingDispatchPlanView(currentPendingDispatchPlan));
} else if (projectIsGroup && "rejected".equals(projectApprovalState) && currentRejectedDispatchPlan != null) {
appendContent(buildRejectedDispatchPlanView(currentRejectedDispatchPlan));
}
if (projectIsGroup
&& effectiveParticipantsPayload != null
&& effectiveParticipantsPayload.optBoolean("repairRequired", false)) {
appendContent(buildRepairGroupMembersView(effectiveParticipantsPayload));
}
JSONArray messages = project == null ? null : project.optJSONArray("messages");
selectionState = ProjectChatUiState.reconcileSelection(selectionState, collectMessageIds(messages));
if (messages != null && messages.length() > 0) {
for (int i = 0; i < messages.length(); i++) {
JSONObject message = messages.optJSONObject(i);
if (message == null) {
continue;
}
appendContent(buildMessageView(message));
runWithSuppressedContentLayout(() -> {
replaceContent();
pendingOutgoingBubble = null;
if (currentPendingDispatchPlan != null) {
appendContent(buildPendingDispatchPlanView(currentPendingDispatchPlan));
} else if (projectIsGroup && "rejected".equals(projectApprovalState) && currentRejectedDispatchPlan != null) {
appendContent(buildRejectedDispatchPlanView(currentRejectedDispatchPlan));
}
if (projectIsGroup
&& effectiveParticipantsPayload != null
&& effectiveParticipantsPayload.optBoolean("repairRequired", false)) {
appendContent(buildRepairGroupMembersView(effectiveParticipantsPayload));
}
} else {
appendContent(BossUi.buildMessagePlaceholder(this, "还没有项目消息,先发一条开始对话。"));
}
boolean masterAgentHasReply = isMasterAgentConversation()
&& ProjectChatUiState.hasReplyBeyondBaseline(project, masterAgentReplyBaselineMessageId);
if (masterAgentHasReply) {
clearMasterAgentReplyState();
}
if (isMasterAgentConversation()) {
if (masterAgentReplyWaiting) {
appendContent(buildMasterAgentReplyStateView(false));
} else if (masterAgentReplyTimedOut) {
appendContent(buildMasterAgentReplyStateView(true));
if (messages != null && messages.length() > 0) {
for (int i = 0; i < messages.length(); i++) {
JSONObject message = messages.optJSONObject(i);
if (message == null) {
continue;
}
appendContent(buildMessageView(message));
}
} else {
appendContent(BossUi.buildMessagePlaceholder(this, "还没有项目消息,先发一条开始对话。"));
}
}
boolean masterAgentHasReply = isMasterAgentConversation()
&& ProjectChatUiState.hasReplyBeyondBaseline(project, masterAgentReplyBaselineMessageId);
if (masterAgentHasReply) {
clearMasterAgentReplyState();
}
if (isMasterAgentConversation()) {
if (masterAgentReplyWaiting) {
appendContent(buildMasterAgentReplyStateView(false));
} else if (masterAgentReplyTimedOut) {
appendContent(buildMasterAgentReplyStateView(true));
}
}
});
currentRenderedProjectPayload = copyJson(payload);
setRefreshing(false);
@@ -686,6 +720,22 @@ public class ProjectDetailActivity extends BossScreenActivity {
}
}
private void runWithSuppressedContentLayout(Runnable action) {
if (action == null) {
return;
}
if (contentLayout == null) {
action.run();
return;
}
contentLayout.suppressLayout(true);
try {
action.run();
} finally {
contentLayout.suppressLayout(false);
}
}
private void updateRealtimeSubscription() {
if (apiClient != null && apiClient.hasSessionHints()) {
realtimeClient.start();