Fix conversation folder search targeting

This commit is contained in:
kris
2026-04-05 14:51:01 +08:00
parent 272698234d
commit a46f11cf6c
8 changed files with 426 additions and 34 deletions

View File

@@ -681,6 +681,17 @@ public final class BossUi {
boolean selectionMode,
boolean selected,
@Nullable View.OnClickListener listener
) {
return buildConversationRow(context, row, selectionMode, selected, false, listener);
}
public static LinearLayout buildConversationRow(
Context context,
WechatSurfaceMapper.ConversationRow row,
boolean selectionMode,
boolean selected,
boolean highlighted,
@Nullable View.OnClickListener listener
) {
LinearLayout card = new LinearLayout(context);
card.setOrientation(LinearLayout.HORIZONTAL);
@@ -692,7 +703,7 @@ public final class BossUi {
params.bottomMargin = dp(context, 1);
card.setLayoutParams(params);
card.setPadding(dp(context, 16), dp(context, 12), dp(context, 16), dp(context, 12));
card.setBackgroundColor(row.pinnedConversation ? PINNED_ROW_BG : Color.WHITE);
card.setBackgroundColor(highlighted ? Color.parseColor("#EAF8F0") : row.pinnedConversation ? PINNED_ROW_BG : Color.WHITE);
card.setElevation(0f);
if (listener != null) {
card.setClickable(true);
@@ -789,6 +800,23 @@ public final class BossUi {
trailingColumn.addView(selector);
}
if (highlighted) {
TextView targetView = new TextView(context);
targetView.setText("目标线程");
targetView.setTextSize(11);
targetView.setTypeface(Typeface.DEFAULT_BOLD);
targetView.setTextColor(context.getColor(R.color.boss_green));
targetView.setBackground(createRoundedBackground(Color.parseColor("#E7F7EE"), dp(context, 9)));
targetView.setPadding(dp(context, 7), dp(context, 3), dp(context, 7), dp(context, 3));
LinearLayout.LayoutParams targetParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
targetParams.topMargin = dp(context, 8);
targetView.setLayoutParams(targetParams);
trailingColumn.addView(targetView);
}
if (row.unreadCount > 0) {
TextView unreadView = new TextView(context);
unreadView.setText(row.unreadCount > 99 ? "99+" : String.valueOf(row.unreadCount));

View File

@@ -8,19 +8,41 @@ import androidx.annotation.Nullable;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
public class ConversationFolderActivity extends BossScreenActivity {
public static final String EXTRA_FOLDER_KEY = "folder_key";
public static final String EXTRA_FOLDER_NAME = "folder_name";
public static final String EXTRA_TARGET_PROJECT_ID = "target_project_id";
public static final String EXTRA_TARGET_PROJECT_IDS = "target_project_ids";
public static final String EXTRA_TARGET_PROJECT_LABEL = "target_project_label";
private String folderKey;
private String folderName;
private String targetProjectId;
private ArrayList<String> targetProjectIds;
private String targetProjectLabel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
folderKey = getIntent().getStringExtra(EXTRA_FOLDER_KEY);
folderName = getIntent().getStringExtra(EXTRA_FOLDER_NAME);
configureScreen(folderName == null || folderName.isEmpty() ? "项目线程" : folderName, "同一项目下的线程列表");
targetProjectId = getIntent().getStringExtra(EXTRA_TARGET_PROJECT_ID);
targetProjectIds = new ArrayList<>();
String[] extraTargetProjectIds = getIntent().getStringArrayExtra(EXTRA_TARGET_PROJECT_IDS);
if (extraTargetProjectIds != null) {
for (String item : extraTargetProjectIds) {
if (item != null) {
String trimmed = item.trim();
if (!trimmed.isEmpty()) {
targetProjectIds.add(trimmed);
}
}
}
}
targetProjectLabel = getIntent().getStringExtra(EXTRA_TARGET_PROJECT_LABEL);
configureScreen(folderName == null || folderName.isEmpty() ? "项目线程" : folderName, "0 个线程");
refreshButton.setVisibility(android.view.View.GONE);
setHeaderAction("...", v -> showMoreMenu());
reload();
@@ -59,13 +81,12 @@ public class ConversationFolderActivity extends BossScreenActivity {
}
String resolvedFolderName = folder.optString("folderLabel", folderName == null ? "项目线程" : folderName);
String deviceName = folder.optString("deviceName", "");
int threadCount = folder.optInt("threadCount", 0);
configureScreen(resolvedFolderName, deviceName.isEmpty() ? "项目线程" : deviceName);
configureScreen(resolvedFolderName, threadCount + "线程");
appendContent(BossUi.buildSoftPanel(
this,
"项目内部线程页",
resolvedFolderName,
(deviceName.isEmpty() ? "当前设备" : deviceName) + "\n共 " + threadCount + " 个线程",
"点击线程后进入具体聊天窗口。"
));
@@ -75,26 +96,97 @@ public class ConversationFolderActivity extends BossScreenActivity {
setRefreshing(false);
return;
}
for (int i = 0; i < threads.length(); i++) {
JSONObject item = threads.optJSONObject(i);
if (item == null) continue;
String projectId = item.optString("projectId", "");
WechatSurfaceMapper.ConversationRow row = WechatSurfaceMapper.toConversationRow(item);
appendContent(BossUi.buildConversationRow(
ArrayList<Integer> targetIndices = resolveTargetThreadIndices(threads);
if (!targetIndices.isEmpty()) {
String matchedLabel = targetProjectLabel;
if ((matchedLabel == null || matchedLabel.isEmpty())) {
JSONObject firstTarget = threads.optJSONObject(targetIndices.get(0));
if (firstTarget != null) {
matchedLabel = firstTarget.optString("threadTitle", "");
}
}
appendContent(BossUi.buildSoftPanel(
this,
row,
v -> {
if (projectId.isEmpty()) {
showMessage("缺少 projectId");
return;
}
openProject(projectId, row.threadTitle);
}
"已定位到目标线程",
matchedLabel == null || matchedLabel.isEmpty()
? "文件夹页已打开,并将匹配线程置顶显示。"
: matchedLabel,
targetIndices.size() + " 个匹配项已置顶"
));
}
for (int i = 0; i < targetIndices.size(); i++) {
renderThreadAtIndex(threads, targetIndices.get(i), true);
}
for (int i = 0; i < threads.length(); i++) {
if (!targetIndices.contains(i)) {
renderThreadAtIndex(threads, i, false);
}
}
setRefreshing(false);
}
private void renderThreadAtIndex(JSONArray threads, int index, boolean highlighted) {
JSONObject item = threads.optJSONObject(index);
if (item == null) return;
String projectId = item.optString("projectId", "");
WechatSurfaceMapper.ConversationRow row = WechatSurfaceMapper.toConversationRow(item);
appendContent(BossUi.buildConversationRow(
this,
row,
false,
false,
highlighted,
v -> {
if (projectId.isEmpty()) {
showMessage("缺少 projectId");
return;
}
openProject(projectId, row.threadTitle);
}
));
}
private ArrayList<Integer> resolveTargetThreadIndices(JSONArray threads) {
ArrayList<Integer> targetIndices = new ArrayList<>();
if (threads == null || threads.length() == 0) {
return targetIndices;
}
if (!targetProjectIds.isEmpty()) {
for (int i = 0; i < threads.length(); i++) {
JSONObject item = threads.optJSONObject(i);
if (item == null) continue;
String projectId = item.optString("projectId", "");
if (targetProjectIds.contains(projectId)) {
targetIndices.add(i);
}
}
return targetIndices;
}
if (targetProjectId != null && !targetProjectId.isEmpty()) {
for (int i = 0; i < threads.length(); i++) {
JSONObject item = threads.optJSONObject(i);
if (item != null && targetProjectId.equals(item.optString("projectId", ""))) {
targetIndices.add(i);
return targetIndices;
}
}
}
if (targetProjectLabel != null && !targetProjectLabel.isEmpty()) {
for (int i = 0; i < threads.length(); i++) {
JSONObject item = threads.optJSONObject(i);
if (item != null && targetProjectLabel.equals(item.optString("threadTitle", ""))) {
targetIndices.add(i);
}
}
}
return targetIndices;
}
private void openProject(String projectId, String projectName) {
Intent intent = new Intent(this, ProjectDetailActivity.class);
intent.putExtra(ProjectDetailActivity.EXTRA_PROJECT_ID, projectId);

View File

@@ -1091,7 +1091,13 @@ public class MainActivity extends AppCompatActivity {
showMessage("缺少 folderKey");
return;
}
openConversationFolder(folderKey, resolveConversationFolderName(item, row));
openConversationFolder(
folderKey,
resolveConversationFolderName(item, row),
item.optString("searchMatchProjectId", ""),
item.optJSONArray("searchMatchProjectIds"),
item.optString("searchMatchLabel", "")
);
return;
}
if (projectId.isEmpty()) {
@@ -1319,6 +1325,11 @@ public class MainActivity extends AppCompatActivity {
String matchLabel = resolveConversationSearchMatchLabel(item, query);
if (!matchLabel.isEmpty()) {
filteredItem.put("searchMatchLabel", matchLabel);
JSONArray matchProjectIds = resolveConversationSearchMatchTargetIds(item, matchLabel);
if (matchProjectIds.length() > 0) {
filteredItem.put("searchMatchProjectId", matchProjectIds.optString(0, ""));
filteredItem.put("searchMatchProjectIds", matchProjectIds);
}
}
} catch (Exception ignored) {
// Keep the original item if JSON cloning fails.
@@ -1466,6 +1477,33 @@ public class MainActivity extends AppCompatActivity {
return "";
}
private static JSONArray resolveConversationSearchMatchTargetIds(JSONObject item, String matchLabel) {
JSONArray matchedProjectIds = new JSONArray();
if (item == null || matchLabel == null || matchLabel.isEmpty()) {
return matchedProjectIds;
}
JSONArray searchAliases = item.optJSONArray("searchAliases");
JSONArray searchTargetProjectIds = item.optJSONArray("searchTargetProjectIds");
if (searchAliases == null || searchTargetProjectIds == null) {
JSONArray legacyTargets = item.optJSONArray("searchAliasTargets");
if (searchAliases == null || legacyTargets == null) {
return matchedProjectIds;
}
searchTargetProjectIds = legacyTargets;
}
int limit = Math.min(searchAliases.length(), searchTargetProjectIds.length());
for (int i = 0; i < limit; i++) {
String alias = searchAliases.optString(i, "").trim();
if (!alias.isEmpty() && alias.equals(matchLabel)) {
String projectId = searchTargetProjectIds.optString(i, "").trim();
if (!projectId.isEmpty()) {
matchedProjectIds.put(projectId);
}
}
}
return matchedProjectIds;
}
private void renderDevicesRoot() {
if (screenList == null) {
return;
@@ -1583,9 +1621,37 @@ public class MainActivity extends AppCompatActivity {
}
private void openConversationFolder(String folderKey, String folderName) {
openConversationFolder(folderKey, folderName, "", null, "");
}
private void openConversationFolder(
String folderKey,
String folderName,
String targetProjectId,
JSONArray targetProjectIds,
String targetProjectLabel
) {
Intent intent = new Intent(this, ConversationFolderActivity.class);
intent.putExtra(ConversationFolderActivity.EXTRA_FOLDER_KEY, folderKey);
intent.putExtra(ConversationFolderActivity.EXTRA_FOLDER_NAME, folderName);
if (targetProjectId != null && !targetProjectId.isEmpty()) {
intent.putExtra(ConversationFolderActivity.EXTRA_TARGET_PROJECT_ID, targetProjectId);
}
if (targetProjectIds != null && targetProjectIds.length() > 0) {
ArrayList<String> ids = new ArrayList<>();
for (int i = 0; i < targetProjectIds.length(); i++) {
String id = targetProjectIds.optString(i, "").trim();
if (!id.isEmpty()) {
ids.add(id);
}
}
if (!ids.isEmpty()) {
intent.putExtra(ConversationFolderActivity.EXTRA_TARGET_PROJECT_IDS, ids.toArray(new String[0]));
}
}
if (targetProjectLabel != null && !targetProjectLabel.isEmpty()) {
intent.putExtra(ConversationFolderActivity.EXTRA_TARGET_PROJECT_LABEL, targetProjectLabel);
}
startActivity(intent);
}