chore: polish native wechat ui release v2.5.1

This commit is contained in:
kris
2026-03-29 20:00:00 +08:00
parent fe186ad8d5
commit 062b46bd41
17 changed files with 314 additions and 67 deletions

View File

@@ -4,6 +4,7 @@ import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
import java.util.List;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -12,6 +13,41 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class GroupCreateActivityTest {
@Test
public void buildHeaderCardSpecs_collapsesSourceFlowIntoSingleCompactCard() {
JSONObject threadMeta = new StubJSONObject()
.withString("threadDisplayName", "北区试产线回归")
.withString("threadId", "thread-7")
.withString("folderName", "Mac Studio");
JSONArray participants = new StubJSONArray(
new StubJSONObject(),
new StubJSONObject(),
new StubJSONObject()
);
List<GroupCreateActivity.SummaryCardSpec> cards = GroupCreateActivity.buildHeaderCardSpecs(
true,
"source-1",
"北区试产线回归",
threadMeta,
participants
);
assertEquals(1, cards.size());
assertEquals("北区试产线回归", cards.get(0).title);
assertEquals("来源线程 thread-7 · Mac Studio · 3 个参与线程", cards.get(0).body);
assertEquals("新群会单独创建,原会话保留", cards.get(0).meta);
}
@Test
public void buildSelectionCardSpec_usesCompactWechatStyleHint() {
GroupCreateActivity.SummaryCardSpec card = GroupCreateActivity.buildSelectionCardSpec(5, 0, true);
assertEquals("选择其他线程", card.title);
assertEquals("至少选择 1 个其他线程", card.body);
assertEquals("候选 5 个 · 已选 0 个", card.meta);
}
@Test
public void collectSelectableConversationItems_filtersOutExistingGroupChats() {
JSONObject threadConversation = new StubJSONObject()

View File

@@ -0,0 +1,142 @@
package com.hyzq.boss;
import static org.junit.Assert.assertTrue;
import android.content.Intent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
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.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 34)
public class GroupCreateActivityUiTest {
@Test
public void renderCreatePageUsesCompactSummaryCardsForSourceFlow() throws Exception {
Intent intent = new Intent()
.putExtra(GroupCreateActivity.EXTRA_SOURCE_PROJECT_ID, "source-1")
.putExtra(GroupCreateActivity.EXTRA_SOURCE_PROJECT_NAME, "北区试产线回归");
TestGroupCreateActivity activity = Robolectric
.buildActivity(TestGroupCreateActivity.class, intent)
.setup()
.get();
ReflectionHelpers.callInstanceMethod(
activity,
"renderCreatePage",
ReflectionHelpers.ClassParameter.from(JSONObject.class, buildParticipantsPayload()),
ReflectionHelpers.ClassParameter.from(JSONObject.class, buildConversationsPayload()),
ReflectionHelpers.ClassParameter.from(boolean.class, true)
);
LinearLayout content = activity.findViewById(R.id.screen_content);
assertTrue(viewTreeContainsText(content.getChildAt(0), "北区试产线回归"));
assertTrue(viewTreeContainsText(content.getChildAt(0), "来源线程 thread-7 · Mac Studio · 3 个参与线程"));
assertTrue(viewTreeContainsText(content.getChildAt(0), "新群会单独创建,原会话保留"));
assertTrue(viewTreeContainsText(content.getChildAt(1), "选择其他线程"));
assertTrue(viewTreeContainsText(content.getChildAt(1), "继续点选可调整成员"));
assertTrue(viewTreeContainsText(content.getChildAt(1), "候选 2 个 · 已选 2 个"));
}
@Test
public void toggleSelectionRefreshesRenderedSelectionSummary() throws Exception {
Intent intent = new Intent()
.putExtra(GroupCreateActivity.EXTRA_SOURCE_PROJECT_ID, "source-1")
.putExtra(GroupCreateActivity.EXTRA_SOURCE_PROJECT_NAME, "北区试产线回归");
TestGroupCreateActivity activity = Robolectric
.buildActivity(TestGroupCreateActivity.class, intent)
.setup()
.get();
ReflectionHelpers.callInstanceMethod(
activity,
"renderCreatePage",
ReflectionHelpers.ClassParameter.from(JSONObject.class, buildParticipantsPayload()),
ReflectionHelpers.ClassParameter.from(JSONObject.class, buildConversationsPayload()),
ReflectionHelpers.ClassParameter.from(boolean.class, true)
);
ReflectionHelpers.callInstanceMethod(
activity,
"toggleSelection",
ReflectionHelpers.ClassParameter.from(String.class, "thread-2")
);
ReflectionHelpers.callInstanceMethod(
activity,
"toggleSelection",
ReflectionHelpers.ClassParameter.from(String.class, "thread-3")
);
LinearLayout content = activity.findViewById(R.id.screen_content);
assertTrue(viewTreeContainsText(content.getChildAt(1), "至少选择 1 个其他线程"));
assertTrue(viewTreeContainsText(content.getChildAt(1), "候选 2 个 · 已选 0 个"));
}
private static JSONObject buildParticipantsPayload() throws Exception {
JSONObject threadMeta = new JSONObject()
.put("threadDisplayName", "北区试产线回归")
.put("threadId", "thread-7")
.put("folderName", "Mac Studio");
JSONArray participants = new JSONArray()
.put(new JSONObject().put("projectId", "source-1"))
.put(new JSONObject().put("projectId", "thread-2"))
.put(new JSONObject().put("projectId", "thread-3"));
return new JSONObject()
.put("threadMeta", threadMeta)
.put("participants", participants);
}
private static JSONObject buildConversationsPayload() throws Exception {
JSONArray conversations = new JSONArray()
.put(new JSONObject()
.put("projectId", "thread-2")
.put("projectTitle", "硬件审计协作")
.put("folderLabel", "Mac Studio")
.put("lastMessagePreview", "检查摄像头供电链路")
.put("latestReplyLabel", "09:28")
.put("isGroup", false))
.put(new JSONObject()
.put("projectId", "thread-3")
.put("projectTitle", "Boss 移动控制台")
.put("folderLabel", "Boss")
.put("lastMessagePreview", "统一顶部按钮样式")
.put("latestReplyLabel", "09:31")
.put("isGroup", false));
return new JSONObject().put("conversations", conversations);
}
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 TestGroupCreateActivity extends GroupCreateActivity {
@Override
protected void reload() {
// Tests drive renderCreatePage manually to avoid network work.
}
}
}

View File

@@ -111,7 +111,7 @@ public class ProjectChatUiStateTest {
assertFalse(chromeState.multiSelecting);
assertTrue(chromeState.showComposer);
assertFalse(chromeState.showMultiSelectBar);
assertTrue(chromeState.showRefresh);
assertFalse(chromeState.showRefresh);
assertTrue(chromeState.showHeaderAction);
assertFalse(chromeState.forwardEnabled);
assertEquals("返回", chromeState.backLabel);
@@ -119,6 +119,22 @@ public class ProjectChatUiStateTest {
assertEquals("归档确认", chromeState.subtitle);
}
@Test
public void chromeStateRestoresRefreshBeforeConversationInfoIsReady() {
ProjectChatUiState.ChromeState chromeState =
ProjectChatUiState.resolveChromeState(ProjectChatUiState.emptySelection(), false, "北区试产线回归", "归档确认");
assertFalse(chromeState.multiSelecting);
assertTrue(chromeState.showComposer);
assertFalse(chromeState.showMultiSelectBar);
assertTrue(chromeState.showRefresh);
assertFalse(chromeState.showHeaderAction);
assertFalse(chromeState.forwardEnabled);
assertEquals("返回", chromeState.backLabel);
assertEquals("北区试产线回归", chromeState.title);
assertEquals("归档确认", chromeState.subtitle);
}
@Test
public void reconcileSelectionDropsMessagesMissingFromRenderSet() {
ProjectChatUiState.SelectionState state = ProjectChatUiState.toggleSelection(null, "m1");

View File

@@ -46,7 +46,7 @@ public class ProjectDetailActivityChromeBindingsTest {
assertFalse(bindings.multiSelecting);
assertTrue(bindings.showComposer);
assertFalse(bindings.showMultiSelectBar);
assertTrue(bindings.showRefresh);
assertFalse(bindings.showRefresh);
assertTrue(bindings.showHeaderAction);
assertFalse(bindings.enableForwardButton);
assertTrue(bindings.enablePullRefresh);

View File

@@ -75,7 +75,7 @@ public class ProjectDetailActivityUiTest {
assertEquals(View.VISIBLE, composerRow.getVisibility());
assertEquals(View.GONE, multiSelectActions.getVisibility());
assertEquals("返回", backButton.getText().toString());
assertEquals(View.VISIBLE, refreshButton.getVisibility());
assertEquals(View.GONE, refreshButton.getVisibility());
}
@Test