fix: complete folder archive action handling

This commit is contained in:
kris
2026-04-06 05:35:42 +08:00
parent a46f11cf6c
commit 6956d1ac78
7 changed files with 352 additions and 24 deletions

View File

@@ -163,20 +163,19 @@ public class ConversationFolderActivity extends BossScreenActivity {
targetIndices.add(i);
}
}
return targetIndices;
}
if (targetProjectId != null && !targetProjectId.isEmpty()) {
if (targetIndices.isEmpty() && 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;
break;
}
}
}
if (targetProjectLabel != null && !targetProjectLabel.isEmpty()) {
if (targetIndices.isEmpty() && 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", ""))) {

View File

@@ -91,6 +91,32 @@ public class ConversationFolderActivityTest {
assertEquals(0, countTextOccurrences(content, "project-1"));
}
@Test
public void conversationFolderFallsBackFromMissingSearchTargetsToProjectIdThenLabel() throws Exception {
Intent intent = new Intent()
.putExtra(ConversationFolderActivity.EXTRA_FOLDER_KEY, "talking")
.putExtra(ConversationFolderActivity.EXTRA_FOLDER_NAME, "Talking")
.putExtra(ConversationFolderActivity.EXTRA_TARGET_PROJECT_ID, "project-3")
.putExtra(ConversationFolderActivity.EXTRA_TARGET_PROJECT_IDS, new String[]{"project-99", "project-100"})
.putExtra(ConversationFolderActivity.EXTRA_TARGET_PROJECT_LABEL, "日志收口");
TestConversationFolderActivity activity = Robolectric
.buildActivity(TestConversationFolderActivity.class, intent)
.setup()
.get();
ReflectionHelpers.callInstanceMethod(
activity,
"renderFolder",
ReflectionHelpers.ClassParameter.from(JSONObject.class, buildFolderPayload())
);
LinearLayout content = activity.findViewById(R.id.screen_content);
assertTrue(viewTreeContainsText(content, "已定位到目标线程"));
assertTrue(viewTreeContainsText(content, "日志收口"));
assertEquals(0, countTextOccurrences(content, "project-99"));
assertEquals(1, countTextOccurrences(content, "目标线程"));
}
private static JSONObject buildFolderPayload() throws Exception {
JSONArray threads = new JSONArray()
.put(new JSONObject()

View File

@@ -14,6 +14,7 @@ import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
import java.io.IOException;
import java.util.function.BooleanSupplier;
@RunWith(RobolectricTestRunner.class)
@@ -260,6 +261,27 @@ public class MainActivityRealtimeTest {
assertEquals("flat-thread", conversationsData.optJSONObject(0).optString("projectId", ""));
}
@Test
public void refreshConversationsData_fallsBackToFlatConversationsFeedWhenHomeFeedThrowsIOException() throws Exception {
MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().resume().get();
Shadows.shadowOf(activity.getMainLooper()).idle();
RecordingIOExceptionConversationSourceClient apiClient = new RecordingIOExceptionConversationSourceClient(
activity.getSharedPreferences("test-boss-api", Context.MODE_PRIVATE)
);
ReflectionHelpers.setField(activity, "apiClient", apiClient);
ReflectionHelpers.callInstanceMethod(activity, "showContent");
Shadows.shadowOf(activity.getMainLooper()).idle();
activity.refreshConversationsData();
waitFor(() -> apiClient.homeCalls > 0 && apiClient.conversationsCalls > 0);
assertEquals(1, apiClient.homeCalls);
assertEquals(1, apiClient.conversationsCalls);
JSONArray conversationsData = ReflectionHelpers.getField(activity, "conversationsData");
assertEquals("flat-thread", conversationsData.optJSONObject(0).optString("projectId", ""));
}
@Test
public void refreshAllData_prefersConversationHomeFeedOverFlatConversationsFeed() throws Exception {
MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().resume().get();
@@ -308,6 +330,31 @@ public class MainActivityRealtimeTest {
assertEquals("flat-thread", conversationsData.optJSONObject(0).optString("projectId", ""));
}
@Test
public void refreshAllData_fallsBackToFlatConversationsFeedWhenHomeFeedThrowsIOException() throws Exception {
MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().resume().get();
Shadows.shadowOf(activity.getMainLooper()).idle();
RecordingIOExceptionConversationSourceClient apiClient = new RecordingIOExceptionConversationSourceClient(
activity.getSharedPreferences("test-boss-api", Context.MODE_PRIVATE)
);
ReflectionHelpers.setField(activity, "apiClient", apiClient);
ReflectionHelpers.callInstanceMethod(activity, "showContent");
Shadows.shadowOf(activity.getMainLooper()).idle();
ReflectionHelpers.callInstanceMethod(
activity,
"refreshAllData",
ReflectionHelpers.ClassParameter.from(JSONObject.class, new JSONObject())
);
waitFor(() -> apiClient.homeCalls > 0 && apiClient.conversationsCalls > 0);
assertEquals(1, apiClient.homeCalls);
assertEquals(1, apiClient.conversationsCalls);
JSONArray conversationsData = ReflectionHelpers.getField(activity, "conversationsData");
assertEquals("flat-thread", conversationsData.optJSONObject(0).optString("projectId", ""));
}
private static void waitFor(BooleanSupplier condition) throws Exception {
long deadlineAt = System.currentTimeMillis() + 2_000L;
while (System.currentTimeMillis() < deadlineAt) {
@@ -506,4 +553,77 @@ public class MainActivityRealtimeTest {
.put("latestReplyLabel", "11:00"));
}
}
private static final class RecordingIOExceptionConversationSourceClient extends BossApiClient {
int homeCalls;
int conversationsCalls;
int sessionCalls;
int devicesCalls;
int settingsCalls;
int otaCalls;
RecordingIOExceptionConversationSourceClient(android.content.SharedPreferences prefs) {
super(prefs, "https://boss.hyzq.net");
}
@Override
public ApiResponse getConversationHome() throws IOException, org.json.JSONException {
homeCalls += 1;
throw new IOException("HOME_TIMEOUT");
}
@Override
public ApiResponse getConversations() throws IOException, org.json.JSONException {
conversationsCalls += 1;
return new ApiResponse(200, new JSONObject()
.put("ok", true)
.put("conversations", buildFlatConversations()));
}
@Override
public ApiResponse getSession() throws IOException, org.json.JSONException {
sessionCalls += 1;
return new ApiResponse(200, new JSONObject()
.put("ok", true)
.put("session", new JSONObject()
.put("account", "17600003315")
.put("displayName", "Boss 超级管理员")));
}
@Override
public ApiResponse getDevices() throws IOException, org.json.JSONException {
devicesCalls += 1;
return new ApiResponse(200, new JSONObject()
.put("ok", true)
.put("devices", new JSONArray()));
}
@Override
public ApiResponse getSettings() throws IOException, org.json.JSONException {
settingsCalls += 1;
return new ApiResponse(200, new JSONObject()
.put("ok", true)
.put("settings", new JSONObject().put("preferredEntryPoint", "conversations"))
.put("user", new JSONObject()));
}
@Override
public ApiResponse getOtaStatus() throws IOException, org.json.JSONException {
otaCalls += 1;
return new ApiResponse(200, new JSONObject()
.put("ok", true)
.put("hasOta", false));
}
private static JSONArray buildFlatConversations() throws org.json.JSONException {
return new JSONArray().put(new JSONObject()
.put("projectId", "flat-thread")
.put("conversationType", "single_device")
.put("projectTitle", "发布回滚")
.put("threadTitle", "发布回滚")
.put("folderLabel", "Boss")
.put("lastMessagePreview", "最近:发布回滚")
.put("latestReplyLabel", "11:00"));
}
}
}