fix: group fallback conversation feed into folder archives on android

This commit is contained in:
kris
2026-04-06 06:55:06 +08:00
parent b7492e4789
commit d28afb2df1
3 changed files with 414 additions and 38 deletions

View File

@@ -241,7 +241,7 @@ public class MainActivityRealtimeTest {
}
@Test
public void refreshConversationsData_fallsBackToFlatConversationsFeedWhenHomeFeedFails() throws Exception {
public void refreshConversationsData_groupsFlatFallbackFeedWhenHomeFeedFails() throws Exception {
MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().resume().get();
Shadows.shadowOf(activity.getMainLooper()).idle();
@@ -253,16 +253,18 @@ public class MainActivityRealtimeTest {
Shadows.shadowOf(activity.getMainLooper()).idle();
activity.refreshConversationsData();
waitFor(() -> apiClient.homeCalls > 0 && apiClient.conversationsCalls > 0);
waitFor(() -> apiClient.homeCalls > 0 && apiClient.conversationsCalls > 0 && hasConversationData(activity));
assertEquals(1, apiClient.homeCalls);
assertEquals(1, apiClient.conversationsCalls);
JSONArray conversationsData = ReflectionHelpers.getField(activity, "conversationsData");
assertEquals("flat-thread", conversationsData.optJSONObject(0).optString("projectId", ""));
assertEquals("folder_archive", conversationsData.optJSONObject(0).optString("conversationType", ""));
assertEquals("mac-studio:boss", conversationsData.optJSONObject(0).optString("projectId", ""));
assertEquals(2, conversationsData.optJSONObject(0).optInt("threadCount", 0));
}
@Test
public void refreshConversationsData_fallsBackToFlatConversationsFeedWhenHomeFeedThrowsIOException() throws Exception {
public void refreshConversationsData_groupsFlatFallbackFeedWhenHomeFeedThrowsIOException() throws Exception {
MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().resume().get();
Shadows.shadowOf(activity.getMainLooper()).idle();
@@ -274,12 +276,14 @@ public class MainActivityRealtimeTest {
Shadows.shadowOf(activity.getMainLooper()).idle();
activity.refreshConversationsData();
waitFor(() -> apiClient.homeCalls > 0 && apiClient.conversationsCalls > 0);
waitFor(() -> apiClient.homeCalls > 0 && apiClient.conversationsCalls > 0 && hasConversationData(activity));
assertEquals(1, apiClient.homeCalls);
assertEquals(1, apiClient.conversationsCalls);
JSONArray conversationsData = ReflectionHelpers.getField(activity, "conversationsData");
assertEquals("flat-thread", conversationsData.optJSONObject(0).optString("projectId", ""));
assertEquals("folder_archive", conversationsData.optJSONObject(0).optString("conversationType", ""));
assertEquals("mac-studio:boss", conversationsData.optJSONObject(0).optString("projectId", ""));
assertEquals(2, conversationsData.optJSONObject(0).optInt("threadCount", 0));
}
@Test
@@ -306,7 +310,7 @@ public class MainActivityRealtimeTest {
}
@Test
public void refreshAllData_fallsBackToFlatConversationsFeedWhenHomeFeedFails() throws Exception {
public void refreshAllData_groupsFlatFallbackFeedWhenHomeFeedFails() throws Exception {
MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().resume().get();
Shadows.shadowOf(activity.getMainLooper()).idle();
@@ -322,16 +326,18 @@ public class MainActivityRealtimeTest {
"refreshAllData",
ReflectionHelpers.ClassParameter.from(JSONObject.class, new JSONObject())
);
waitFor(() -> apiClient.homeCalls > 0 && apiClient.conversationsCalls > 0);
waitFor(() -> apiClient.homeCalls > 0 && apiClient.conversationsCalls > 0 && hasConversationData(activity));
assertEquals(1, apiClient.homeCalls);
assertEquals(1, apiClient.conversationsCalls);
JSONArray conversationsData = ReflectionHelpers.getField(activity, "conversationsData");
assertEquals("flat-thread", conversationsData.optJSONObject(0).optString("projectId", ""));
assertEquals("folder_archive", conversationsData.optJSONObject(0).optString("conversationType", ""));
assertEquals("mac-studio:boss", conversationsData.optJSONObject(0).optString("projectId", ""));
assertEquals(2, conversationsData.optJSONObject(0).optInt("threadCount", 0));
}
@Test
public void refreshAllData_fallsBackToFlatConversationsFeedWhenHomeFeedThrowsIOException() throws Exception {
public void refreshAllData_groupsFlatFallbackFeedWhenHomeFeedThrowsIOException() throws Exception {
MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().resume().get();
Shadows.shadowOf(activity.getMainLooper()).idle();
@@ -347,12 +353,14 @@ public class MainActivityRealtimeTest {
"refreshAllData",
ReflectionHelpers.ClassParameter.from(JSONObject.class, new JSONObject())
);
waitFor(() -> apiClient.homeCalls > 0 && apiClient.conversationsCalls > 0);
waitFor(() -> apiClient.homeCalls > 0 && apiClient.conversationsCalls > 0 && hasConversationData(activity));
assertEquals(1, apiClient.homeCalls);
assertEquals(1, apiClient.conversationsCalls);
JSONArray conversationsData = ReflectionHelpers.getField(activity, "conversationsData");
assertEquals("flat-thread", conversationsData.optJSONObject(0).optString("projectId", ""));
assertEquals("folder_archive", conversationsData.optJSONObject(0).optString("conversationType", ""));
assertEquals("mac-studio:boss", conversationsData.optJSONObject(0).optString("projectId", ""));
assertEquals(2, conversationsData.optJSONObject(0).optInt("threadCount", 0));
}
private static void waitFor(BooleanSupplier condition) throws Exception {
@@ -367,6 +375,11 @@ public class MainActivityRealtimeTest {
throw new AssertionError("condition not met before timeout");
}
private static boolean hasConversationData(MainActivity activity) {
JSONArray conversationsData = ReflectionHelpers.getField(activity, "conversationsData");
return conversationsData != null && conversationsData.length() > 0;
}
public static class TestMainActivity extends MainActivity {
int conversationRefreshCount;
int deviceRefreshCount;
@@ -455,14 +468,29 @@ public class MainActivityRealtimeTest {
}
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"));
return new JSONArray()
.put(new JSONObject()
.put("projectId", "thread-revert")
.put("conversationType", "single_device")
.put("projectTitle", "发布回滚")
.put("threadTitle", "发布回滚")
.put("folderLabel", "Boss")
.put("folderKey", "mac-studio:boss")
.put("lastMessagePreview", "最近:发布回滚")
.put("latestReplyAt", "2026-04-06T10:00:00.000Z")
.put("latestReplyLabel", "11:00")
.put("contextBudgetIndicator", new JSONObject().put("visible", true).put("style", "ring_percent").put("percent", 80).put("level", "watch")))
.put(new JSONObject()
.put("projectId", "thread-ui")
.put("conversationType", "single_device")
.put("projectTitle", "Android UI 收尾")
.put("threadTitle", "Android UI 收尾")
.put("folderLabel", "Boss")
.put("folderKey", "mac-studio:boss")
.put("lastMessagePreview", "最近Android UI 收尾")
.put("latestReplyAt", "2026-04-06T09:59:00.000Z")
.put("latestReplyLabel", "10:59")
.put("contextBudgetIndicator", new JSONObject().put("visible", true).put("style", "ring_percent").put("percent", 95).put("level", "safe")));
}
}
@@ -543,14 +571,29 @@ public class MainActivityRealtimeTest {
}
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"));
return new JSONArray()
.put(new JSONObject()
.put("projectId", "thread-revert")
.put("conversationType", "single_device")
.put("projectTitle", "发布回滚")
.put("threadTitle", "发布回滚")
.put("folderLabel", "Boss")
.put("folderKey", "mac-studio:boss")
.put("lastMessagePreview", "最近:发布回滚")
.put("latestReplyAt", "2026-04-06T10:00:00.000Z")
.put("latestReplyLabel", "11:00")
.put("contextBudgetIndicator", new JSONObject().put("visible", true).put("style", "ring_percent").put("percent", 80).put("level", "watch")))
.put(new JSONObject()
.put("projectId", "thread-ui")
.put("conversationType", "single_device")
.put("projectTitle", "Android UI 收尾")
.put("threadTitle", "Android UI 收尾")
.put("folderLabel", "Boss")
.put("folderKey", "mac-studio:boss")
.put("lastMessagePreview", "最近Android UI 收尾")
.put("latestReplyAt", "2026-04-06T09:59:00.000Z")
.put("latestReplyLabel", "10:59")
.put("contextBudgetIndicator", new JSONObject().put("visible", true).put("style", "ring_percent").put("percent", 95).put("level", "safe")));
}
}
@@ -616,14 +659,29 @@ public class MainActivityRealtimeTest {
}
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"));
return new JSONArray()
.put(new JSONObject()
.put("projectId", "thread-revert")
.put("conversationType", "single_device")
.put("projectTitle", "发布回滚")
.put("threadTitle", "发布回滚")
.put("folderLabel", "Boss")
.put("folderKey", "mac-studio:boss")
.put("lastMessagePreview", "最近:发布回滚")
.put("latestReplyAt", "2026-04-06T10:00:00.000Z")
.put("latestReplyLabel", "11:00")
.put("contextBudgetIndicator", new JSONObject().put("visible", true).put("style", "ring_percent").put("percent", 80).put("level", "watch")))
.put(new JSONObject()
.put("projectId", "thread-ui")
.put("conversationType", "single_device")
.put("projectTitle", "Android UI 收尾")
.put("threadTitle", "Android UI 收尾")
.put("folderLabel", "Boss")
.put("folderKey", "mac-studio:boss")
.put("lastMessagePreview", "最近Android UI 收尾")
.put("latestReplyAt", "2026-04-06T09:59:00.000Z")
.put("latestReplyLabel", "10:59")
.put("contextBudgetIndicator", new JSONObject().put("visible", true).put("style", "ring_percent").put("percent", 95).put("level", "safe")));
}
}
}