diff --git a/android/app/src/main/java/com/hyzq/boss/MainActivity.java b/android/app/src/main/java/com/hyzq/boss/MainActivity.java index 8a0fdc5..24e289d 100644 --- a/android/app/src/main/java/com/hyzq/boss/MainActivity.java +++ b/android/app/src/main/java/com/hyzq/boss/MainActivity.java @@ -388,14 +388,14 @@ public class MainActivity extends AppCompatActivity { BossApiClient.ApiResponse conversations = null; boolean conversationsOk = false; try { - conversations = apiClient.getConversations(); + conversations = apiClient.getConversationHome(); conversationsOk = conversations.ok(); } catch (Exception ignored) { conversationsOk = false; } if (!conversationsOk) { try { - BossApiClient.ApiResponse fallbackConversations = apiClient.getConversationHome(); + BossApiClient.ApiResponse fallbackConversations = apiClient.getConversations(); if (fallbackConversations.ok()) { conversations = fallbackConversations; conversationsOk = true; @@ -653,14 +653,14 @@ public class MainActivity extends AppCompatActivity { boolean settingsOk = false; try { - conversations = apiClient.getConversations(); + conversations = apiClient.getConversationHome(); conversationsOk = conversations.ok(); } catch (Exception ignored) { conversationsOk = false; } if (!conversationsOk) { try { - BossApiClient.ApiResponse fallbackConversations = apiClient.getConversationHome(); + BossApiClient.ApiResponse fallbackConversations = apiClient.getConversations(); if (fallbackConversations.ok()) { conversations = fallbackConversations; conversationsOk = true; diff --git a/android/app/src/test/java/com/hyzq/boss/MainActivityRealtimeTest.java b/android/app/src/test/java/com/hyzq/boss/MainActivityRealtimeTest.java index fcc5509..184ef6e 100644 --- a/android/app/src/test/java/com/hyzq/boss/MainActivityRealtimeTest.java +++ b/android/app/src/test/java/com/hyzq/boss/MainActivityRealtimeTest.java @@ -2,8 +2,10 @@ package com.hyzq.boss; import static org.junit.Assert.assertEquals; +import android.content.Context; import android.os.Looper; import org.json.JSONObject; +import org.json.JSONArray; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; @@ -218,6 +220,48 @@ public class MainActivityRealtimeTest { assertEquals(0, activity.meRefreshCount); } + @Test + public void refreshConversationsData_prefersConversationHomeFeedOverFlatConversationsFeed() throws Exception { + MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().resume().get(); + Shadows.shadowOf(activity.getMainLooper()).idle(); + + RecordingConversationSourceClient apiClient = new RecordingConversationSourceClient( + 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(0, apiClient.conversationsCalls); + } + + @Test + public void refreshAllData_prefersConversationHomeFeedOverFlatConversationsFeed() throws Exception { + MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().resume().get(); + Shadows.shadowOf(activity.getMainLooper()).idle(); + + RecordingConversationSourceClient apiClient = new RecordingConversationSourceClient( + 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(0, apiClient.conversationsCalls); + } + private static void waitFor(BooleanSupplier condition) throws Exception { long deadlineAt = System.currentTimeMillis() + 2_000L; while (System.currentTimeMillis() < deadlineAt) { @@ -253,4 +297,92 @@ public class MainActivityRealtimeTest { completeRealtimeTabRefresh(); } } + + private static final class RecordingConversationSourceClient extends BossApiClient { + int homeCalls; + int conversationsCalls; + int sessionCalls; + int devicesCalls; + int settingsCalls; + int otaCalls; + + RecordingConversationSourceClient(android.content.SharedPreferences prefs) { + super(prefs, "https://boss.hyzq.net"); + } + + @Override + public ApiResponse getConversationHome() throws java.io.IOException, org.json.JSONException { + homeCalls += 1; + return new ApiResponse(200, new JSONObject() + .put("ok", true) + .put("conversations", buildHomeConversations())); + } + + @Override + public ApiResponse getConversations() throws java.io.IOException, org.json.JSONException { + conversationsCalls += 1; + return new ApiResponse(200, new JSONObject() + .put("ok", true) + .put("conversations", buildFlatConversations())); + } + + @Override + public ApiResponse getSession() throws java.io.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 java.io.IOException, org.json.JSONException { + devicesCalls += 1; + return new ApiResponse(200, new JSONObject() + .put("ok", true) + .put("devices", new JSONArray())); + } + + @Override + public ApiResponse getSettings() throws java.io.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 java.io.IOException, org.json.JSONException { + otaCalls += 1; + return new ApiResponse(200, new JSONObject() + .put("ok", true) + .put("hasOta", false)); + } + + private static JSONArray buildHomeConversations() throws org.json.JSONException { + return new JSONArray().put(new JSONObject() + .put("projectId", "folder-boss") + .put("conversationType", "folder_archive") + .put("folderKey", "mac-studio:boss") + .put("projectTitle", "Boss") + .put("threadTitle", "Boss") + .put("folderLabel", "2 个线程 · 最近:发布回滚") + .put("searchAliases", new JSONArray().put("发布回滚").put("Android UI 收尾")) + .put("lastMessagePreview", "最近:发布回滚") + .put("latestReplyLabel", "11:00")); + } + + 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")); + } + } }