From effdaabab313e19f14a629c16f4bcc5040c2e5a4 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Thu, 9 Jul 2026 13:55:14 +0000 Subject: [PATCH] [Feat] (android-plugin): table-style POST report with tap-to-expand details Checks render as a two-column table (name | colored status chip) with alternating row stripes; per-check detail text is hidden until the row is tapped, and the raw JSON report collapses behind a bottom toggle. Co-Authored-By: Claude Fable 5 --- .../top/mobilegl/plugin/PostActivity.java | 131 ++++++++++++++++-- 1 file changed, 120 insertions(+), 11 deletions(-) diff --git a/android-plugin/app/src/main/java/top/mobilegl/plugin/PostActivity.java b/android-plugin/app/src/main/java/top/mobilegl/plugin/PostActivity.java index ff1593df..881b668c 100644 --- a/android-plugin/app/src/main/java/top/mobilegl/plugin/PostActivity.java +++ b/android-plugin/app/src/main/java/top/mobilegl/plugin/PostActivity.java @@ -5,6 +5,8 @@ import android.graphics.Typeface; import android.os.Bundle; import android.util.Log; import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; @@ -25,6 +27,12 @@ public final class PostActivity extends Activity { private static final int COLOR_WARN = 0xFFFF9800; private static final int COLOR_FAIL = 0xFFF44336; private static final int COLOR_INFO = 0xFF9E9E9E; + private static final int COLOR_DETAIL = 0xFFBBBBBB; + private static final int COLOR_ROW_EVEN = 0xFF1A1A1A; + private static final int COLOR_ROW_ODD = 0xFF121212; + + private static final String INDICATOR_COLLAPSED = "▸"; + private static final String INDICATOR_EXPANDED = "▾"; /** * Single-flight state: the driver POST runs at most once per process. @@ -177,7 +185,7 @@ public final class PostActivity extends Activity { String nativeError = root.optString("error", ""); if (!nativeError.isEmpty()) { showError(nativeError); - addText(json, 10, COLOR_INFO, false, dp(8)); + addRawJsonSection(json); return; } JSONArray backends = extractBackends(root); @@ -192,6 +200,7 @@ public final class PostActivity extends Activity { renderBackendSection(backend); } } + addRawJsonSection(json); } private static JSONArray extractBackends(JSONObject root) { @@ -238,19 +247,113 @@ public final class PostActivity extends Activity { if (checks == null) { return; } + LinearLayout table = new LinearLayout(this); + table.setOrientation(LinearLayout.VERTICAL); + LinearLayout.LayoutParams tableParams = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ); + tableParams.topMargin = dp(6); + contentLayout.addView(table, tableParams); + int rowIndex = 0; for (int i = 0; i < checks.length(); ++i) { JSONObject check = checks.optJSONObject(i); if (check == null) { continue; } - String status = check.optString("status", "INFO"); - String checkName = check.optString("name", "unnamed check"); - String detail = check.optString("detail", check.optString("message", "")); - String row = "[" + status + "] " + checkName + (detail.isEmpty() ? "" : " - " + detail); - addText(row, 12, statusColor(status), false, dp(4)); + addCheckRow(table, check, rowIndex++); } } + /** + * Adds one two-column check row (name | status chip) to the table. Rows with + * a non-empty detail get a collapse indicator and toggle the detail text on tap; + * rows without detail show no indicator and are not tappable. + */ + private void addCheckRow(LinearLayout table, JSONObject check, int rowIndex) { + String status = check.optString("status", "INFO"); + String checkName = check.optString("name", "unnamed check"); + String detail = check.optString("detail", check.optString("message", "")); + boolean hasDetail = !detail.isEmpty(); + + LinearLayout row = new LinearLayout(this); + row.setOrientation(LinearLayout.VERTICAL); + row.setBackgroundColor(rowIndex % 2 == 0 ? COLOR_ROW_EVEN : COLOR_ROW_ODD); + table.addView(row, new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + )); + + LinearLayout line = new LinearLayout(this); + line.setOrientation(LinearLayout.HORIZONTAL); + line.setGravity(Gravity.CENTER_VERTICAL); + line.setMinimumHeight(dp(44)); + line.setPadding(dp(8), dp(6), dp(8), dp(6)); + row.addView(line, new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + )); + + TextView indicatorView = makeText(hasDetail ? INDICATOR_COLLAPSED : "", 12, COLOR_INFO, false); + line.addView(indicatorView, new LinearLayout.LayoutParams( + dp(16), + LinearLayout.LayoutParams.WRAP_CONTENT + )); + + TextView nameView = makeText(checkName, 12, COLOR_TEXT, false); + line.addView(nameView, new LinearLayout.LayoutParams( + 0, + LinearLayout.LayoutParams.WRAP_CONTENT, + 1f + )); + + TextView statusChip = makeText(status, 12, statusColor(status), true); + statusChip.setGravity(Gravity.END); + statusChip.setMinWidth(dp(56)); + LinearLayout.LayoutParams chipParams = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ); + chipParams.leftMargin = dp(8); + line.addView(statusChip, chipParams); + + if (!hasDetail) { + return; + } + + TextView detailView = makeText(detail, 11, COLOR_DETAIL, false); + detailView.setPadding(dp(24), 0, dp(8), dp(8)); + detailView.setVisibility(View.GONE); + row.addView(detailView, new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + )); + + row.setOnClickListener(view -> { + boolean expanded = detailView.getVisibility() == View.VISIBLE; + detailView.setVisibility(expanded ? View.GONE : View.VISIBLE); + indicatorView.setText(expanded ? INDICATOR_COLLAPSED : INDICATOR_EXPANDED); + }); + } + + /** Adds the collapsed "Raw report" toggle plus the (initially hidden) raw JSON dump. */ + private void addRawJsonSection(String json) { + TextView toggleView = addText(INDICATOR_COLLAPSED + " Raw report (tap to expand)", 12, COLOR_INFO, true, dp(24)); + toggleView.setMinimumHeight(dp(44)); + toggleView.setGravity(Gravity.CENTER_VERTICAL); + + TextView rawView = addText(json, 10, COLOR_INFO, false, dp(4)); + rawView.setVisibility(View.GONE); + + toggleView.setOnClickListener(view -> { + boolean expanded = rawView.getVisibility() == View.VISIBLE; + rawView.setVisibility(expanded ? View.GONE : View.VISIBLE); + toggleView.setText(expanded + ? INDICATOR_COLLAPSED + " Raw report (tap to expand)" + : INDICATOR_EXPANDED + " Raw report (tap to collapse)"); + }); + } + private static String sectionTitle(String backendName) { String lower = backendName.toLowerCase(Locale.ROOT); if (lower.contains("gles") || lower.contains("espryt")) { @@ -298,11 +401,7 @@ public final class PostActivity extends Activity { } private TextView addText(String text, int sizeSp, int color, boolean bold, int topMarginPx) { - TextView view = new TextView(this); - view.setText(text); - view.setTextColor(color); - view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sizeSp); - view.setTypeface(Typeface.MONOSPACE, bold ? Typeface.BOLD : Typeface.NORMAL); + TextView view = makeText(text, sizeSp, color, bold); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT @@ -312,6 +411,16 @@ public final class PostActivity extends Activity { return view; } + /** Builds a styled TextView without attaching it to any parent. */ + private TextView makeText(String text, int sizeSp, int color, boolean bold) { + TextView view = new TextView(this); + view.setText(text); + view.setTextColor(color); + view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sizeSp); + view.setTypeface(Typeface.MONOSPACE, bold ? Typeface.BOLD : Typeface.NORMAL); + return view; + } + private int dp(int value) { return Math.round(value * getResources().getDisplayMetrics().density); }