feat: add wechat style native message forwarding
This commit is contained in:
@@ -723,6 +723,107 @@ public final class BossUi {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
public static LinearLayout buildForwardSingleBubble(
|
||||
Context context,
|
||||
String senderLabel,
|
||||
String body,
|
||||
@Nullable String meta,
|
||||
@Nullable String sourceLabel,
|
||||
boolean outgoing
|
||||
) {
|
||||
LinearLayout wrapper = buildMessageBubble(
|
||||
context,
|
||||
senderLabel,
|
||||
body,
|
||||
meta,
|
||||
outgoing,
|
||||
ProjectChatUiState.labelForForwardKind("forward_single")
|
||||
);
|
||||
if (wrapper.getChildCount() < 2 || !(wrapper.getChildAt(1) instanceof LinearLayout)) {
|
||||
return wrapper;
|
||||
}
|
||||
LinearLayout bubble = (LinearLayout) wrapper.getChildAt(1);
|
||||
if (!TextUtils.isEmpty(sourceLabel)) {
|
||||
TextView sourceView = new TextView(context);
|
||||
sourceView.setText("来自 " + sourceLabel);
|
||||
sourceView.setTextSize(12);
|
||||
sourceView.setTextColor(context.getColor(outgoing ? R.color.boss_surface : R.color.boss_text_muted));
|
||||
sourceView.setAlpha(outgoing ? 0.85f : 1f);
|
||||
sourceView.setPadding(0, 0, 0, dp(context, 8));
|
||||
bubble.addView(sourceView, Math.min(1, bubble.getChildCount()));
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
public static LinearLayout buildForwardBundleCard(
|
||||
Context context,
|
||||
String senderLabel,
|
||||
String cardTitle,
|
||||
String summary,
|
||||
@Nullable String meta,
|
||||
boolean outgoing
|
||||
) {
|
||||
LinearLayout wrapper = new LinearLayout(context);
|
||||
wrapper.setOrientation(LinearLayout.VERTICAL);
|
||||
wrapper.setGravity(outgoing ? Gravity.END : Gravity.START);
|
||||
LinearLayout.LayoutParams wrapperParams = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
wrapperParams.bottomMargin = dp(context, 12);
|
||||
wrapper.setLayoutParams(wrapperParams);
|
||||
|
||||
TextView metaView = new TextView(context);
|
||||
String metaText = senderLabel;
|
||||
if (!TextUtils.isEmpty(meta)) {
|
||||
metaText = metaText + " · " + meta;
|
||||
}
|
||||
metaView.setText(metaText);
|
||||
metaView.setTextSize(11);
|
||||
metaView.setTextColor(context.getColor(R.color.boss_text_soft));
|
||||
metaView.setPadding(dp(context, 6), 0, dp(context, 6), dp(context, 4));
|
||||
wrapper.addView(metaView);
|
||||
|
||||
LinearLayout card = new LinearLayout(context);
|
||||
card.setOrientation(LinearLayout.VERTICAL);
|
||||
card.setMinimumWidth(dp(context, 180));
|
||||
card.setPadding(dp(context, 14), dp(context, 12), dp(context, 14), dp(context, 12));
|
||||
card.setBackground(createRoundedBackground(
|
||||
outgoing ? Color.parseColor("#CFF0D8") : Color.WHITE,
|
||||
dp(context, 18)
|
||||
));
|
||||
card.setElevation(dp(context, 1));
|
||||
|
||||
TextView kindView = new TextView(context);
|
||||
kindView.setText(ProjectChatUiState.labelForForwardKind("forward_bundle"));
|
||||
kindView.setTextSize(11);
|
||||
kindView.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
kindView.setTextColor(context.getColor(R.color.boss_text_muted));
|
||||
card.addView(kindView);
|
||||
|
||||
TextView titleView = new TextView(context);
|
||||
titleView.setText(TextUtils.isEmpty(cardTitle) ? "聊天记录" : cardTitle);
|
||||
titleView.setTextSize(15);
|
||||
titleView.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
titleView.setTextColor(context.getColor(R.color.boss_text_primary));
|
||||
titleView.setPadding(0, dp(context, 6), 0, 0);
|
||||
titleView.setMaxLines(2);
|
||||
titleView.setEllipsize(TextUtils.TruncateAt.END);
|
||||
card.addView(titleView);
|
||||
|
||||
TextView summaryView = new TextView(context);
|
||||
summaryView.setText(TextUtils.isEmpty(summary) ? "转发的聊天记录" : summary);
|
||||
summaryView.setTextSize(13);
|
||||
summaryView.setLineSpacing(0f, 1.2f);
|
||||
summaryView.setTextColor(context.getColor(R.color.boss_text_muted));
|
||||
summaryView.setPadding(0, dp(context, 8), 0, 0);
|
||||
summaryView.setMaxWidth(Math.round(context.getResources().getDisplayMetrics().widthPixels * 0.72f));
|
||||
card.addView(summaryView);
|
||||
|
||||
wrapper.addView(card);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
public static LinearLayout buildPendingOutgoingMessageBubble(
|
||||
Context context,
|
||||
String senderLabel,
|
||||
@@ -732,6 +833,19 @@ public final class BossUi {
|
||||
return buildMessageBubble(context, effectiveSender, body, "发送中", true, null);
|
||||
}
|
||||
|
||||
public static void applyMessageSelectionState(Context context, View messageView, boolean selected) {
|
||||
if (messageView == null) {
|
||||
return;
|
||||
}
|
||||
if (selected) {
|
||||
messageView.setBackground(createRoundedBackground(Color.parseColor("#EAF7F0"), dp(context, 20)));
|
||||
messageView.setAlpha(1f);
|
||||
} else {
|
||||
messageView.setBackgroundColor(Color.TRANSPARENT);
|
||||
messageView.setAlpha(1f);
|
||||
}
|
||||
}
|
||||
|
||||
public static TextView buildMessagePlaceholder(Context context, String text) {
|
||||
TextView placeholder = new TextView(context);
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
|
||||
@@ -32,6 +32,10 @@ public final class ProjectChatUiState {
|
||||
return new SelectionState(new LinkedHashSet<>());
|
||||
}
|
||||
|
||||
public static SelectionState selectOnly(String messageId) {
|
||||
return toggleSelection(emptySelection(), messageId);
|
||||
}
|
||||
|
||||
public static SelectionState toggleSelection(@Nullable SelectionState current, String messageId) {
|
||||
if (messageId == null || messageId.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("messageId must not be blank");
|
||||
@@ -49,4 +53,15 @@ public final class ProjectChatUiState {
|
||||
public static boolean canForwardSelection(@Nullable SelectionState state) {
|
||||
return state != null && state.multiSelecting && state.selectedMessageIds.size() >= 2;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String labelForForwardKind(@Nullable String kind) {
|
||||
if ("forward_single".equals(kind)) {
|
||||
return "转发";
|
||||
}
|
||||
if ("forward_bundle".equals(kind)) {
|
||||
return "聊天记录";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.hyzq.boss;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
@@ -14,10 +16,14 @@ import android.widget.ScrollView;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ProjectDetailActivity extends BossScreenActivity {
|
||||
public static final String EXTRA_PROJECT_ID = "project_id";
|
||||
public static final String EXTRA_PROJECT_NAME = "project_name";
|
||||
@@ -27,14 +33,22 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
||||
private boolean projectIsGroup;
|
||||
private String projectFolderName;
|
||||
private LinearLayout quickActionsLayout;
|
||||
private LinearLayout composerRow;
|
||||
private LinearLayout multiSelectActionsLayout;
|
||||
private EditText composerInput;
|
||||
private Button composerSendButton;
|
||||
private Button multiSelectForwardButton;
|
||||
private ScrollView chatScrollView;
|
||||
private View pendingOutgoingBubble;
|
||||
private boolean composerSending;
|
||||
private boolean renderNearBottom;
|
||||
private boolean renderForcedScrollToBottom;
|
||||
private boolean conversationInfoReady;
|
||||
private String currentScreenTitle;
|
||||
private String currentScreenSubtitle;
|
||||
private ProjectChatUiState.SelectionState selectionState = ProjectChatUiState.emptySelection();
|
||||
private ActivityResultLauncher<Intent> conversationInfoLauncher;
|
||||
private ActivityResultLauncher<Intent> forwardTargetLauncher;
|
||||
|
||||
@Override
|
||||
protected int getLayoutResId() {
|
||||
@@ -47,8 +61,11 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
||||
projectId = getIntent().getStringExtra(EXTRA_PROJECT_ID);
|
||||
initialProjectName = getIntent().getStringExtra(EXTRA_PROJECT_NAME);
|
||||
quickActionsLayout = findViewById(R.id.project_chat_quick_actions);
|
||||
composerRow = findViewById(R.id.project_chat_composer_row);
|
||||
multiSelectActionsLayout = findViewById(R.id.project_chat_multi_select_actions);
|
||||
composerInput = findViewById(R.id.project_chat_input);
|
||||
composerSendButton = findViewById(R.id.project_chat_send);
|
||||
multiSelectForwardButton = findViewById(R.id.project_chat_multi_forward);
|
||||
chatScrollView = findViewById(R.id.project_chat_scroll);
|
||||
conversationInfoLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
@@ -61,15 +78,32 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
||||
String updatedTitle = data.getStringExtra(ConversationInfoActivity.EXTRA_PROJECT_NAME);
|
||||
if (!TextUtils.isEmpty(updatedTitle)) {
|
||||
initialProjectName = updatedTitle;
|
||||
configureScreen(updatedTitle, "正在同步项目详情...");
|
||||
updateProjectHeader(updatedTitle, "正在同步项目详情...");
|
||||
}
|
||||
}
|
||||
reload();
|
||||
}
|
||||
);
|
||||
forwardTargetLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() != RESULT_OK) {
|
||||
return;
|
||||
}
|
||||
exitMultiSelect();
|
||||
reload(true);
|
||||
}
|
||||
);
|
||||
|
||||
configureScreen(initialProjectName == null ? "项目详情" : initialProjectName, "正在同步项目详情...");
|
||||
updateProjectHeader(initialProjectName == null ? "项目详情" : initialProjectName, "正在同步项目详情...");
|
||||
composerSendButton.setOnClickListener(v -> sendTextMessageFromComposer());
|
||||
multiSelectForwardButton.setOnClickListener(v -> {
|
||||
if (!ProjectChatUiState.canForwardSelection(selectionState)) {
|
||||
showMessage("至少选择两条消息后才能合并转发");
|
||||
return;
|
||||
}
|
||||
openBundleForwardTarget(new ArrayList<>(selectionState.selectedMessageIds));
|
||||
});
|
||||
composerInput.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
@@ -83,6 +117,7 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
||||
public void afterTextChanged(Editable s) {}
|
||||
});
|
||||
updateComposerSendButtonState();
|
||||
updateSelectionUi();
|
||||
reload(true);
|
||||
}
|
||||
|
||||
@@ -129,6 +164,7 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
||||
composerInput.setEnabled(!refreshing);
|
||||
}
|
||||
updateComposerSendButtonState();
|
||||
updateSelectionUi();
|
||||
}
|
||||
|
||||
private void renderProject(JSONObject payload) {
|
||||
@@ -140,8 +176,8 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
||||
initialProjectName = title;
|
||||
projectIsGroup = project != null && project.optBoolean("isGroup", false);
|
||||
projectFolderName = threadMeta == null ? "" : threadMeta.optString("folderName", "");
|
||||
configureScreen(title, buildProjectSubtitle(projectFolderName, devices));
|
||||
setHeaderAction(WechatSurfaceMapper.conversationInfoActionLabel(), v -> openConversationInfo());
|
||||
conversationInfoReady = project != null;
|
||||
updateProjectHeader(title, buildProjectSubtitle(projectFolderName, devices));
|
||||
|
||||
renderQuickActions();
|
||||
replaceContent();
|
||||
@@ -154,20 +190,14 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
||||
if (message == null) {
|
||||
continue;
|
||||
}
|
||||
appendContent(BossUi.buildMessageBubble(
|
||||
this,
|
||||
message.optString("senderLabel", "消息"),
|
||||
message.optString("body", ""),
|
||||
formatMessageTime(message.optString("sentAt", "")),
|
||||
isOutgoingMessage(message.optString("senderLabel", "")),
|
||||
labelForMessageKind(message.optString("kind", ""))
|
||||
));
|
||||
appendContent(buildMessageView(message));
|
||||
}
|
||||
} else {
|
||||
appendContent(BossUi.buildMessagePlaceholder(this, "还没有项目消息,先发一条开始对话。"));
|
||||
}
|
||||
|
||||
setRefreshing(false);
|
||||
updateSelectionUi();
|
||||
if (ProjectChatUiState.shouldAutoScroll(renderNearBottom, renderForcedScrollToBottom)) {
|
||||
scrollChatToBottom();
|
||||
}
|
||||
@@ -278,6 +308,217 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
||||
conversationInfoLauncher.launch(intent);
|
||||
}
|
||||
|
||||
private View buildMessageView(JSONObject message) {
|
||||
String messageId = message.optString("id", "");
|
||||
String senderLabel = message.optString("senderLabel", "消息");
|
||||
String body = message.optString("body", "");
|
||||
String meta = formatMessageTime(message.optString("sentAt", ""));
|
||||
String kind = message.optString("kind", "");
|
||||
boolean outgoing = isOutgoingMessage(senderLabel);
|
||||
|
||||
View messageView;
|
||||
switch (kind) {
|
||||
case "forward_single":
|
||||
messageView = BossUi.buildForwardSingleBubble(
|
||||
this,
|
||||
senderLabel,
|
||||
body,
|
||||
meta,
|
||||
resolveForwardSingleSourceLabel(message),
|
||||
outgoing
|
||||
);
|
||||
break;
|
||||
case "forward_bundle":
|
||||
messageView = BossUi.buildForwardBundleCard(
|
||||
this,
|
||||
senderLabel,
|
||||
resolveForwardBundleTitle(message),
|
||||
resolveForwardBundleSummary(message),
|
||||
meta,
|
||||
outgoing
|
||||
);
|
||||
break;
|
||||
default:
|
||||
messageView = BossUi.buildMessageBubble(
|
||||
this,
|
||||
senderLabel,
|
||||
body,
|
||||
meta,
|
||||
outgoing,
|
||||
labelForMessageKind(kind)
|
||||
);
|
||||
break;
|
||||
}
|
||||
bindMessageInteractions(messageView, messageId, body);
|
||||
return messageView;
|
||||
}
|
||||
|
||||
private void bindMessageInteractions(View messageView, String messageId, String body) {
|
||||
if (messageView == null || TextUtils.isEmpty(messageId)) {
|
||||
return;
|
||||
}
|
||||
messageView.setTag(messageId);
|
||||
messageView.setClickable(true);
|
||||
messageView.setLongClickable(true);
|
||||
messageView.setOnClickListener(v -> {
|
||||
if (!selectionState.multiSelecting) {
|
||||
return;
|
||||
}
|
||||
toggleMultiSelectMessage(messageId);
|
||||
});
|
||||
messageView.setOnLongClickListener(v -> {
|
||||
showMessageActions(messageId, body);
|
||||
return true;
|
||||
});
|
||||
BossUi.applyMessageSelectionState(
|
||||
this,
|
||||
messageView,
|
||||
selectionState.selectedMessageIds.contains(messageId)
|
||||
);
|
||||
}
|
||||
|
||||
private void showMessageActions(String messageId, String body) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("消息操作")
|
||||
.setItems(new CharSequence[]{"转发", "多选", "复制", "删除", "取消"}, (dialog, which) -> {
|
||||
switch (which) {
|
||||
case 0:
|
||||
openSingleForwardTarget(messageId);
|
||||
break;
|
||||
case 1:
|
||||
enterMultiSelectFromMessage(messageId);
|
||||
break;
|
||||
case 2:
|
||||
copyMessageBody(body);
|
||||
break;
|
||||
case 3:
|
||||
showMessage("删除消息能力暂未接通");
|
||||
break;
|
||||
default:
|
||||
dialog.dismiss();
|
||||
break;
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void copyMessageBody(String body) {
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||
if (clipboard == null) {
|
||||
showMessage("当前设备不支持复制");
|
||||
return;
|
||||
}
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText("boss-message", TextUtils.isEmpty(body) ? "" : body));
|
||||
showMessage("已复制消息");
|
||||
}
|
||||
|
||||
private void openSingleForwardTarget(String sourceMessageId) {
|
||||
if (TextUtils.isEmpty(sourceMessageId)) {
|
||||
showMessage("缺少消息 ID");
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(this, ForwardTargetActivity.class);
|
||||
intent.putExtra(ForwardTargetActivity.EXTRA_SOURCE_PROJECT_ID, projectId);
|
||||
intent.putExtra(ForwardTargetActivity.EXTRA_FORWARD_MODE, "single");
|
||||
intent.putExtra(ForwardTargetActivity.EXTRA_SOURCE_MESSAGE_ID, sourceMessageId);
|
||||
forwardTargetLauncher.launch(intent);
|
||||
}
|
||||
|
||||
private void openBundleForwardTarget(List<String> sourceMessageIds) {
|
||||
if (sourceMessageIds == null || sourceMessageIds.size() < 2) {
|
||||
showMessage("至少选择两条消息后才能合并转发");
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(this, ForwardTargetActivity.class);
|
||||
intent.putExtra(ForwardTargetActivity.EXTRA_SOURCE_PROJECT_ID, projectId);
|
||||
intent.putExtra(ForwardTargetActivity.EXTRA_FORWARD_MODE, "bundle");
|
||||
intent.putExtra(
|
||||
ForwardTargetActivity.EXTRA_SOURCE_MESSAGE_IDS,
|
||||
sourceMessageIds.toArray(new String[0])
|
||||
);
|
||||
forwardTargetLauncher.launch(intent);
|
||||
}
|
||||
|
||||
private void enterMultiSelectFromMessage(String messageId) {
|
||||
selectionState = ProjectChatUiState.selectOnly(messageId);
|
||||
updateSelectionUi();
|
||||
}
|
||||
|
||||
private void exitMultiSelect() {
|
||||
selectionState = ProjectChatUiState.emptySelection();
|
||||
updateSelectionUi();
|
||||
}
|
||||
|
||||
private void toggleMultiSelectMessage(String messageId) {
|
||||
ProjectChatUiState.SelectionState next = ProjectChatUiState.toggleSelection(selectionState, messageId);
|
||||
if (!next.multiSelecting) {
|
||||
exitMultiSelect();
|
||||
return;
|
||||
}
|
||||
selectionState = next;
|
||||
updateSelectionUi();
|
||||
}
|
||||
|
||||
private void updateSelectionUi() {
|
||||
boolean multiSelecting = selectionState != null && selectionState.multiSelecting;
|
||||
if (composerRow != null) {
|
||||
composerRow.setVisibility(multiSelecting ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
if (multiSelectActionsLayout != null) {
|
||||
multiSelectActionsLayout.setVisibility(multiSelecting ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
if (multiSelectForwardButton != null) {
|
||||
multiSelectForwardButton.setEnabled(!isComposerBusy() && ProjectChatUiState.canForwardSelection(selectionState));
|
||||
}
|
||||
if (refreshLayout != null) {
|
||||
refreshLayout.setEnabled(!multiSelecting);
|
||||
}
|
||||
|
||||
if (multiSelecting) {
|
||||
backButton.setText("取消");
|
||||
backButton.setOnClickListener(v -> exitMultiSelect());
|
||||
refreshButton.setVisibility(View.GONE);
|
||||
hideHeaderAction();
|
||||
titleView.setText("已选 " + selectionState.selectedMessageIds.size() + " 条");
|
||||
subtitleView.setText("选择要转发的消息");
|
||||
} else {
|
||||
backButton.setText("返回");
|
||||
backButton.setOnClickListener(v -> finish());
|
||||
refreshButton.setVisibility(View.VISIBLE);
|
||||
titleView.setText(TextUtils.isEmpty(currentScreenTitle) ? "项目详情" : currentScreenTitle);
|
||||
subtitleView.setText(TextUtils.isEmpty(currentScreenSubtitle) ? "原生页面" : currentScreenSubtitle);
|
||||
if (conversationInfoReady) {
|
||||
setHeaderAction(WechatSurfaceMapper.conversationInfoActionLabel(), v -> openConversationInfo());
|
||||
} else {
|
||||
hideHeaderAction();
|
||||
}
|
||||
}
|
||||
refreshMessageSelectionViews();
|
||||
}
|
||||
|
||||
private void refreshMessageSelectionViews() {
|
||||
if (contentLayout == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < contentLayout.getChildCount(); i++) {
|
||||
View child = contentLayout.getChildAt(i);
|
||||
Object tag = child.getTag();
|
||||
boolean selected = tag instanceof String
|
||||
&& selectionState != null
|
||||
&& selectionState.selectedMessageIds.contains(tag);
|
||||
BossUi.applyMessageSelectionState(this, child, selected);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProjectHeader(String title, String subtitle) {
|
||||
currentScreenTitle = title;
|
||||
currentScreenSubtitle = subtitle;
|
||||
if (selectionState != null && selectionState.multiSelecting) {
|
||||
return;
|
||||
}
|
||||
configureScreen(title, subtitle);
|
||||
}
|
||||
|
||||
private String joinDeviceNames(@Nullable JSONArray devices) {
|
||||
if (devices == null || devices.length() == 0) {
|
||||
return "未绑定设备";
|
||||
@@ -379,11 +620,58 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
||||
return sentAt;
|
||||
}
|
||||
|
||||
private String resolveForwardSingleSourceLabel(JSONObject message) {
|
||||
JSONObject forwardSource = message.optJSONObject("forwardSource");
|
||||
if (forwardSource == null) {
|
||||
return "";
|
||||
}
|
||||
String threadTitle = forwardSource.optString("sourceThreadTitle", "");
|
||||
if (!TextUtils.isEmpty(threadTitle)) {
|
||||
return threadTitle;
|
||||
}
|
||||
return forwardSource.optString("sourceProjectName", "");
|
||||
}
|
||||
|
||||
private String resolveForwardBundleTitle(JSONObject message) {
|
||||
JSONObject forwardBundle = message.optJSONObject("forwardBundle");
|
||||
if (forwardBundle == null) {
|
||||
return "聊天记录";
|
||||
}
|
||||
String threadTitle = forwardBundle.optString("sourceThreadTitle", "");
|
||||
if (!TextUtils.isEmpty(threadTitle)) {
|
||||
return threadTitle;
|
||||
}
|
||||
String projectName = forwardBundle.optString("sourceProjectName", "");
|
||||
return TextUtils.isEmpty(projectName) ? "聊天记录" : projectName;
|
||||
}
|
||||
|
||||
private String resolveForwardBundleSummary(JSONObject message) {
|
||||
JSONObject forwardBundle = message.optJSONObject("forwardBundle");
|
||||
if (forwardBundle == null) {
|
||||
return message.optString("body", "转发的聊天记录");
|
||||
}
|
||||
int itemCount = forwardBundle.optInt("itemCount", 0);
|
||||
JSONArray items = forwardBundle.optJSONArray("items");
|
||||
JSONObject lastItem = items == null || items.length() == 0 ? null : items.optJSONObject(items.length() - 1);
|
||||
String lastBody = lastItem == null ? "" : lastItem.optString("body", "");
|
||||
if (itemCount > 0 && !TextUtils.isEmpty(lastBody)) {
|
||||
return itemCount + " 条消息 · 最后一条:" + lastBody;
|
||||
}
|
||||
if (itemCount > 0) {
|
||||
return itemCount + " 条消息";
|
||||
}
|
||||
return message.optString("body", "转发的聊天记录");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String labelForMessageKind(String kind) {
|
||||
if (TextUtils.isEmpty(kind) || "text".equals(kind)) {
|
||||
return null;
|
||||
}
|
||||
String forwardLabel = ProjectChatUiState.labelForForwardKind(kind);
|
||||
if (!TextUtils.isEmpty(forwardLabel)) {
|
||||
return forwardLabel;
|
||||
}
|
||||
switch (kind) {
|
||||
case "voice_intent":
|
||||
return "语音";
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/project_chat_composer_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/boss_surface"
|
||||
@@ -163,4 +164,28 @@
|
||||
android:textColor="@color/boss_surface"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/project_chat_multi_select_actions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/boss_surface"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<Button
|
||||
android:id="@+id/project_chat_multi_forward"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="44dp"
|
||||
android:background="@drawable/bg_primary_button"
|
||||
android:text="转发"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/boss_surface"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -72,4 +72,14 @@ public class ProjectChatUiStateTest {
|
||||
assertEquals("messageId must not be blank", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleForwardMessageUsesSingleModeLabel() {
|
||||
assertEquals("转发", ProjectChatUiState.labelForForwardKind("forward_single"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bundleForwardMessageUsesBundleModeLabel() {
|
||||
assertEquals("聊天记录", ProjectChatUiState.labelForForwardKind("forward_bundle"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user