Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de0f7654d0 | ||
|
|
650431e3d1 | ||
|
|
412c69cc36 |
@@ -2,11 +2,11 @@ package com.neatstudio.tmuxandroid;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -27,6 +27,7 @@ import android.text.TextUtils;
|
||||
import android.text.InputType;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.Gravity;
|
||||
import android.view.DragEvent;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
@@ -595,25 +596,11 @@ public final class MainActivity extends Activity {
|
||||
titleBlock.addView(title);
|
||||
row.addView(titleBlock, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1));
|
||||
|
||||
row.addView(primaryButton("+ Session", view -> promptCreateSession()), new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
dp(38)
|
||||
));
|
||||
addHeaderTool(row, "⚙", "Session display settings", view -> promptSessionSettings(""));
|
||||
addHeaderTool(row, "↻", "Refresh sessions", view -> refreshSessions());
|
||||
addHeaderTool(row, "+", "Create session", view -> promptCreateSession());
|
||||
addHeaderTool(row, "▰", "Manage groups", view -> showGroupManagement());
|
||||
header.addView(row, matchWrap());
|
||||
|
||||
LinearLayout utilities = new LinearLayout(this);
|
||||
utilities.setOrientation(LinearLayout.HORIZONTAL);
|
||||
utilities.setGravity(Gravity.END | Gravity.CENTER_VERTICAL);
|
||||
Button display = terminalToolButton("⚙", view -> promptSessionSettings(""));
|
||||
display.setContentDescription("Session display settings");
|
||||
utilities.addView(display);
|
||||
Button refresh = compactButton("↻ Refresh", view -> refreshSessions());
|
||||
refresh.setContentDescription("Refresh sessions");
|
||||
utilities.addView(refresh);
|
||||
Button addGroup = compactButton("+ New group", view -> promptCreateKanbanProject());
|
||||
addGroup.setContentDescription("Add group");
|
||||
utilities.addView(addGroup);
|
||||
header.addView(utilities, spacedMatchWrap(8, 0));
|
||||
return header;
|
||||
}
|
||||
|
||||
@@ -754,7 +741,7 @@ public final class MainActivity extends Activity {
|
||||
}
|
||||
|
||||
private void confirmRemoveSavedServer(String url) {
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Remove server")
|
||||
.setMessage("Remove " + url + " from this device?")
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -788,12 +775,12 @@ public final class MainActivity extends Activity {
|
||||
}
|
||||
|
||||
private void showMainNavigation() {
|
||||
String[] items = {"Projects", "Tools", "Update", "About"};
|
||||
new AlertDialog.Builder(this)
|
||||
String[] items = {"Sessions / groups", "Tools", "Update", "About"};
|
||||
new AppDialogBuilder()
|
||||
.setTitle("tmuxctl")
|
||||
.setItems(items, (dialog, which) -> {
|
||||
if (which == 0) {
|
||||
renderProjectsScreen();
|
||||
openSessionPage();
|
||||
} else if (which == 1) {
|
||||
renderToolsScreen();
|
||||
} else if (which == 2) {
|
||||
@@ -839,7 +826,7 @@ public final class MainActivity extends Activity {
|
||||
));
|
||||
content.addView(sectionTitle("Kanban / Messages"));
|
||||
content.addView(actionPanel(
|
||||
actionButton("Projects", view -> showRaw("Kanban projects", () -> api.kanbanProjects())),
|
||||
actionButton("Groups", view -> showRaw("Groups", () -> api.kanbanProjects())),
|
||||
actionButton("New project", view -> promptCreateKanbanProject()),
|
||||
actionButton("Delete project", view -> promptDeleteKanbanProject()),
|
||||
actionButton("Remove session", view -> promptRemoveKanbanSession())
|
||||
@@ -1053,11 +1040,15 @@ public final class MainActivity extends Activity {
|
||||
|
||||
LinearLayout actions = new LinearLayout(this);
|
||||
actions.setOrientation(LinearLayout.HORIZONTAL);
|
||||
actions.setGravity(Gravity.END | Gravity.CENTER_VERTICAL);
|
||||
Button copy = compactButton("Copy commands", view -> copyText("Server install", SERVER_INSTALL_COMMANDS));
|
||||
actions.addView(copy, new LinearLayout.LayoutParams(0, dp(40), 1));
|
||||
actions.addView(copy, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, dp(32)));
|
||||
Button add = compactButton("Add server", view -> promptCustomServer());
|
||||
LinearLayout.LayoutParams addParams = new LinearLayout.LayoutParams(0, dp(40), 1);
|
||||
addParams.leftMargin = dp(7);
|
||||
LinearLayout.LayoutParams addParams = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
dp(32)
|
||||
);
|
||||
addParams.leftMargin = dp(5);
|
||||
actions.addView(add, addParams);
|
||||
panel.addView(actions, spacedMatchWrap(10, 0));
|
||||
|
||||
@@ -1241,7 +1232,6 @@ public final class MainActivity extends Activity {
|
||||
row.setPadding(dp(8), dp(5), dp(8), dp(5));
|
||||
row.addView(navButton(PAGE_SERVERS, selected, view -> renderServerScreen()));
|
||||
row.addView(navButton(PAGE_SESSIONS, selected, view -> openSessionPage()));
|
||||
row.addView(navButton(PAGE_PROJECTS, selected, view -> renderProjectsScreen()));
|
||||
row.addView(navButton(PAGE_TOOLS, selected, view -> renderToolsScreen()));
|
||||
row.addView(navButton(PAGE_UPDATE, selected, view -> renderUpdateScreen()));
|
||||
row.addView(navButton(PAGE_ABOUT, selected, view -> renderAboutScreen()));
|
||||
@@ -1320,28 +1310,40 @@ public final class MainActivity extends Activity {
|
||||
}
|
||||
|
||||
private LinearLayout actionPanel(Button... buttons) {
|
||||
final int columns = 3;
|
||||
LinearLayout panel = new LinearLayout(this);
|
||||
panel.setOrientation(LinearLayout.VERTICAL);
|
||||
panel.setPadding(dp(6), dp(6), dp(6), dp(1));
|
||||
panel.setPadding(dp(4), dp(4), dp(4), 0);
|
||||
panel.setBackground(panelBackground());
|
||||
LinearLayout row = null;
|
||||
for (int index = 0; index < buttons.length; index++) {
|
||||
if (index % 2 == 0) {
|
||||
if (index % columns == 0) {
|
||||
row = new LinearLayout(this);
|
||||
row.setOrientation(LinearLayout.HORIZONTAL);
|
||||
panel.addView(row, matchWrap());
|
||||
}
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, dp(38), 1);
|
||||
params.leftMargin = dp(3);
|
||||
params.rightMargin = dp(3);
|
||||
params.bottomMargin = dp(6);
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, dp(32), 1);
|
||||
params.leftMargin = dp(2);
|
||||
params.rightMargin = dp(2);
|
||||
params.bottomMargin = dp(4);
|
||||
buttons[index].setTextSize(9);
|
||||
buttons[index].setPadding(dp(4), 0, dp(4), 0);
|
||||
row.addView(buttons[index], params);
|
||||
}
|
||||
int remainder = buttons.length % columns;
|
||||
if (row != null && remainder != 0) {
|
||||
for (int index = remainder; index < columns; index++) {
|
||||
LinearLayout.LayoutParams spacerParams = new LinearLayout.LayoutParams(0, dp(32), 1);
|
||||
spacerParams.leftMargin = dp(2);
|
||||
spacerParams.rightMargin = dp(2);
|
||||
row.addView(new View(this), spacerParams);
|
||||
}
|
||||
}
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
params.bottomMargin = dp(8);
|
||||
params.bottomMargin = dp(6);
|
||||
panel.setLayoutParams(params);
|
||||
return panel;
|
||||
}
|
||||
@@ -1482,6 +1484,7 @@ public final class MainActivity extends Activity {
|
||||
private View sessionGroupSection(String name, List<SessionSummary> sessions, boolean project) {
|
||||
LinearLayout section = new LinearLayout(this);
|
||||
section.setOrientation(LinearLayout.VERTICAL);
|
||||
section.setOnDragListener((view, event) -> handleSessionDrop(section, name, project, event));
|
||||
|
||||
LinearLayout heading = new LinearLayout(this);
|
||||
heading.setOrientation(LinearLayout.HORIZONTAL);
|
||||
@@ -1504,6 +1507,10 @@ public final class MainActivity extends Activity {
|
||||
count.setTextSize(11);
|
||||
count.setTypeface(Typeface.MONOSPACE);
|
||||
heading.addView(count);
|
||||
Button actions = terminalToolButton("⋮", view -> showGroupActions(name, project));
|
||||
actions.setContentDescription("Actions for " + name);
|
||||
heading.addView(new View(this), new LinearLayout.LayoutParams(0, 1, 1));
|
||||
heading.addView(actions);
|
||||
section.addView(heading);
|
||||
|
||||
if (sessions.isEmpty()) {
|
||||
@@ -1515,13 +1522,79 @@ public final class MainActivity extends Activity {
|
||||
section.addView(empty, matchWrap());
|
||||
} else {
|
||||
for (SessionSummary session : sessions) {
|
||||
section.addView(sessionRow(session), spacedMatchWrap(0, 10));
|
||||
section.addView(sessionRow(session, project ? name : null), spacedMatchWrap(0, 10));
|
||||
}
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
private boolean handleSessionDrop(
|
||||
LinearLayout section,
|
||||
String targetGroup,
|
||||
boolean targetIsGroup,
|
||||
DragEvent event
|
||||
) {
|
||||
if (!(event.getLocalState() instanceof SessionDrag)) {
|
||||
return false;
|
||||
}
|
||||
if (event.getAction() == DragEvent.ACTION_DRAG_ENTERED) {
|
||||
section.setBackground(rounded(COLOR_CARD_ALT, 8, COLOR_ACCENT, 1));
|
||||
return true;
|
||||
}
|
||||
if (event.getAction() == DragEvent.ACTION_DRAG_EXITED
|
||||
|| event.getAction() == DragEvent.ACTION_DRAG_ENDED) {
|
||||
section.setBackgroundColor(Color.TRANSPARENT);
|
||||
return true;
|
||||
}
|
||||
if (event.getAction() == DragEvent.ACTION_DROP) {
|
||||
section.setBackgroundColor(Color.TRANSPARENT);
|
||||
SessionDrag drag = (SessionDrag) event.getLocalState();
|
||||
moveSessionBetweenGroups(drag.sessionName, drag.sourceGroup, targetIsGroup ? targetGroup : null);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showGroupActions(String groupName, boolean project) {
|
||||
String[] items = project
|
||||
? new String[]{"Add session", "Messages", "Delete group"}
|
||||
: new String[]{"Create group", "Refresh sessions"};
|
||||
new AppDialogBuilder()
|
||||
.setTitle(groupName)
|
||||
.setItems(items, (dialog, which) -> {
|
||||
if (!project) {
|
||||
if (which == 0) {
|
||||
promptCreateKanbanProject();
|
||||
} else {
|
||||
refreshSessions();
|
||||
}
|
||||
} else if (which == 0) {
|
||||
promptAddKanbanSessionToProject(groupName);
|
||||
} else if (which == 1) {
|
||||
showRaw("Group messages: " + groupName, () -> api.groupMessages(groupName));
|
||||
} else {
|
||||
runApiAction("Delete group", () -> api.deleteKanbanProject(groupName));
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showGroupManagement() {
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Groups")
|
||||
.setItems(new String[]{"Create group", "Delete group", "Group messages"}, (dialog, which) -> {
|
||||
if (which == 0) {
|
||||
promptCreateKanbanProject();
|
||||
} else if (which == 1) {
|
||||
promptDeleteKanbanProject();
|
||||
} else {
|
||||
promptGroupMessages();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void refreshProjects() {
|
||||
if (projectList != null) {
|
||||
projectList.removeAllViews();
|
||||
@@ -1669,7 +1742,7 @@ public final class MainActivity extends Activity {
|
||||
list.addView(empty);
|
||||
}
|
||||
for (SessionSummary session : sessions) {
|
||||
list.addView(sessionRow(session), spacedMatchWrap(0, 10));
|
||||
list.addView(sessionRow(session, null), spacedMatchWrap(0, 10));
|
||||
}
|
||||
if (sessionSummaryText != null) {
|
||||
sessionSummaryText.setText("Server: " + getServerUrl() + "\nSessions: " + sessions.size());
|
||||
@@ -1677,7 +1750,7 @@ public final class MainActivity extends Activity {
|
||||
setStatus("Loaded " + sessions.size() + " sessions");
|
||||
}
|
||||
|
||||
private View sessionRow(SessionSummary session) {
|
||||
private View sessionRow(SessionSummary session, String sourceGroup) {
|
||||
LinearLayout row = new LinearLayout(this);
|
||||
row.setOrientation(LinearLayout.HORIZONTAL);
|
||||
row.setGravity(Gravity.CENTER_VERTICAL);
|
||||
@@ -1687,7 +1760,13 @@ public final class MainActivity extends Activity {
|
||||
row.setOnClickListener(view -> openTerminal(session.name));
|
||||
row.setOnLongClickListener(view -> {
|
||||
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
showSessionActions(session.name);
|
||||
ClipData data = ClipData.newPlainText("tmux-session", session.name);
|
||||
view.startDragAndDrop(
|
||||
data,
|
||||
new View.DragShadowBuilder(view),
|
||||
new SessionDrag(session.name, sourceGroup),
|
||||
0
|
||||
);
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -1741,7 +1820,7 @@ public final class MainActivity extends Activity {
|
||||
row.addView(textBlock, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1));
|
||||
|
||||
Button move = terminalToolButton("⇄", view -> promptAddKanbanSession(session.name));
|
||||
move.setContentDescription("Move " + session.name + " to project");
|
||||
move.setContentDescription("Move " + session.name + " to group");
|
||||
row.addView(move);
|
||||
Button kill = terminalToolButton("×", view -> confirmKill(session.name));
|
||||
kill.setContentDescription("Kill session");
|
||||
@@ -1855,7 +1934,7 @@ public final class MainActivity extends Activity {
|
||||
}
|
||||
|
||||
private void confirmKill(String sessionName) {
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Kill session")
|
||||
.setMessage("Kill tmux session \"" + sessionName + "\"?")
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -3039,7 +3118,103 @@ public final class MainActivity extends Activity {
|
||||
}
|
||||
|
||||
private void promptAddKanbanSession(String sessionName) {
|
||||
promptText("Add to kanban project", "project", "", projectName -> api.addKanbanSession(projectName, sessionName));
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
List<String> groups = kanbanGroupNames(api.kanbanProjects());
|
||||
runOnUiThread(() -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
List<String> choices = new ArrayList<>();
|
||||
choices.add("Ungrouped");
|
||||
choices.addAll(groups);
|
||||
choices.add("+ Create new group");
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Move " + sessionName)
|
||||
.setItems(choices.toArray(new String[0]), (dialog, which) -> {
|
||||
if (which == 0) {
|
||||
moveSessionToGroup(sessionName, null);
|
||||
} else if (which == choices.size() - 1) {
|
||||
promptCreateGroupForSession(sessionName);
|
||||
} else {
|
||||
moveSessionToGroup(sessionName, choices.get(which));
|
||||
}
|
||||
})
|
||||
.show();
|
||||
});
|
||||
} catch (Exception error) {
|
||||
runOnUiThread(() -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
showMessage("Group load failed: " + error.getMessage());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<String> kanbanGroupNames(String projectsText) throws Exception {
|
||||
List<String> groups = new ArrayList<>();
|
||||
JSONObject object = new JSONObject(projectsText == null || projectsText.isEmpty() ? "{}" : projectsText);
|
||||
JSONArray projects = object.optJSONArray("projects");
|
||||
for (int index = 0; projects != null && index < projects.length(); index++) {
|
||||
JSONObject project = projects.optJSONObject(index);
|
||||
if (project != null && !project.optString("name").isEmpty()) {
|
||||
groups.add(project.optString("name"));
|
||||
}
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
private void promptCreateGroupForSession(String sessionName) {
|
||||
promptText("Create group for " + sessionName, "group name", "", groupName -> {
|
||||
if (groupName.isEmpty()) {
|
||||
throw new IllegalArgumentException("Group name is required");
|
||||
}
|
||||
api.createKanbanProject(groupName, "~", "");
|
||||
api.addKanbanSession(groupName, sessionName);
|
||||
});
|
||||
}
|
||||
|
||||
private void moveSessionToGroup(String sessionName, String targetGroup) {
|
||||
runApiAction("Move session", () -> {
|
||||
JSONObject object = new JSONObject(api.kanbanProjects());
|
||||
JSONArray projects = object.optJSONArray("projects");
|
||||
boolean alreadyInTarget = false;
|
||||
for (int projectIndex = 0; projects != null && projectIndex < projects.length(); projectIndex++) {
|
||||
JSONObject project = projects.optJSONObject(projectIndex);
|
||||
if (project == null) {
|
||||
continue;
|
||||
}
|
||||
String projectName = project.optString("name");
|
||||
JSONArray agents = project.optJSONArray("agents");
|
||||
for (int agentIndex = 0; agents != null && agentIndex < agents.length(); agentIndex++) {
|
||||
if (!sessionName.equals(agentSessionName(agents.optJSONObject(agentIndex)))) {
|
||||
continue;
|
||||
}
|
||||
if (projectName.equals(targetGroup)) {
|
||||
alreadyInTarget = true;
|
||||
} else {
|
||||
api.removeKanbanSession(projectName, sessionName, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetGroup != null && !alreadyInTarget) {
|
||||
api.addKanbanSession(targetGroup, sessionName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void moveSessionBetweenGroups(String sessionName, String sourceGroup, String targetGroup) {
|
||||
if ((sourceGroup == null && targetGroup == null)
|
||||
|| (sourceGroup != null && sourceGroup.equals(targetGroup))) {
|
||||
return;
|
||||
}
|
||||
runApiAction("Move session", () -> {
|
||||
if (sourceGroup != null) {
|
||||
api.removeKanbanSession(sourceGroup, sessionName, false);
|
||||
}
|
||||
if (targetGroup != null) {
|
||||
api.addKanbanSession(targetGroup, sessionName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void promptAddKanbanSessionToProject(String projectName) {
|
||||
@@ -3051,7 +3226,7 @@ public final class MainActivity extends Activity {
|
||||
EditText project = formField(form, "Project", "");
|
||||
EditText agent = formField(form, "Agent/session name", "");
|
||||
EditText kill = formField(form, "Kill too: true or false", "false");
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Remove kanban session")
|
||||
.setView(form)
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -3371,7 +3546,7 @@ public final class MainActivity extends Activity {
|
||||
EditText body = formField(form, "Message", "");
|
||||
body.setMinLines(3);
|
||||
body.setSingleLine(false);
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Send group message")
|
||||
.setView(form)
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -3392,7 +3567,7 @@ public final class MainActivity extends Activity {
|
||||
LinearLayout form = formRoot();
|
||||
EditText project = formField(form, "Project", "");
|
||||
EditText message = formField(form, "Message ID", "");
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Scan group message")
|
||||
.setView(form)
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -3417,7 +3592,7 @@ public final class MainActivity extends Activity {
|
||||
EditText body = formField(form, "Body", "");
|
||||
body.setMinLines(2);
|
||||
body.setSingleLine(false);
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Post hook event")
|
||||
.setView(form)
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -3436,7 +3611,7 @@ public final class MainActivity extends Activity {
|
||||
LinearLayout form = formRoot();
|
||||
EditText session = formField(form, "Session optional", "");
|
||||
EditText url = formField(form, "Image URL", "");
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Upload image URL")
|
||||
.setView(form)
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -3453,7 +3628,7 @@ public final class MainActivity extends Activity {
|
||||
EditText session = new EditText(this);
|
||||
session.setSingleLine(true);
|
||||
session.setHint("session optional");
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Upload image file")
|
||||
.setView(session)
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -3479,7 +3654,7 @@ public final class MainActivity extends Activity {
|
||||
LinearLayout form = formRoot();
|
||||
EditText path = formField(form, "Path", "");
|
||||
EditText basePath = formField(form, "Base path optional", "");
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Image preview info")
|
||||
.setView(form)
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -3496,7 +3671,7 @@ public final class MainActivity extends Activity {
|
||||
LinearLayout form = formRoot();
|
||||
EditText path = formField(form, "Path", "");
|
||||
EditText basePath = formField(form, "Base path optional", "");
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Open image preview")
|
||||
.setView(form)
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -3531,7 +3706,7 @@ public final class MainActivity extends Activity {
|
||||
text.append('\n');
|
||||
text.append(permissionSummary());
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Permissions / update")
|
||||
.setMessage(text.toString())
|
||||
.setNegativeButton("Close", null)
|
||||
@@ -3569,7 +3744,7 @@ public final class MainActivity extends Activity {
|
||||
"Preview manual: " + BuildConfig.DEFAULT_PREVIEW_UPDATE_URL,
|
||||
"Custom URL"
|
||||
};
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Update source")
|
||||
.setItems(items, (dialog, which) -> {
|
||||
if (which == 0) {
|
||||
@@ -3704,7 +3879,7 @@ public final class MainActivity extends Activity {
|
||||
image.setImageBitmap(bitmap);
|
||||
image.setAdjustViewBounds(true);
|
||||
image.setPadding(dp(8), dp(8), dp(8), dp(8));
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle("Image preview")
|
||||
.setView(image)
|
||||
.setPositiveButton("Close", null)
|
||||
@@ -3742,7 +3917,7 @@ public final class MainActivity extends Activity {
|
||||
input.setHint(hint);
|
||||
input.setText(value);
|
||||
input.setSelectAllOnFocus(true);
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle(title)
|
||||
.setView(input)
|
||||
.setNegativeButton("Cancel", null)
|
||||
@@ -3800,7 +3975,7 @@ public final class MainActivity extends Activity {
|
||||
ScrollView scroll = new ScrollView(this);
|
||||
TextView content = new TextView(this);
|
||||
content.setText(text == null || text.isEmpty() ? "(empty)" : text);
|
||||
content.setTextColor(Color.rgb(20, 24, 30));
|
||||
content.setTextColor(COLOR_TEXT);
|
||||
content.setTextSize(12);
|
||||
content.setTypeface(Typeface.MONOSPACE);
|
||||
content.setTextIsSelectable(true);
|
||||
@@ -3809,13 +3984,150 @@ public final class MainActivity extends Activity {
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
new AlertDialog.Builder(this)
|
||||
new AppDialogBuilder()
|
||||
.setTitle(title)
|
||||
.setView(scroll)
|
||||
.setPositiveButton("Close", null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private final class AppDialogBuilder {
|
||||
private String title = "";
|
||||
private String message;
|
||||
private View content;
|
||||
private String[] items;
|
||||
private DialogInterface.OnClickListener itemAction;
|
||||
private String negativeLabel;
|
||||
private DialogInterface.OnClickListener negativeAction;
|
||||
private String neutralLabel;
|
||||
private DialogInterface.OnClickListener neutralAction;
|
||||
private String positiveLabel;
|
||||
private DialogInterface.OnClickListener positiveAction;
|
||||
|
||||
AppDialogBuilder setTitle(String value) {
|
||||
title = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
AppDialogBuilder setMessage(String value) {
|
||||
message = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
AppDialogBuilder setView(View value) {
|
||||
content = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
AppDialogBuilder setItems(String[] values, DialogInterface.OnClickListener action) {
|
||||
items = values;
|
||||
itemAction = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
AppDialogBuilder setNegativeButton(String label, DialogInterface.OnClickListener action) {
|
||||
negativeLabel = label;
|
||||
negativeAction = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
AppDialogBuilder setNeutralButton(String label, DialogInterface.OnClickListener action) {
|
||||
neutralLabel = label;
|
||||
neutralAction = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
AppDialogBuilder setPositiveButton(String label, DialogInterface.OnClickListener action) {
|
||||
positiveLabel = label;
|
||||
positiveAction = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
Dialog show() {
|
||||
Dialog dialog = new Dialog(MainActivity.this);
|
||||
LinearLayout sheet = bottomSheetContent(dialog, title, dialogSubtitle());
|
||||
if (message != null) {
|
||||
TextView body = bodyText(message);
|
||||
body.setTextSize(12);
|
||||
body.setTextIsSelectable(true);
|
||||
body.setPadding(dp(2), dp(4), dp(2), dp(8));
|
||||
sheet.addView(body, matchWrap());
|
||||
}
|
||||
if (content != null) {
|
||||
LinearLayout.LayoutParams contentParams = matchWrap();
|
||||
contentParams.bottomMargin = dp(10);
|
||||
sheet.addView(content, contentParams);
|
||||
}
|
||||
if (items != null) {
|
||||
for (int index = 0; index < items.length; index++) {
|
||||
final int selected = index;
|
||||
Button choice = toolbarButton(items[index], view -> {
|
||||
dialog.dismiss();
|
||||
if (itemAction != null) {
|
||||
itemAction.onClick(dialog, selected);
|
||||
}
|
||||
});
|
||||
choice.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
|
||||
choice.setTextSize(11);
|
||||
LinearLayout.LayoutParams choiceParams = matchWrap();
|
||||
choiceParams.height = dp(42);
|
||||
choiceParams.bottomMargin = dp(6);
|
||||
sheet.addView(choice, choiceParams);
|
||||
}
|
||||
}
|
||||
addDialogActions(dialog, sheet);
|
||||
showBottomSheet(dialog, sheet, null);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private String dialogSubtitle() {
|
||||
if (items != null) {
|
||||
return "Choose an option";
|
||||
}
|
||||
if (content != null) {
|
||||
return "Complete the fields below";
|
||||
}
|
||||
return "Confirm this action";
|
||||
}
|
||||
|
||||
private void addDialogActions(Dialog dialog, LinearLayout sheet) {
|
||||
if (negativeLabel == null && neutralLabel == null && positiveLabel == null) {
|
||||
return;
|
||||
}
|
||||
LinearLayout actions = new LinearLayout(MainActivity.this);
|
||||
actions.setOrientation(LinearLayout.HORIZONTAL);
|
||||
actions.setGravity(Gravity.END | Gravity.CENTER_VERTICAL);
|
||||
addDialogAction(actions, dialog, neutralLabel, neutralAction, DialogInterface.BUTTON_NEUTRAL, false);
|
||||
addDialogAction(actions, dialog, negativeLabel, negativeAction, DialogInterface.BUTTON_NEGATIVE, false);
|
||||
addDialogAction(actions, dialog, positiveLabel, positiveAction, DialogInterface.BUTTON_POSITIVE,
|
||||
"Remove".equals(positiveLabel) || "Kill".equals(positiveLabel) || "Delete".equals(positiveLabel));
|
||||
sheet.addView(actions, spacedMatchWrap(4, 0));
|
||||
}
|
||||
|
||||
private void addDialogAction(
|
||||
LinearLayout actions,
|
||||
Dialog dialog,
|
||||
String label,
|
||||
DialogInterface.OnClickListener action,
|
||||
int which,
|
||||
boolean danger
|
||||
) {
|
||||
if (label == null) {
|
||||
return;
|
||||
}
|
||||
Button button = compactButton(label, view -> {
|
||||
dialog.dismiss();
|
||||
if (action != null) {
|
||||
action.onClick(dialog, which);
|
||||
}
|
||||
});
|
||||
if (danger) {
|
||||
button.setTextColor(COLOR_DANGER);
|
||||
}
|
||||
actions.addView(button);
|
||||
}
|
||||
}
|
||||
|
||||
private LinearLayout formRoot() {
|
||||
LinearLayout form = new LinearLayout(this);
|
||||
form.setOrientation(LinearLayout.VERTICAL);
|
||||
@@ -5156,6 +5468,16 @@ public final class MainActivity extends Activity {
|
||||
void onValue(int value);
|
||||
}
|
||||
|
||||
private static final class SessionDrag {
|
||||
final String sessionName;
|
||||
final String sourceGroup;
|
||||
|
||||
SessionDrag(String sessionName, String sourceGroup) {
|
||||
this.sessionName = sessionName;
|
||||
this.sourceGroup = sourceGroup;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SheetAction {
|
||||
final String icon;
|
||||
final String title;
|
||||
|
||||
Reference in New Issue
Block a user