From c683f135e38616e3913be0e89466930f4d3e5847 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 6 Jul 2026 13:12:01 +0000 Subject: [PATCH] Add sessions page status panel --- README.md | 1 + .../neatstudio/tmuxandroid/MainActivity.java | 38 +++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 430bad9..94a715e 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ APIs directly: - one-tap probe for the preset Tailscale APIs, showing health/version and session counts - native tmux session list +- Sessions page with current API/server and loaded session count - create, rename, send command, split pane, select pane, kill pane, pin, mute, and kill session through HTTP API - open one live terminal viewer through `/ws/terminal` diff --git a/app/src/main/java/com/neatstudio/tmuxandroid/MainActivity.java b/app/src/main/java/com/neatstudio/tmuxandroid/MainActivity.java index 913df9e..e5b5789 100644 --- a/app/src/main/java/com/neatstudio/tmuxandroid/MainActivity.java +++ b/app/src/main/java/com/neatstudio/tmuxandroid/MainActivity.java @@ -81,6 +81,7 @@ public final class MainActivity extends Activity { private EditText urlField; private ProgressBar progressBar; private TextView statusText; + private TextView sessionSummaryText; private TextView terminalText; private ScrollView terminalScroll; private EditText inputField; @@ -190,11 +191,14 @@ public final class MainActivity extends Activity { )); ScrollView scroll = new ScrollView(this); + LinearLayout content = pageContent(); + content.addView(sessionSummaryBlock()); + content.addView(sectionTitle("Tmux sessions")); LinearLayout list = new LinearLayout(this); list.setOrientation(LinearLayout.VERTICAL); - list.setPadding(dp(8), dp(8), dp(8), dp(8)); list.setTag("session-list"); - scroll.addView(list); + content.addView(list); + scroll.addView(content); root.addView(scroll, new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, 0, @@ -206,6 +210,15 @@ public final class MainActivity extends Activity { )); } + private View sessionSummaryBlock() { + View block = infoBlock( + "Active API", + "Server: " + getServerUrl() + "\nSessions: loading" + ); + sessionSummaryText = findBodyText(block); + return block; + } + private void renderToolsScreen() { closeTerminalSocket(); activeSessionName = null; @@ -547,6 +560,17 @@ public final class MainActivity extends Activity { return block; } + private TextView findBodyText(View block) { + if (!(block instanceof LinearLayout)) { + return null; + } + LinearLayout layout = (LinearLayout) block; + if (layout.getChildCount() < 2 || !(layout.getChildAt(1) instanceof TextView)) { + return null; + } + return (TextView) layout.getChildAt(1); + } + private LinearLayout actionPanel(Button... buttons) { LinearLayout panel = new LinearLayout(this); panel.setOrientation(LinearLayout.VERTICAL); @@ -602,7 +626,12 @@ public final class MainActivity extends Activity { List sessions = api.getSessions(); runOnUiThread(() -> renderSessionList(sessions)); } catch (Exception error) { - runOnUiThread(() -> showMessage("Session load failed: " + error.getMessage())); + runOnUiThread(() -> { + if (sessionSummaryText != null) { + sessionSummaryText.setText("Server: " + getServerUrl() + "\nSessions: failed - " + error.getMessage()); + } + showMessage("Session load failed: " + error.getMessage()); + }); } finally { runOnUiThread(() -> progressBar.setVisibility(View.GONE)); } @@ -623,6 +652,9 @@ public final class MainActivity extends Activity { for (SessionSummary session : sessions) { list.addView(sessionRow(session), matchWrap()); } + if (sessionSummaryText != null) { + sessionSummaryText.setText("Server: " + getServerUrl() + "\nSessions: " + sessions.size()); + } setStatus("Loaded " + sessions.size() + " sessions"); }