Added: Add support for Share selected text of terminal in long hold MORE menu so that users don't have to copy and paste to move text between apps

This commit is contained in:
agnostic-apollo
2022-10-04 04:05:43 +05:00
parent 0c14c291b2
commit 3f7a939313
7 changed files with 90 additions and 7 deletions

View File

@@ -38,6 +38,7 @@ import com.termux.shared.activity.ActivityUtils;
import com.termux.shared.activity.media.AppCompatActivityUtils; import com.termux.shared.activity.media.AppCompatActivityUtils;
import com.termux.shared.data.IntentUtils; import com.termux.shared.data.IntentUtils;
import com.termux.shared.android.PermissionUtils; import com.termux.shared.android.PermissionUtils;
import com.termux.shared.data.DataUtils;
import com.termux.shared.termux.TermuxConstants; import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY; import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
import com.termux.app.activities.HelpActivity; import com.termux.app.activities.HelpActivity;
@@ -179,6 +180,7 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
private static final int CONTEXT_MENU_SELECT_URL_ID = 0; private static final int CONTEXT_MENU_SELECT_URL_ID = 0;
private static final int CONTEXT_MENU_SHARE_TRANSCRIPT_ID = 1; private static final int CONTEXT_MENU_SHARE_TRANSCRIPT_ID = 1;
private static final int CONTEXT_MENU_SHARE_SELECTED_TEXT = 10;
private static final int CONTEXT_MENU_AUTOFILL_ID = 2; private static final int CONTEXT_MENU_AUTOFILL_ID = 2;
private static final int CONTEXT_MENU_RESET_TERMINAL_ID = 3; private static final int CONTEXT_MENU_RESET_TERMINAL_ID = 3;
private static final int CONTEXT_MENU_KILL_PROCESS_ID = 4; private static final int CONTEXT_MENU_KILL_PROCESS_ID = 4;
@@ -640,7 +642,10 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
menu.add(Menu.NONE, CONTEXT_MENU_SELECT_URL_ID, Menu.NONE, R.string.action_select_url); menu.add(Menu.NONE, CONTEXT_MENU_SELECT_URL_ID, Menu.NONE, R.string.action_select_url);
menu.add(Menu.NONE, CONTEXT_MENU_SHARE_TRANSCRIPT_ID, Menu.NONE, R.string.action_share_transcript); menu.add(Menu.NONE, CONTEXT_MENU_SHARE_TRANSCRIPT_ID, Menu.NONE, R.string.action_share_transcript);
if (addAutoFillMenu) menu.add(Menu.NONE, CONTEXT_MENU_AUTOFILL_ID, Menu.NONE, R.string.action_autofill_password); if (!DataUtils.isNullOrEmpty(mTerminalView.getStoredSelectedText()))
menu.add(Menu.NONE, CONTEXT_MENU_SHARE_SELECTED_TEXT, Menu.NONE, R.string.action_share_selected_text);
if (addAutoFillMenu)
menu.add(Menu.NONE, CONTEXT_MENU_AUTOFILL_ID, Menu.NONE, R.string.action_autofill_password);
menu.add(Menu.NONE, CONTEXT_MENU_RESET_TERMINAL_ID, Menu.NONE, R.string.action_reset_terminal); menu.add(Menu.NONE, CONTEXT_MENU_RESET_TERMINAL_ID, Menu.NONE, R.string.action_reset_terminal);
menu.add(Menu.NONE, CONTEXT_MENU_KILL_PROCESS_ID, Menu.NONE, getResources().getString(R.string.action_kill_process, getCurrentSession().getPid())).setEnabled(currentSession.isRunning()); menu.add(Menu.NONE, CONTEXT_MENU_KILL_PROCESS_ID, Menu.NONE, getResources().getString(R.string.action_kill_process, getCurrentSession().getPid())).setEnabled(currentSession.isRunning());
menu.add(Menu.NONE, CONTEXT_MENU_STYLING_ID, Menu.NONE, R.string.action_style_terminal); menu.add(Menu.NONE, CONTEXT_MENU_STYLING_ID, Menu.NONE, R.string.action_style_terminal);
@@ -668,6 +673,9 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
case CONTEXT_MENU_SHARE_TRANSCRIPT_ID: case CONTEXT_MENU_SHARE_TRANSCRIPT_ID:
mTermuxTerminalViewClient.shareSessionTranscript(); mTermuxTerminalViewClient.shareSessionTranscript();
return true; return true;
case CONTEXT_MENU_SHARE_SELECTED_TEXT:
mTermuxTerminalViewClient.shareSelectedText();
return true;
case CONTEXT_MENU_AUTOFILL_ID: case CONTEXT_MENU_AUTOFILL_ID:
requestAutoFill(); requestAutoFill();
return true; return true;
@@ -697,6 +705,13 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
} }
} }
@Override
public void onContextMenuClosed(Menu menu) {
super.onContextMenuClosed(menu);
// onContextMenuClosed() is triggered twice if back button is pressed to dismiss instead of tap for some reason
mTerminalView.onContextMenuClosed(menu);
}
private void showKillSessionDialog(TerminalSession session) { private void showKillSessionDialog(TerminalSession session) {
if (session == null) return; if (session == null) return;

View File

@@ -17,6 +17,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.termux.R; import com.termux.R;
import com.termux.shared.interact.ShareUtils;
import com.termux.shared.termux.shell.command.runner.terminal.TermuxSession; import com.termux.shared.termux.shell.command.runner.terminal.TermuxSession;
import com.termux.shared.termux.interact.TextInputDialogUtils; import com.termux.shared.termux.interact.TextInputDialogUtils;
import com.termux.app.TermuxActivity; import com.termux.app.TermuxActivity;

View File

@@ -684,6 +684,13 @@ public class TermuxTerminalViewClient extends TermuxTerminalViewClientBase {
transcriptText, mActivity.getString(R.string.title_share_transcript_with)); transcriptText, mActivity.getString(R.string.title_share_transcript_with));
} }
public void shareSelectedText() {
String selectedText = mActivity.getTerminalView().getStoredSelectedText();
if (DataUtils.isNullOrEmpty(selectedText)) return;
ShareUtils.shareText(mActivity, mActivity.getString(R.string.title_share_selected_text),
selectedText, mActivity.getString(R.string.title_share_selected_text_with));
}
public void showUrlSelection() { public void showUrlSelection() {
TerminalSession session = mActivity.getCurrentSession(); TerminalSession session = mActivity.getCurrentSession();
if (session == null) return; if (session == null) return;

View File

@@ -69,6 +69,10 @@
<string name="title_share_transcript">Terminal transcript</string> <string name="title_share_transcript">Terminal transcript</string>
<string name="title_share_transcript_with">Send transcript to:</string> <string name="title_share_transcript_with">Send transcript to:</string>
<string name="action_share_selected_text">Share selected text</string>
<string name="title_share_selected_text">Terminal Text</string>
<string name="title_share_selected_text_with">Send selected text to:</string>
<string name="action_autofill_password">Autofill password</string> <string name="action_autofill_password">Autofill password</string>
<string name="action_reset_terminal">Reset</string> <string name="action_reset_terminal">Reset</string>

View File

@@ -2,6 +2,7 @@ package com.termux.view;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
@@ -19,6 +20,7 @@ import android.view.HapticFeedbackConstants;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyCharacterMap; import android.view.KeyCharacterMap;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.Menu;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
@@ -30,6 +32,7 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnection;
import android.widget.Scroller; import android.widget.Scroller;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import com.termux.terminal.KeyHandler; import com.termux.terminal.KeyHandler;
@@ -456,6 +459,14 @@ public final class TerminalView extends View {
if (mAccessibilityEnabled) setContentDescription(getText()); if (mAccessibilityEnabled) setContentDescription(getText());
} }
/** This must be called by the hosting activity in {@link Activity#onContextMenuClosed(Menu)}
* when context menu for the {@link TerminalView} is started by
* {@link TextSelectionCursorController#ACTION_MORE} is closed. */
public void onContextMenuClosed(Menu menu) {
// Unset the stored text since it shouldn't be used anymore and should be cleared from memory
unsetStoredSelectedText();
}
/** /**
* Sets the text size, which in turn sets the number of rows and columns. * Sets the text size, which in turn sets the number of rows and columns.
* *
@@ -1206,6 +1217,25 @@ public final class TerminalView extends View {
} }
} }
/** Get the currently selected text if selecting. */
public String getSelectedText() {
if (isSelectingText() && mTextSelectionCursorController != null)
return mTextSelectionCursorController.getSelectedText();
else
return null;
}
/** Get the selected text stored before "MORE" button was pressed on the context menu. */
@Nullable
public String getStoredSelectedText() {
return mTextSelectionCursorController != null ? mTextSelectionCursorController.getStoredSelectedText() : null;
}
/** Unset the selected text stored before "MORE" button was pressed on the context menu. */
public void unsetStoredSelectedText() {
if (mTextSelectionCursorController != null) mTextSelectionCursorController.unsetStoredSelectedText();
}
private ActionMode getTextSelectionActionMode() { private ActionMode getTextSelectionActionMode() {
if (mTextSelectionCursorController != null) { if (mTextSelectionCursorController != null) {
return mTextSelectionCursorController.getActionMode(); return mTextSelectionCursorController.getActionMode();

View File

@@ -11,6 +11,8 @@ import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import androidx.annotation.Nullable;
import com.termux.terminal.TerminalBuffer; import com.termux.terminal.TerminalBuffer;
import com.termux.terminal.WcWidth; import com.termux.terminal.WcWidth;
import com.termux.view.R; import com.termux.view.R;
@@ -20,6 +22,7 @@ public class TextSelectionCursorController implements CursorController {
private final TerminalView terminalView; private final TerminalView terminalView;
private final TextSelectionHandleView mStartHandle, mEndHandle; private final TextSelectionHandleView mStartHandle, mEndHandle;
private String mStoredSelectedText;
private boolean mIsSelectingText = false; private boolean mIsSelectingText = false;
private long mShowStartTime = System.currentTimeMillis(); private long mShowStartTime = System.currentTimeMillis();
@@ -27,9 +30,9 @@ public class TextSelectionCursorController implements CursorController {
private int mSelX1 = -1, mSelX2 = -1, mSelY1 = -1, mSelY2 = -1; private int mSelX1 = -1, mSelX2 = -1, mSelY1 = -1, mSelY2 = -1;
private ActionMode mActionMode; private ActionMode mActionMode;
private final int ACTION_COPY = 1; public final int ACTION_COPY = 1;
private final int ACTION_PASTE = 2; public final int ACTION_PASTE = 2;
private final int ACTION_MORE = 3; public final int ACTION_MORE = 3;
public TextSelectionCursorController(TerminalView terminalView) { public TextSelectionCursorController(TerminalView terminalView) {
this.terminalView = terminalView; this.terminalView = terminalView;
@@ -112,7 +115,7 @@ public class TextSelectionCursorController implements CursorController {
ClipboardManager clipboard = (ClipboardManager) terminalView.getContext().getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) terminalView.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
menu.add(Menu.NONE, ACTION_COPY, Menu.NONE, R.string.copy_text).setShowAsAction(show); menu.add(Menu.NONE, ACTION_COPY, Menu.NONE, R.string.copy_text).setShowAsAction(show);
menu.add(Menu.NONE, ACTION_PASTE, Menu.NONE, R.string.paste_text).setEnabled(clipboard.hasPrimaryClip()).setShowAsAction(show); menu.add(Menu.NONE, ACTION_PASTE, Menu.NONE, R.string.paste_text).setEnabled(clipboard != null && clipboard.hasPrimaryClip()).setShowAsAction(show);
menu.add(Menu.NONE, ACTION_MORE, Menu.NONE, R.string.text_selection_more); menu.add(Menu.NONE, ACTION_MORE, Menu.NONE, R.string.text_selection_more);
return true; return true;
} }
@@ -131,7 +134,7 @@ public class TextSelectionCursorController implements CursorController {
switch (item.getItemId()) { switch (item.getItemId()) {
case ACTION_COPY: case ACTION_COPY:
String selectedText = terminalView.mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2).trim(); String selectedText = getSelectedText();
terminalView.mTermSession.onCopyTextToClipboard(selectedText); terminalView.mTermSession.onCopyTextToClipboard(selectedText);
terminalView.stopTextSelectionMode(); terminalView.stopTextSelectionMode();
break; break;
@@ -140,7 +143,13 @@ public class TextSelectionCursorController implements CursorController {
terminalView.mTermSession.onPasteTextFromClipboard(); terminalView.mTermSession.onPasteTextFromClipboard();
break; break;
case ACTION_MORE: case ACTION_MORE:
terminalView.stopTextSelectionMode(); //we stop text selection first, otherwise handles will show above popup // We first store the selected text in case TerminalViewClient needs the
// selected text before MORE button was pressed since we are going to
// stop selection mode
mStoredSelectedText = getSelectedText();
// The text selection needs to be stopped before showing context menu,
// otherwise handles will show above popup
terminalView.stopTextSelectionMode();
terminalView.showContextMenu(); terminalView.showContextMenu();
break; break;
} }
@@ -361,6 +370,22 @@ public class TextSelectionCursorController implements CursorController {
sel[3] = mSelX2; sel[3] = mSelX2;
} }
/** Get the currently selected text. */
public String getSelectedText() {
return terminalView.mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2);
}
/** Get the selected text stored before "MORE" button was pressed on the context menu. */
@Nullable
public String getStoredSelectedText() {
return mStoredSelectedText;
}
/** Unset the selected text stored before "MORE" button was pressed on the context menu. */
public void unsetStoredSelectedText() {
mStoredSelectedText = null;
}
public ActionMode getActionMode() { public ActionMode getActionMode() {
return mActionMode; return mActionMode;
} }

View File

@@ -156,6 +156,7 @@ public class ShareUtils {
/**
* Open a url. * Open a url.
* *
* @param context The context for operations. * @param context The context for operations.