fix: keep chat scroll usable while sending

This commit is contained in:
kris
2026-04-18 05:23:14 +08:00
parent 449f84fcbc
commit bb237fdd4f
4 changed files with 133 additions and 31 deletions

View File

@@ -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;

View File

@@ -141,18 +141,17 @@
android:paddingRight="12dp"
android:paddingBottom="12dp">
<Button
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/project_chat_attach"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginRight="8dp"
android:background="@drawable/bg_secondary_button"
android:minWidth="0dp"
android:text="+"
android:textAllCaps="false"
android:textColor="@color/boss_text_primary"
android:textSize="20sp"
android:textStyle="bold" />
android:contentDescription="发送附件"
android:padding="12dp"
android:scaleType="center"
android:src="@drawable/ic_boss_add"
android:tint="@color/boss_text_primary" />
<EditText
android:id="@+id/project_chat_input"