Compare commits

..
2 Commits
Author SHA1 Message Date
Codex 5122683761 Compact terminal composer controls
Gitea Android APK / build (push) Failing after 0s
Gitea Smoke / smoke (push) Successful in 0s
2026-07-10 02:43:11 +00:00
Codex 924835dd55 Fix terminal enter and ungrouped sessions
Gitea Smoke / smoke (push) Successful in 1s
Gitea Android APK / build (push) Successful in 11m55s
2026-07-09 16:36:52 +00:00
@@ -46,7 +46,9 @@ import org.json.JSONObject;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -60,7 +62,7 @@ public final class MainActivity extends Activity {
private static final int MAX_TERMINAL_COLS = 140;
private static final int MIN_TERMINAL_ROWS = 8;
private static final int MAX_TERMINAL_ROWS = 80;
private static final int TERMINAL_KEYS_HEIGHT_DP = 76;
private static final int TERMINAL_KEYS_HEIGHT_DP = 64;
private static final int STATUS_NORMAL = 0;
private static final int STATUS_BUSY = 1;
private static final int STATUS_SUCCESS = 2;
@@ -92,7 +94,7 @@ public final class MainActivity extends Activity {
private static final String PAGE_TOOLS = "Tools";
private static final String PAGE_UPDATE = "Update";
private static final String PAGE_ABOUT = "About";
private static final String TERMINAL_ENTER = "\n";
private static final String TERMINAL_ENTER = "\r";
private static final String[] SERVER_PROFILES = {
"http://100.89.0.116:3000",
"http://100.89.0.2:3000",
@@ -1320,9 +1322,10 @@ public final class MainActivity extends Activity {
JSONObject rootObject = new JSONObject(text == null || text.isEmpty() ? "{}" : text);
JSONArray projects = rootObject.optJSONArray("projects");
if (projects == null) {
terminalGroupRow.addView(groupLabel("no group"));
renderUngroupedTerminalSessions(sessionName, null);
return;
}
Set<String> groupedSessions = collectGroupedSessions(projects);
for (int projectIndex = 0; projectIndex < projects.length(); projectIndex++) {
JSONObject project = projects.optJSONObject(projectIndex);
if (project == null) {
@@ -1342,12 +1345,62 @@ public final class MainActivity extends Activity {
}
return;
}
terminalGroupRow.addView(groupLabel("no group"));
renderUngroupedTerminalSessions(sessionName, groupedSessions);
} catch (Exception error) {
terminalGroupRow.addView(groupLabel("group parse"));
}
}
private Set<String> collectGroupedSessions(JSONArray projects) {
Set<String> names = new HashSet<>();
for (int projectIndex = 0; projectIndex < projects.length(); projectIndex++) {
JSONObject project = projects.optJSONObject(projectIndex);
JSONArray agents = project == null ? null : project.optJSONArray("agents");
for (int agentIndex = 0; agents != null && agentIndex < agents.length(); agentIndex++) {
String sessionName = agentSessionName(agents.optJSONObject(agentIndex));
if (!sessionName.isEmpty()) {
names.add(sessionName);
}
}
}
return names;
}
private void renderUngroupedTerminalSessions(String sessionName, Set<String> groupedSessions) {
terminalGroupRow.addView(groupLabel("ungrouped..."));
executor.execute(() -> {
try {
List<SessionSummary> sessions = api.getSessions();
runOnUiThread(() -> {
if (!sessionName.equals(activeSessionName) || terminalGroupRow == null) {
return;
}
terminalGroupRow.removeAllViews();
terminalGroupRow.addView(groupLabel("ungrouped"));
int count = 0;
for (SessionSummary session : sessions) {
if (groupedSessions != null && groupedSessions.contains(session.name)) {
continue;
}
terminalGroupRow.addView(groupSessionButton(session.name, session.name.equals(sessionName)));
count++;
}
if (count == 0) {
terminalGroupRow.removeAllViews();
terminalGroupRow.addView(groupLabel("no group"));
}
});
} catch (Exception error) {
runOnUiThread(() -> {
if (sessionName.equals(activeSessionName) && terminalGroupRow != null) {
terminalGroupRow.removeAllViews();
terminalGroupRow.addView(groupLabel("ungrouped failed"));
}
});
}
});
}
private boolean projectContainsSession(JSONArray agents, String sessionName) {
if (agents == null) {
return false;
@@ -1543,10 +1596,10 @@ public final class MainActivity extends Activity {
terminalKeyPageButton = terminalPageButton();
LinearLayout.LayoutParams pageParams = new LinearLayout.LayoutParams(
dp(70),
dp(48)
dp(62),
dp(42)
);
pageParams.rightMargin = dp(6);
pageParams.rightMargin = dp(4);
row.addView(terminalKeyPageButton, pageParams);
inputField = new EditText(this);
@@ -1555,7 +1608,7 @@ public final class MainActivity extends Activity {
inputField.setHint("type, edit, paste");
inputField.setSingleLine(false);
inputField.setMinLines(1);
inputField.setMaxLines(3);
inputField.setMaxLines(2);
inputField.setCursorVisible(true);
inputField.setFocusableInTouchMode(true);
inputField.setGravity(Gravity.TOP | Gravity.START);
@@ -1581,13 +1634,9 @@ public final class MainActivity extends Activity {
return false;
});
row.addView(inputField, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1));
row.addView(toolbarButton("Type", view -> sendTypedText()), new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
dp(48)
));
row.addView(toolbarButton("Send", view -> sendLine()), new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
dp(48)
dp(42)
));
bar.addView(row, matchWrap());
return bar;
@@ -2360,21 +2409,6 @@ public final class MainActivity extends Activity {
setStatus("Sent " + text.length() + " chars");
}
private void sendTypedText() {
if (inputField == null) {
return;
}
String text = inputField.getText().toString();
if (text.isEmpty()) {
return;
}
String normalized = text.replace("\r\n", "\n").replace('\r', '\n');
terminalFollowOutput = true;
sendTerminalInput(normalized);
inputField.setText("");
setStatus("Typed " + text.length() + " chars");
}
private void sendTerminalInput(String data) {
if (activeSessionName == null) {
return;
@@ -2673,9 +2707,9 @@ public final class MainActivity extends Activity {
private Button terminalPageButton() {
Button button = toolbarButton("", view -> setTerminalKeyPage(terminalKeyPage + 1));
button.setTextSize(10);
button.setPadding(dp(5), 0, dp(5), 0);
button.setMinWidth(dp(70));
button.setMinimumWidth(dp(70));
button.setPadding(dp(4), 0, dp(4), 0);
button.setMinWidth(dp(62));
button.setMinimumWidth(dp(62));
button.setOnLongClickListener(view -> {
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
setTerminalKeyPage(terminalKeyPage - 1);
@@ -2691,7 +2725,7 @@ public final class MainActivity extends Activity {
private void updateTerminalPageButton(Button button) {
if (button != null) {
button.setText(" " + accessoryPageName() + " ");
button.setText(accessoryPageName());
}
}
@@ -2708,7 +2742,7 @@ public final class MainActivity extends Activity {
input.setTextColor(COLOR_TEXT);
input.setHintTextColor(COLOR_TEXT_DIM);
input.setTextSize(14);
input.setPadding(dp(10), dp(8), dp(10), dp(8));
input.setPadding(dp(9), dp(6), dp(9), dp(6));
input.setBackground(inputBackground());
}
@@ -2770,18 +2804,18 @@ public final class MainActivity extends Activity {
private void addSoftButton(LinearLayout row, String label, View.OnClickListener listener) {
Button button = toolbarButton(label, listener);
button.setTextSize(isArrowLabel(label) ? 17 : 10);
button.setPadding(dp(5), 0, dp(5), 0);
int width = "Space".equals(label) ? 64 : (isArrowLabel(label) ? 38 : 44);
button.setTextSize(isArrowLabel(label) ? 15 : 9);
button.setPadding(dp(4), 0, dp(4), 0);
int width = "Space".equals(label) ? 56 : (isArrowLabel(label) ? 32 : 38);
button.setMinWidth(dp(width));
button.setMinimumWidth(dp(width));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.MATCH_PARENT
dp(27)
);
params.leftMargin = dp(2);
params.rightMargin = dp(2);
params.topMargin = dp(1);
params.leftMargin = dp(1);
params.rightMargin = dp(1);
params.topMargin = dp(2);
params.bottomMargin = dp(1);
row.addView(button, params);
}