mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-05 18:25:31 +08:00
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:
@@ -38,6 +38,7 @@ import com.termux.shared.activity.ActivityUtils;
|
||||
import com.termux.shared.activity.media.AppCompatActivityUtils;
|
||||
import com.termux.shared.data.IntentUtils;
|
||||
import com.termux.shared.android.PermissionUtils;
|
||||
import com.termux.shared.data.DataUtils;
|
||||
import com.termux.shared.termux.TermuxConstants;
|
||||
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
|
||||
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_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_RESET_TERMINAL_ID = 3;
|
||||
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_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_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);
|
||||
@@ -668,6 +673,9 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
|
||||
case CONTEXT_MENU_SHARE_TRANSCRIPT_ID:
|
||||
mTermuxTerminalViewClient.shareSessionTranscript();
|
||||
return true;
|
||||
case CONTEXT_MENU_SHARE_SELECTED_TEXT:
|
||||
mTermuxTerminalViewClient.shareSelectedText();
|
||||
return true;
|
||||
case CONTEXT_MENU_AUTOFILL_ID:
|
||||
requestAutoFill();
|
||||
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) {
|
||||
if (session == null) return;
|
||||
|
||||
|
@@ -17,6 +17,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
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.interact.TextInputDialogUtils;
|
||||
import com.termux.app.TermuxActivity;
|
||||
|
@@ -684,6 +684,13 @@ public class TermuxTerminalViewClient extends TermuxTerminalViewClientBase {
|
||||
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() {
|
||||
TerminalSession session = mActivity.getCurrentSession();
|
||||
if (session == null) return;
|
||||
|
@@ -69,6 +69,10 @@
|
||||
<string name="title_share_transcript">Terminal transcript</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_reset_terminal">Reset</string>
|
||||
|
@@ -2,6 +2,7 @@ package com.termux.view;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
@@ -19,6 +20,7 @@ import android.view.HapticFeedbackConstants;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyCharacterMap;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
@@ -30,6 +32,7 @@ import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.widget.Scroller;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.termux.terminal.KeyHandler;
|
||||
@@ -456,6 +459,14 @@ public final class TerminalView extends View {
|
||||
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.
|
||||
*
|
||||
@@ -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() {
|
||||
if (mTextSelectionCursorController != null) {
|
||||
return mTextSelectionCursorController.getActionMode();
|
||||
|
@@ -11,6 +11,8 @@ import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.termux.terminal.TerminalBuffer;
|
||||
import com.termux.terminal.WcWidth;
|
||||
import com.termux.view.R;
|
||||
@@ -20,6 +22,7 @@ public class TextSelectionCursorController implements CursorController {
|
||||
|
||||
private final TerminalView terminalView;
|
||||
private final TextSelectionHandleView mStartHandle, mEndHandle;
|
||||
private String mStoredSelectedText;
|
||||
private boolean mIsSelectingText = false;
|
||||
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 ActionMode mActionMode;
|
||||
private final int ACTION_COPY = 1;
|
||||
private final int ACTION_PASTE = 2;
|
||||
private final int ACTION_MORE = 3;
|
||||
public final int ACTION_COPY = 1;
|
||||
public final int ACTION_PASTE = 2;
|
||||
public final int ACTION_MORE = 3;
|
||||
|
||||
public TextSelectionCursorController(TerminalView terminalView) {
|
||||
this.terminalView = terminalView;
|
||||
@@ -112,7 +115,7 @@ public class TextSelectionCursorController implements CursorController {
|
||||
|
||||
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_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);
|
||||
return true;
|
||||
}
|
||||
@@ -131,7 +134,7 @@ public class TextSelectionCursorController implements CursorController {
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case ACTION_COPY:
|
||||
String selectedText = terminalView.mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2).trim();
|
||||
String selectedText = getSelectedText();
|
||||
terminalView.mTermSession.onCopyTextToClipboard(selectedText);
|
||||
terminalView.stopTextSelectionMode();
|
||||
break;
|
||||
@@ -140,7 +143,13 @@ public class TextSelectionCursorController implements CursorController {
|
||||
terminalView.mTermSession.onPasteTextFromClipboard();
|
||||
break;
|
||||
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();
|
||||
break;
|
||||
}
|
||||
@@ -361,6 +370,22 @@ public class TextSelectionCursorController implements CursorController {
|
||||
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() {
|
||||
return mActionMode;
|
||||
}
|
||||
|
@@ -156,6 +156,7 @@ public class ShareUtils {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Open a url.
|
||||
*
|
||||
* @param context The context for operations.
|
||||
|
Reference in New Issue
Block a user