diff --git a/android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java b/android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java index ae4eb9b..c0f2800 100644 --- a/android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java +++ b/android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java @@ -19,6 +19,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; +import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; @@ -61,7 +62,7 @@ public class ProjectDetailActivity extends BossScreenActivity { private LinearLayout quickActionsLayout; private LinearLayout composerRow; private LinearLayout multiSelectActionsLayout; - private Button composerAttachmentButton; + private ImageButton composerAttachmentButton; private EditText composerInput; private Button composerSendButton; private Button multiSelectForwardButton; @@ -105,6 +106,7 @@ public class ProjectDetailActivity extends BossScreenActivity { private boolean realtimeReloadRequiresFullSnapshot; private boolean reloadInFlight; private boolean pendingReload; + private boolean pendingReloadMessagesOnly; private boolean pendingReloadForcedScrollToBottom; private volatile boolean activityDestroyed; private final Runnable conversationAutoRefreshRunnable = new Runnable() { @@ -114,7 +116,7 @@ public class ProjectDetailActivity extends BossScreenActivity { if (!shouldMaintainConversationAutoRefresh()) { return; } - if (!reloadInFlight && !refreshLayout.isRefreshing() && shouldAutoRefreshConversation()) { + if (!reloadInFlight && !isComposerBusy() && shouldAutoRefreshConversation()) { reload(false); } armConversationAutoRefresh(); @@ -280,6 +282,7 @@ public class ProjectDetailActivity extends BossScreenActivity { BossWindowInsets.applyKeyboardAvoidingInset(composerRow); BossWindowInsets.applyKeyboardAvoidingInset(multiSelectActionsLayout); + bindChatRefreshScrollBridge(); updateProjectHeader(initialProjectName == null ? "项目详情" : initialProjectName, "正在同步项目详情..."); if (composerAttachmentButton != null) { @@ -352,6 +355,18 @@ public class ProjectDetailActivity extends BossScreenActivity { reload(false); } + private void bindChatRefreshScrollBridge() { + if (refreshLayout == null) { + return; + } + refreshLayout.setOnChildScrollUpCallback((parent, child) -> { + if (chatScrollView == null || chatScrollView.getVisibility() != View.VISIBLE) { + return false; + } + return chatScrollView.canScrollVertically(-1) || chatScrollView.getScrollY() > 0; + }); + } + void handleRealtimeEvent(BossRealtimeEvent event) { if (event == null || event.eventName.isEmpty() || projectId == null || projectId.isEmpty()) { return; @@ -371,7 +386,7 @@ public class ProjectDetailActivity extends BossScreenActivity { if (tryApplyRealtimeMessagesPatch(event)) { return; } - runOnUiThread(() -> scheduleRealtimeReload(true)); + runOnUiThread(() -> scheduleRealtimeReload(!"project.messages.updated".equals(event.eventName))); } private boolean tryApplyRealtimeMessagesPatch(BossRealtimeEvent event) { @@ -562,6 +577,10 @@ public class ProjectDetailActivity extends BossScreenActivity { return; } if (reloadInFlight) { + pendingReloadMessagesOnly = pendingReload && pendingReloadMessagesOnly && messagesOnly; + if (!pendingReload) { + pendingReloadMessagesOnly = messagesOnly; + } pendingReload = true; pendingReloadForcedScrollToBottom = pendingReloadForcedScrollToBottom || forcedScrollToBottom; return; @@ -641,20 +660,16 @@ public class ProjectDetailActivity extends BossScreenActivity { return; } boolean forcedScrollToBottom = pendingReloadForcedScrollToBottom; + boolean messagesOnly = pendingReloadMessagesOnly; pendingReload = false; + pendingReloadMessagesOnly = false; pendingReloadForcedScrollToBottom = false; - reload(forcedScrollToBottom); + reloadSnapshot(forcedScrollToBottom, messagesOnly); } @Override protected void setRefreshing(boolean refreshing) { super.setRefreshing(refreshing); - if (composerAttachmentButton != null) { - composerAttachmentButton.setEnabled(!refreshing && !composerSending); - } - if (composerInput != null) { - composerInput.setEnabled(!refreshing); - } updateComposerSendButtonState(); updateSelectionUi(); if (!refreshing) { @@ -788,7 +803,7 @@ public class ProjectDetailActivity extends BossScreenActivity { && shouldMaintainConversationAutoRefresh() && !reloadInFlight && refreshLayout != null - && !refreshLayout.isRefreshing()) { + && !isComposerBusy()) { reload(); } updateConversationAutoRefresh(); @@ -1017,7 +1032,6 @@ public class ProjectDetailActivity extends BossScreenActivity { private void sendProjectMessage(String kind, String body) { composerSending = true; updateComposerSendButtonState(); - setRefreshing(true); appendPendingOutgoingBubble(body); scrollChatToBottom(); executor.execute(() -> { @@ -1220,7 +1234,6 @@ public class ProjectDetailActivity extends BossScreenActivity { private void uploadAttachment(AttachmentComposerState.PendingAttachment attachment) { composerSending = true; updateComposerSendButtonState(); - setRefreshing(true); appendPendingOutgoingAttachment(attachment); scrollChatToBottom(); executor.execute(() -> { @@ -2361,8 +2374,13 @@ public class ProjectDetailActivity extends BossScreenActivity { if (composerSendButton == null || composerInput == null) { return; } + boolean composerBusy = isComposerBusy(); + if (composerAttachmentButton != null) { + composerAttachmentButton.setEnabled(!composerBusy); + } + composerInput.setEnabled(!composerBusy); String body = composerInput.getText() == null ? "" : composerInput.getText().toString(); - composerSendButton.setEnabled(ProjectChatUiState.canSend(body, isComposerBusy())); + composerSendButton.setEnabled(ProjectChatUiState.canSend(body, composerBusy)); } private boolean isComposerBusy() { @@ -2698,7 +2716,6 @@ public class ProjectDetailActivity extends BossScreenActivity { } composerSending = true; updateComposerSendButtonState(); - setRefreshing(true); showMessage(waitingMessage); enqueueReplyWaitPoll(waitSpec.baselineMessageId, includeDispatchPlans); } @@ -2781,7 +2798,6 @@ public class ProjectDetailActivity extends BossScreenActivity { if (!hasReply && !isMasterAgentConversation()) { composerSending = true; updateComposerSendButtonState(); - setRefreshing(true); } }); renderedInitialSnapshot = true; diff --git a/android/app/src/main/res/layout/activity_project_chat.xml b/android/app/src/main/res/layout/activity_project_chat.xml index 8613603..fcce8e5 100644 --- a/android/app/src/main/res/layout/activity_project_chat.xml +++ b/android/app/src/main/res/layout/activity_project_chat.xml @@ -141,18 +141,17 @@ android:paddingRight="12dp" android:paddingBottom="12dp"> -