feat: improve evolution screen feedback states

This commit is contained in:
kris
2026-04-16 06:06:03 +08:00
parent 4bedf75dc2
commit e8304faebc
2 changed files with 135 additions and 9 deletions

View File

@@ -17,6 +17,8 @@ public class MasterAgentEvolutionActivity extends BossScreenActivity {
private long lastRealtimeReloadAt;
private boolean contentLoaded;
private @Nullable String currentMode;
private @Nullable String statusMessage;
private boolean statusIsError;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -57,12 +59,16 @@ public class MasterAgentEvolutionActivity extends BossScreenActivity {
if (!response.ok()) {
throw new IllegalStateException(response.message());
}
runOnUiThread(() -> renderDashboard(response.json));
runOnUiThread(() -> {
clearStatusMessage();
renderDashboard(response.json);
});
} catch (Exception error) {
runOnUiThread(() -> {
setRefreshing(false);
contentLoaded = false;
replaceContent(BossUi.buildEmptyCard(this, "自动进化加载失败:" + error.getMessage()));
showStatusMessage("自动进化加载失败:" + error.getMessage(), true);
renderLoadErrorState(error.getMessage());
});
}
});
@@ -119,6 +125,7 @@ public class MasterAgentEvolutionActivity extends BossScreenActivity {
"autonomous".equals(currentMode) ? "完全自我进化" : "受控自动进化",
autoApplyLowRiskRules ? "低风险提案会自动采纳。" : "所有提案都需要人工确认。"
));
maybeRenderStatusBanner();
Button controlledButton = BossUi.buildMiniActionButton(this, "切到受控模式", false);
controlledButton.setEnabled(!"controlled".equals(currentMode));
@@ -181,7 +188,7 @@ public class MasterAgentEvolutionActivity extends BossScreenActivity {
proposal.optString("summary", "暂无摘要"),
proposal.optString("proposalType", "-")
+ " · " + proposal.optString("riskLevel", "-")
+ " · " + proposal.optString("createdAt", "-"),
+ " · " + formatTime(proposal.optString("createdAt", "-")),
null,
null
));
@@ -208,7 +215,7 @@ public class MasterAgentEvolutionActivity extends BossScreenActivity {
this,
signal.optString("kind", "signal"),
signal.optString("requestText", ""),
signal.optString("createdAt", "-"),
formatTime(signal.optString("createdAt", "-")),
null,
null
));
@@ -227,7 +234,7 @@ public class MasterAgentEvolutionActivity extends BossScreenActivity {
this,
rule.optString("ruleType", "rule"),
rule.optString("sourceProposalId", "直接创建"),
rule.optString("createdAt", "-"),
formatTime(rule.optString("createdAt", "-")),
null,
null
));
@@ -261,14 +268,14 @@ public class MasterAgentEvolutionActivity extends BossScreenActivity {
throw new IllegalStateException(response.message());
}
runOnUiThread(() -> {
showMessage("已切到 " + ("autonomous".equals(mode) ? "完全自我进化" : "受控自动进化"));
showStatusMessage("已切到 " + ("autonomous".equals(mode) ? "完全自我进化" : "受控自动进化"), false);
setResult(RESULT_OK);
reload();
});
} catch (Exception error) {
runOnUiThread(() -> {
setRefreshing(false);
showMessage("切换失败:" + error.getMessage());
showStatusMessage("切换失败:" + error.getMessage(), true);
});
}
});
@@ -289,16 +296,73 @@ public class MasterAgentEvolutionActivity extends BossScreenActivity {
throw new IllegalStateException(response.message());
}
runOnUiThread(() -> {
showMessage(approve ? "提案已批准" : "提案已拒绝");
showStatusMessage(approve ? "提案已批准" : "提案已拒绝", false);
setResult(RESULT_OK);
reload();
});
} catch (Exception error) {
runOnUiThread(() -> {
setRefreshing(false);
showMessage((approve ? "批准失败:" : "拒绝失败:") + error.getMessage());
showStatusMessage((approve ? "批准失败:" : "拒绝失败:") + error.getMessage(), true);
});
}
});
}
private void maybeRenderStatusBanner() {
if (statusMessage == null || statusMessage.isEmpty()) {
return;
}
contentRoot.addView(BossUi.buildSoftPanel(
this,
statusIsError ? "最近状态" : "最近操作",
statusMessage,
statusIsError ? "你可以直接点顶部刷新重试,或继续切换模式/审批提案。" : "本页已经同步到最新自动进化状态。"
));
}
private void renderLoadErrorState(String message) {
replaceContent(contentRoot);
contentRoot.removeAllViews();
contentRoot.addView(BossUi.buildSimpleProfileHeader(
this,
"主 Agent 自动进化",
"信号、提案与生效规则",
"当前加载失败,保留在这个页面直接重试即可。"
));
maybeRenderStatusBanner();
Button retryButton = BossUi.buildMiniActionButton(this, "重新加载", true);
retryButton.setOnClickListener(v -> reload());
contentRoot.addView(BossUi.buildInlineActionRow(this, retryButton));
contentRoot.addView(BossUi.buildEmptyCard(this, "自动进化中心暂时不可用:" + message));
}
private void showStatusMessage(String message, boolean isError) {
statusMessage = message;
statusIsError = isError;
showMessage(message);
}
private void clearStatusMessage() {
if (!statusIsError) {
statusMessage = null;
}
statusIsError = false;
}
private String formatTime(String value) {
if (value == null || value.isEmpty() || "-".equals(value)) {
return "-";
}
String normalized = value.replace('T', ' ');
int plusIndex = normalized.indexOf('+');
if (plusIndex > 0) {
return normalized.substring(0, plusIndex);
}
int zIndex = normalized.indexOf('Z');
if (zIndex > 0) {
return normalized.substring(0, zIndex);
}
return normalized;
}
}

