这是indexloc提供的服务,不要输入任何密码
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions app/src/main/java/com/termux/app/TermuxActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,11 @@ private void setTerminalToolbarView(Bundle savedInstanceState) {
if (savedInstanceState != null)
savedTextInput = savedInstanceState.getString(ARG_TERMINAL_TOOLBAR_TEXT_INPUT);

terminalToolbarViewPager.setAdapter(new TerminalToolbarViewPager.PageAdapter(this, savedTextInput));
terminalToolbarViewPager.addOnPageChangeListener(new TerminalToolbarViewPager.OnPageChangeListener(this, terminalToolbarViewPager));
TerminalToolbarViewPager.PageAdapter pageAdapter = new TerminalToolbarViewPager.PageAdapter(this, savedTextInput);
TerminalToolbarViewPager.OnPageChangeListener pageChangeListener = new TerminalToolbarViewPager.OnPageChangeListener(this, terminalToolbarViewPager);
pageChangeListener.setPageAdapter(pageAdapter);
terminalToolbarViewPager.setAdapter(pageAdapter);
terminalToolbarViewPager.addOnPageChangeListener(pageChangeListener);
}

private void setTerminalToolbarHeight() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.termux.app.terminal.io;

import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
Expand All @@ -20,10 +22,12 @@ public static class PageAdapter extends PagerAdapter {

final TermuxActivity mActivity;
String mSavedTextInput;
private final TextInputHistory mTextInputHistory;

public PageAdapter(TermuxActivity activity, String savedTextInput) {
this.mActivity = activity;
this.mSavedTextInput = savedTextInput;
this.mTextInputHistory = new TextInputHistory();
}

@Override
Expand Down Expand Up @@ -64,17 +68,27 @@ public Object instantiateItem(@NonNull ViewGroup collection, int position) {
mSavedTextInput = null;
}

// Set up gesture detection for up/down swipes
setupTextInputGestureDetection(editText);

editText.setOnEditorActionListener((v, actionId, event) -> {
TerminalSession session = mActivity.getCurrentSession();
if (session != null) {
if (session.isRunning()) {
String textToSend = editText.getText().toString();
if (textToSend.length() == 0) textToSend = "\r";

// Add to history before sending (ignore empty entries and carriage returns)
if (!textToSend.equals("\r") && !textToSend.trim().isEmpty()) {
mTextInputHistory.addEntry(textToSend);
}

session.write(textToSend);
} else {
mActivity.getTermuxTerminalSessionClient().removeFinishedSession(session);
}
editText.setText("");
mTextInputHistory.resetNavigation(); // Reset navigation after submission
}
return true;
});
Expand All @@ -88,6 +102,81 @@ public void destroyItem(@NonNull ViewGroup collection, int position, @NonNull Ob
collection.removeView((View) view);
}

/**
* Sets up gesture detection for the text input EditText to handle up/down swipes
* for history navigation while preserving horizontal swipes for ViewPager.
*/
private void setupTextInputGestureDetection(EditText editText) {
GestureDetector gestureDetector = new GestureDetector(mActivity,
new GestureDetector.SimpleOnGestureListener() {

private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (e1 == null || e2 == null) return false;

float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();

// Only handle vertical swipes (up/down)
if (Math.abs(diffY) > Math.abs(diffX) &&
Math.abs(diffY) > SWIPE_THRESHOLD &&
Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {

if (diffY > 0) {
// Swipe down - navigate to newer entries
navigateHistoryDown(editText);
} else {
// Swipe up - navigate to older entries
navigateHistoryUp(editText);
}
return true;
}
return false;
}
});

editText.setOnTouchListener((v, event) -> {
// Let the GestureDetector handle the event first
boolean handled = gestureDetector.onTouchEvent(event);

// If it wasn't a vertical swipe gesture, let the normal touch handling proceed
// This preserves the EditText's normal text selection and cursor positioning
if (!handled) {
v.performClick();
return false; // Let the EditText handle the touch normally
}
return true; // We handled the gesture
});
}

/**
* Navigates up in history (to older entries) and updates the EditText.
*/
private void navigateHistoryUp(EditText editText) {
String currentText = editText.getText().toString();
String historyEntry = mTextInputHistory.navigateUp(currentText);

if (historyEntry != null) {
editText.setText(historyEntry);
editText.setSelection(historyEntry.length()); // Move cursor to end
}
}

/**
* Navigates down in history (to newer entries) and updates the EditText.
*/
private void navigateHistoryDown(EditText editText) {
String historyEntry = mTextInputHistory.navigateDown();

if (historyEntry != null) {
editText.setText(historyEntry);
editText.setSelection(historyEntry.length()); // Move cursor to end
}
}

}


Expand All @@ -96,15 +185,27 @@ public static class OnPageChangeListener extends ViewPager.SimpleOnPageChangeLis

