feat: align android conversation folders with drawer design

This commit is contained in:
kris
2026-04-05 13:49:16 +08:00
parent c8156d5f40
commit 7206be05b6
4 changed files with 171 additions and 12 deletions

View File

@@ -5,10 +5,14 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import android.content.Intent;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import androidx.recyclerview.widget.RecyclerView;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
@@ -94,6 +98,43 @@ public class MainActivityConversationSearchTest {
assertFalse(activity.findViewById(R.id.search_button).isShown());
}
@Test
public void searchHitInsideArchivedProject_keepsProjectContextAndOpensFolderPage() throws Exception {
MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().get();
ReflectionHelpers.setField(activity, "conversationsData", new JSONArray()
.put(new JSONObject()
.put("projectId", "boss-thread-1")
.put("conversationType", "single_device")
.put("folderKey", "mac-studio:boss")
.put("folderLabel", "Boss")
.put("projectTitle", "Boss")
.put("threadTitle", "发布回滚")
.put("lastMessagePreview", "最近:发布回滚")
.put("latestReplyLabel", "11:00")
.put("threadCount", 2)));
ReflectionHelpers.callInstanceMethod(activity, "showContent");
Shadows.shadowOf(activity.getMainLooper()).idle();
ReflectionHelpers.callInstanceMethod(activity, "enterConversationSearchMode");
Shadows.shadowOf(activity.getMainLooper()).idle();
EditText searchInput = activity.findViewById(R.id.top_search_input);
searchInput.setText("发布回滚");
Shadows.shadowOf(activity.getMainLooper()).idle();
RecyclerView list = ReflectionHelpers.getField(activity, "screenList");
View row = getRecyclerChild(list, 0);
assertTrue(viewTreeContainsText(row, "Boss / 发布回滚"));
row.performClick();
Shadows.shadowOf(activity.getMainLooper()).idle();
Intent nextIntent = Shadows.shadowOf(activity).getNextStartedActivity();
assertEquals(ConversationFolderActivity.class.getName(), nextIntent.getComponent().getClassName());
assertEquals("mac-studio:boss", nextIntent.getStringExtra(ConversationFolderActivity.EXTRA_FOLDER_KEY));
assertEquals("Boss", nextIntent.getStringExtra(ConversationFolderActivity.EXTRA_FOLDER_NAME));
}
private static JSONArray buildConversations() throws Exception {
return new JSONArray()
.put(new JSONObject()
@@ -105,4 +146,31 @@ public class MainActivityConversationSearchTest {
.put("latestReplyLabel", "09:40")
.put("conversationType", "single_device"));
}
private static View getRecyclerChild(RecyclerView recyclerView, int position) {
RecyclerView.Adapter adapter = recyclerView.getAdapter();
int viewType = adapter.getItemViewType(position);
RecyclerView.ViewHolder holder = adapter.createViewHolder(recyclerView, viewType);
adapter.bindViewHolder(holder, position);
return ((android.widget.FrameLayout) holder.itemView).getChildAt(0);
}
private static boolean viewTreeContainsText(View root, String expectedText) {
if (root instanceof android.widget.TextView) {
CharSequence text = ((android.widget.TextView) root).getText();
if (expectedText.contentEquals(text)) {
return true;
}
}
if (!(root instanceof LinearLayout)) {
return false;
}
LinearLayout group = (LinearLayout) root;
for (int index = 0; index < group.getChildCount(); index += 1) {
if (viewTreeContainsText(group.getChildAt(index), expectedText)) {
return true;
}
}
return false;
}
}

View File

@@ -54,7 +54,7 @@ public class MainActivityPinnedConversationsTest {
assertTrue(recyclerContainsText(list, "主 Agent"));
assertTrue(recyclerContainsText(list, "Boss 移动控制台"));
View pinnedHeader = getRecyclerChild(list, 1);
View pinnedHeader = getRecyclerChild(list, 0);
pinnedHeader.performClick();
assertEquals(true, ReflectionHelpers.getField(activity, "pinnedConversationsCollapsed"));
@@ -62,6 +62,32 @@ public class MainActivityPinnedConversationsTest {
assertTrue("收起后普通会话仍应保留", recyclerContainsText(list, "Boss 移动控制台"));
}
@Test
public void folderArchiveRow_usesProjectTitleAndCompactSubtitleOnHomepage() throws Exception {
MainActivity activity = Robolectric.buildActivity(MainActivity.class).setup().get();
ReflectionHelpers.setField(activity, "conversationsData", new JSONArray()
.put(new JSONObject()
.put("projectId", "folder-boss")
.put("conversationType", "folder_archive")
.put("folderKey", "mac-studio:boss")
.put("projectTitle", "Boss")
.put("threadTitle", "发布回滚")
.put("folderLabel", "2 个线程 · 最近:发布回滚")
.put("lastMessagePreview", "最近:发布回滚")
.put("latestReplyLabel", "11:00")));
ReflectionHelpers.callInstanceMethod(activity, "showContent");
Shadows.shadowOf(activity.getMainLooper()).idle();
ReflectionHelpers.callInstanceMethod(activity, "renderConversationsRoot");
Shadows.shadowOf(activity.getMainLooper()).idle();
RecyclerView list = ReflectionHelpers.getField(activity, "screenList");
View row = getRecyclerChild(list, 0);
assertTrue(viewTreeContainsText(row, "Boss"));
assertTrue(viewTreeContainsText(row, "2 个线程 · 最近:发布回滚"));
}
private static View getRecyclerChild(RecyclerView recyclerView, int position) {
RecyclerView.Adapter adapter = recyclerView.getAdapter();
int viewType = adapter.getItemViewType(position);