View File

@@ -91,6 +91,68 @@ public class MasterAgentEvolutionActivityTest {
assertEquals(1, activity.reloadCount);
}
@Test
public void renderDashboardShowsStatusBannerAndFormattedTimes() throws Exception {
TestMasterAgentEvolutionActivity activity = Robolectric
.buildActivity(TestMasterAgentEvolutionActivity.class, new Intent())
.setup()
.get();
ReflectionHelpers.setField(activity, "statusMessage", "提案已批准");
ReflectionHelpers.setField(activity, "statusIsError", false);
JSONObject payload = new JSONObject()
.put("config", new JSONObject()
.put("mode", "controlled")
.put("autoApplyLowRiskRules", false))
.put("signals", new JSONArray()
.put(new JSONObject()
.put("signalId", "signal-1")
.put("kind", "backend_fallback")
.put("requestText", "主节点暂时不可用")
.put("createdAt", "2026-04-16T12:00:00+08:00")))
.put("proposals", new JSONArray())
.put("rules", new JSONArray()
.put(new JSONObject()
.put("ruleId", "rule-1")
.put("ruleType", "fast_path_rule")
.put("createdAt", "2026-04-16T12:02:00+08:00")));
ReflectionHelpers.callInstanceMethod(
activity,
"renderDashboard",
ReflectionHelpers.ClassParameter.from(JSONObject.class, payload)
);
View content = activity.findViewById(R.id.screen_content);
assertTrue(viewTreeContainsText(content, "最近操作"));
assertTrue(viewTreeContainsText(content, "提案已批准"));
assertTrue(viewTreeContainsText(content, "2026-04-16 12:00:00"));
assertTrue(viewTreeContainsText(content, "2026-04-16 12:02:00"));
}
@Test
public void renderLoadErrorStateKeepsRetryEntryVisible() throws Exception {
TestMasterAgentEvolutionActivity activity = Robolectric
.buildActivity(TestMasterAgentEvolutionActivity.class, new Intent())
.setup()
.get();
ReflectionHelpers.setField(activity, "statusMessage", "自动进化加载失败network down");
ReflectionHelpers.setField(activity, "statusIsError", true);
ReflectionHelpers.callInstanceMethod(
activity,
"renderLoadErrorState",
ReflectionHelpers.ClassParameter.from(String.class, "network down")
);
View content = activity.findViewById(R.id.screen_content);
assertTrue(viewTreeContainsText(content, "当前加载失败,保留在这个页面直接重试即可。"));
assertTrue(viewTreeContainsText(content, "重新加载"));
assertTrue(viewTreeContainsText(content, "自动进化中心暂时不可用network down"));
assertTrue(viewTreeContainsText(content, "最近状态"));
}
private static boolean viewTreeContainsText(View root, String expectedText) {
if (root instanceof TextView) {
CharSequence text = ((TextView) root).getText();