final TermuxActivity mActivity;
final ViewPager mTerminalToolbarViewPager;
private PageAdapter mPageAdapter;

public OnPageChangeListener(TermuxActivity activity, ViewPager viewPager) {
this.mActivity = activity;
this.mTerminalToolbarViewPager = viewPager;
}

/**
* Sets the PageAdapter reference so we can access the text input history.
*/
public void setPageAdapter(PageAdapter pageAdapter) {
this.mPageAdapter = pageAdapter;
}

@Override
public void onPageSelected(int position) {
if (position == 0) {
// Switching away from text input - reset navigation
if (mPageAdapter != null) {
mPageAdapter.mTextInputHistory.resetNavigation();
}
mActivity.getTerminalView().requestFocus();
} else {
final EditText editText = mTerminalToolbarViewPager.findViewById(R.id.terminal_toolbar_text_input);
Expand Down
179 changes: 179 additions & 0 deletions app/src/main/java/com/termux/app/terminal/io/TextInputHistory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package com.termux.app.terminal.io;

import java.util.ArrayList;

/**
* Manages command history for the terminal toolbar text input view.
* Provides functionality similar to bash command history with up/down navigation.
*/
public class TextInputHistory {

private static final int DEFAULT_MAX_HISTORY_SIZE = 20;

private final ArrayList<String> history;
private final int maxHistorySize;
private int currentIndex; // -1 means not navigating history, 0+ means navigating
private String currentEdit; // Stores user's current input when navigating history

/**
* Creates a new TextInputHistory with default maximum size.
*/
public TextInputHistory() {
this(DEFAULT_MAX_HISTORY_SIZE);
}

/**
* Creates a new TextInputHistory with specified maximum size.
* @param maxHistorySize Maximum number of history entries to store
*/
public TextInputHistory(int maxHistorySize) {
this.maxHistorySize = Math.max(1, maxHistorySize);
this.history = new ArrayList<>(this.maxHistorySize);
this.currentIndex = -1;
this.currentEdit = "";
}

/**
* Adds a new entry to the history.
* Duplicate consecutive entries are not added.
* @param text The text to add to history (empty/null entries are ignored)
*/
public void addEntry(String text) {
if (text == null || text.trim().isEmpty()) {
return;
}

// Don't add if it's the same as the last entry
if (!history.isEmpty() && history.get(history.size() - 1).equals(text)) {
return;
}

// Add to end of history
history.add(text);

// Remove oldest entries if we exceed max size
if (history.size() > maxHistorySize) {
history.remove(0);
}

// Reset navigation state
resetNavigation();
}

/**
* Navigates up in history (to older entries).
* @param currentText The current text in the input field
* @return The previous history entry, or null if at the beginning
*/
public String navigateUp(String currentText) {
if (history.isEmpty()) {
return null;
}

// If not currently navigating, store current text and start from the end
if (currentIndex == -1) {
currentEdit = currentText != null ? currentText : "";
currentIndex = history.size();
}

// Move up (to older entries)
if (currentIndex > 0) {
currentIndex--;
return history.get(currentIndex);
}

// Already at the oldest entry
return history.get(currentIndex);
}

/**
* Navigates down in history (to newer entries).
* @return The next history entry, current edit, or null if at the end
*/
public String navigateDown() {
if (currentIndex == -1 || history.isEmpty()) {
return null;
}

// Move down (to newer entries)
currentIndex++;

// If we've gone past the newest entry, return to current edit
if (currentIndex >= history.size()) {
String result = currentEdit;
resetNavigation();
return result;
}

return history.get(currentIndex);
}

/**
* Resets the navigation state to normal input mode.
*/
public void resetNavigation() {
currentIndex = -1;
currentEdit = "";
}

/**
* Checks if currently navigating through history.
* @return true if in navigation mode, false if in normal input mode
*/
public boolean isNavigating() {
return currentIndex != -1;
}

/**
* Gets the current history size.
* @return Number of entries in history
*/
public int size() {
return history.size();
}

/**
* Checks if history is empty.
* @return true if no history entries exist
*/
public boolean isEmpty() {
return history.isEmpty();
}

/**
* Clears all history entries.
*/
public void clear() {
history.clear();
resetNavigation();
}

/**
* Gets a copy of the current history for persistence or debugging.
* @return A new ArrayList containing all history entries
*/
public ArrayList<String> getHistoryCopy() {
return new ArrayList<>(history);
}

/**
* Restores history from a list (for persistence).
* @param historyEntries List of history entries to restore
*/
public void restoreHistory(ArrayList<String> historyEntries) {
if (historyEntries == null) {
return;
}

clear();

// Add entries while respecting max size
int startIndex = Math.max(0, historyEntries.size() - maxHistorySize);
for (int i = startIndex; i < historyEntries.size(); i++) {
String entry = historyEntries.get(i);
if (entry != null && !entry.trim().isEmpty()) {
history.add(entry);
}
}
}
}
Loading