style: unify native overflow menus

This commit is contained in:
kris
2026-04-03 04:48:41 +08:00
parent 24241d1f64
commit 42cf489450
6 changed files with 204 additions and 2 deletions

View File

@@ -21,6 +21,8 @@ public class ConversationFolderActivity extends BossScreenActivity {
folderKey = getIntent().getStringExtra(EXTRA_FOLDER_KEY);
folderName = getIntent().getStringExtra(EXTRA_FOLDER_NAME);
configureScreen(folderName == null || folderName.isEmpty() ? "项目线程" : folderName, "同一项目下的线程列表");
refreshButton.setVisibility(android.view.View.GONE);
setHeaderAction("...", v -> showMoreMenu());
reload();
}
@@ -99,4 +101,10 @@ public class ConversationFolderActivity extends BossScreenActivity {
intent.putExtra(ProjectDetailActivity.EXTRA_PROJECT_NAME, projectName);
startActivity(intent);
}
private void showMoreMenu() {
new androidx.appcompat.app.AlertDialog.Builder(this)
.setItems(new CharSequence[]{"刷新"}, (dialog, which) -> reload())
.show();
}
}

View File

@@ -31,7 +31,8 @@ public class ConversationInfoActivity extends BossScreenActivity {
projectId = getIntent().getStringExtra(EXTRA_PROJECT_ID);
projectName = getIntent().getStringExtra(EXTRA_PROJECT_NAME);
configureScreen("会话信息", projectName == null ? "单线程会话" : projectName);
setHeaderAction("改名", v -> openRenameDialog());
refreshButton.setVisibility(android.view.View.GONE);
setHeaderAction("...", v -> showMoreMenu());
reload();
}
@@ -185,6 +186,18 @@ public class ConversationInfoActivity extends BossScreenActivity {
.show();
}
private void showMoreMenu() {
new AlertDialog.Builder(this)
.setItems(new CharSequence[]{"改名", "刷新"}, (dialog, which) -> {
if (which == 0) {
openRenameDialog();
return;
}
reload();
})
.show();
}
private void saveConversationName(String name) {
if (name.isEmpty()) {
showMessage("线程名不能为空");

View File

@@ -30,7 +30,8 @@ public class GroupInfoActivity extends BossScreenActivity {
projectId = getIntent().getStringExtra(EXTRA_PROJECT_ID);
projectName = getIntent().getStringExtra(EXTRA_PROJECT_NAME);
configureScreen("群资料", projectName == null ? "协作群聊" : projectName);
setHeaderAction("改名", v -> openRenameDialog());
refreshButton.setVisibility(android.view.View.GONE);
setHeaderAction("...", v -> showMoreMenu());
reload();
}
@@ -425,6 +426,18 @@ public class GroupInfoActivity extends BossScreenActivity {
});
}
private void showMoreMenu() {
new AlertDialog.Builder(this)
.setItems(new CharSequence[]{"改名", "刷新"}, (dialog, which) -> {
if (which == 0) {
openRenameDialog();
return;
}
reload();
})
.show();
}
private String resolveBackendLabel(JSONObject backendPayload, String backendId) {
JSONArray availableChoices = backendPayload.optJSONArray("availableChoices");
if (availableChoices != null) {

View File

@@ -0,0 +1,108 @@
package com.hyzq.boss;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Intent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowDialog;
import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 34)
public class ConversationFolderActivityTest {
@Test
public void conversationFolderUsesOverflowMenuInTopBar() throws Exception {
Intent intent = new Intent()
.putExtra(ConversationFolderActivity.EXTRA_FOLDER_KEY, "talking")
.putExtra(ConversationFolderActivity.EXTRA_FOLDER_NAME, "Talking");
TestConversationFolderActivity activity = Robolectric
.buildActivity(TestConversationFolderActivity.class, intent)
.setup()
.get();
ReflectionHelpers.callInstanceMethod(
activity,
"renderFolder",
ReflectionHelpers.ClassParameter.from(JSONObject.class, buildFolderPayload())
);
Button headerAction = activity.findViewById(R.id.screen_header_action);
Button refreshButton = activity.findViewById(R.id.screen_refresh_button);
LinearLayout content = activity.findViewById(R.id.screen_content);
assertEquals("...", headerAction.getText().toString());
assertEquals(View.GONE, refreshButton.getVisibility());
assertTrue(viewTreeContainsText(content, "Talking"));
assertTrue(viewTreeContainsText(content, "查询腾讯HAI GPU服务器"));
ReflectionHelpers.callInstanceMethod(activity, "showMoreMenu");
android.app.Dialog latestDialog = ShadowDialog.getLatestDialog();
assertTrue(latestDialog instanceof AlertDialog);
ListView listView = ((AlertDialog) latestDialog).getListView();
assertTrue(viewTreeContainsText(listView.getAdapter().getView(0, null, listView), "刷新"));
}
private static JSONObject buildFolderPayload() throws Exception {
JSONArray threads = new JSONArray()
.put(new JSONObject()
.put("projectId", "project-1")
.put("threadTitle", "查询腾讯HAI GPU服务器")
.put("folderLabel", "Talking")
.put("lastMessagePreview", "已从设备导入线程")
.put("timeLabel", "02:28"))
.put(new JSONObject()
.put("projectId", "project-2")
.put("threadTitle", "状态栏显示CPU和内存")
.put("folderLabel", "Talking")
.put("lastMessagePreview", "已从设备导入线程")
.put("timeLabel", "02:12"));
return new JSONObject()
.put("folderLabel", "Talking")
.put("deviceName", "Mac Studio")
.put("threadCount", 2)
.put("threads", threads);
}
private static boolean viewTreeContainsText(View root, String expectedText) {
if (root instanceof TextView) {
CharSequence text = ((TextView) root).getText();
if (expectedText.contentEquals(text)) {
return true;
}
}
if (!(root instanceof ViewGroup)) {
return false;
}
ViewGroup group = (ViewGroup) root;
for (int index = 0; index < group.getChildCount(); index += 1) {
if (viewTreeContainsText(group.getChildAt(index), expectedText)) {
return true;
}
}
return false;
}
public static class TestConversationFolderActivity extends ConversationFolderActivity {
@Override
protected void reload() {
// Tests render the folder state directly.
}
}
}

View File

@@ -8,9 +8,13 @@ import static org.junit.Assert.assertTrue;
import android.content.Intent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
@@ -19,6 +23,7 @@ import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowDialog;
import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
@@ -95,6 +100,31 @@ public class ConversationInfoActivityTest {
);
}
@Test
public void conversationInfoUsesOverflowMenuInTopBar() {
Intent intent = new Intent()
.putExtra(ConversationInfoActivity.EXTRA_PROJECT_ID, "project-1")
.putExtra(ConversationInfoActivity.EXTRA_PROJECT_NAME, "北区试产线回归");
TestConversationInfoActivity activity = Robolectric
.buildActivity(TestConversationInfoActivity.class, intent)
.setup()
.get();
Button headerAction = activity.findViewById(R.id.screen_header_action);
Button refreshButton = activity.findViewById(R.id.screen_refresh_button);
assertEquals("...", headerAction.getText().toString());
assertEquals(View.GONE, refreshButton.getVisibility());
ReflectionHelpers.callInstanceMethod(activity, "showMoreMenu");
android.app.Dialog latestDialog = ShadowDialog.getLatestDialog();
assertTrue(latestDialog instanceof AlertDialog);
ListView listView = ((AlertDialog) latestDialog).getListView();
assertTrue(viewTreeContainsText(listView.getAdapter().getView(0, null, listView), "改名"));
assertTrue(viewTreeContainsText(listView.getAdapter().getView(1, null, listView), "刷新"));
}
private static JSONObject buildDetailPayload() throws Exception {
JSONObject threadMeta = new JSONObject()
.put("threadId", "thread-7")

View File

@@ -9,9 +9,13 @@ import android.content.Intent;
import android.os.Looper;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
@@ -20,6 +24,7 @@ import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowDialog;
import org.robolectric.util.ReflectionHelpers;
import java.io.ByteArrayInputStream;
@@ -179,6 +184,31 @@ public class GroupInfoActivityTest {
assertTrue(viewTreeContainsText(content, "OMX Team Runtime 当前不可用,当前已自动回退到 Boss Native Orchestrator。"));
}
@Test
public void groupInfoUsesOverflowMenuInTopBar() {
Intent intent = new Intent()
.putExtra(GroupInfoActivity.EXTRA_PROJECT_ID, "group-1")
.putExtra(GroupInfoActivity.EXTRA_PROJECT_NAME, "巡检协作群");
TestGroupInfoActivity activity = Robolectric
.buildActivity(TestGroupInfoActivity.class, intent)
.setup()
.get();
Button headerAction = activity.findViewById(R.id.screen_header_action);
Button refreshButton = activity.findViewById(R.id.screen_refresh_button);
assertEquals("...", headerAction.getText().toString());
assertEquals(View.GONE, refreshButton.getVisibility());
ReflectionHelpers.callInstanceMethod(activity, "showMoreMenu");
android.app.Dialog latestDialog = ShadowDialog.getLatestDialog();
assertTrue(latestDialog instanceof AlertDialog);
ListView listView = ((AlertDialog) latestDialog).getListView();
assertTrue(viewTreeContainsText(listView.getAdapter().getView(0, null, listView), "改名"));
assertTrue(viewTreeContainsText(listView.getAdapter().getView(1, null, listView), "刷新"));
}
@Test
public void saveOrchestrationBackendUsesScopedEndpoint() throws Exception {
Intent intent = new Intent()