feat: MyTermuxActivity 重构为 TermuxButton 列表管理界面
- models/TermuxButtonManager: 新增数据管理层,支持 CRUD 及 JSON 文件持久化 - MyTermuxActivity: 替换硬编码按钮为 ListView,支持点击执行、长按编辑/删除 - layout/activity_my_termux: 布局重构,替换 ScrollView 为 ListView + 添加按钮 - strings.xml: 新增 17 条中文字符串资源
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Wed May 13 10:28:36 HKT 2026
|
||||
#Wed May 13 11:15:04 CST 2026
|
||||
stageCount=2
|
||||
libraryProject=libwinboll
|
||||
baseVersion=15.20
|
||||
publishVersion=15.20.1
|
||||
buildCount=0
|
||||
buildCount=1
|
||||
baseBetaVersion=15.20.2
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Wed May 13 10:28:36 HKT 2026
|
||||
#Wed May 13 11:15:04 CST 2026
|
||||
stageCount=2
|
||||
libraryProject=libwinboll
|
||||
baseVersion=15.20
|
||||
publishVersion=15.20.1
|
||||
buildCount=0
|
||||
buildCount=1
|
||||
baseBetaVersion=15.20.2
|
||||
|
||||
@@ -1,31 +1,46 @@
|
||||
package cc.winboll.studio.winboll.applications;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.winboll.R;
|
||||
import cc.winboll.studio.winboll.models.TermuxButtonManager;
|
||||
import cc.winboll.studio.winboll.models.TermuxButtonModel;
|
||||
import cc.winboll.studio.winboll.termux.TermuxCommandExecutor;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MyTermuxActivity extends AppCompatActivity {
|
||||
|
||||
public static final String TAG = "MyTermuxActivity";
|
||||
|
||||
private Toolbar mToolbar;
|
||||
private Button mTermuxButton;
|
||||
private Button mTermuxWorkSpacesButton;
|
||||
private ListView mListView;
|
||||
private Button mBtnAdd;
|
||||
private ButtonAdapter mAdapter;
|
||||
private ArrayList<TermuxButtonModel> mButtonList;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_my_termux);
|
||||
|
||||
// 初始化工具栏
|
||||
initToolbar();
|
||||
// 初始化按钮
|
||||
initView();
|
||||
initListView();
|
||||
initAddButton();
|
||||
refreshList();
|
||||
}
|
||||
|
||||
private void initToolbar() {
|
||||
@@ -34,44 +49,189 @@ public class MyTermuxActivity extends AppCompatActivity {
|
||||
setSupportActionBar(mToolbar);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "点击返回按钮");
|
||||
finish();
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "工具栏初始化完成");
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mTermuxButton = findViewById(R.id.btn_termux);
|
||||
if (mTermuxButton != null) {
|
||||
mTermuxButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "点击 Termux 按钮");
|
||||
TermuxCommandExecutor.openTermuxBash(MyTermuxActivity.this, "cd ~");
|
||||
//TermuxCommandExecutor.openTermuxBash(MyTermuxActivity.this, "cd ~/TermuxWorkSpaces", "./TermuxWorkSpaces");
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "Termux 按钮初始化完成");
|
||||
}
|
||||
private void initListView() {
|
||||
mListView = findViewById(R.id.list_termux_buttons);
|
||||
mButtonList = new ArrayList<TermuxButtonModel>();
|
||||
mAdapter = new ButtonAdapter();
|
||||
mListView.setAdapter(mAdapter);
|
||||
|
||||
mTermuxWorkSpacesButton = findViewById(R.id.btn_termuxworkspaces);
|
||||
if (mTermuxWorkSpacesButton != null) {
|
||||
mTermuxWorkSpacesButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "点击 TermuxWorkSpaces 按钮");
|
||||
TermuxCommandExecutor.openTermuxBash(MyTermuxActivity.this, "cd ~/TermuxWorkSpaces", "./TermuxWorkSpaces");
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "TermuxWorkSpaces 按钮初始化完成");
|
||||
}
|
||||
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
TermuxButtonModel model = mButtonList.get(position);
|
||||
TermuxCommandExecutor.openTermuxBash(MyTermuxActivity.this,
|
||||
model.getExeCommand(), model.getWorkDir());
|
||||
}
|
||||
});
|
||||
|
||||
mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
showContextMenu(position);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isTermuxAvailable() {
|
||||
return TermuxCommandExecutor.isTermuxInstalled(this);
|
||||
private void initAddButton() {
|
||||
mBtnAdd = findViewById(R.id.btn_add_termux_button);
|
||||
mBtnAdd.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showButtonDialog(-1, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void refreshList() {
|
||||
mButtonList.clear();
|
||||
ArrayList<TermuxButtonModel> loaded = TermuxButtonManager.loadButtons(this);
|
||||
if (loaded != null) {
|
||||
mButtonList.addAll(loaded);
|
||||
}
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void showContextMenu(final int position) {
|
||||
final TermuxButtonModel model = mButtonList.get(position);
|
||||
String[] items = new String[]{
|
||||
getString(R.string.menu_execute),
|
||||
getString(R.string.menu_edit),
|
||||
getString(R.string.menu_delete),
|
||||
getString(R.string.menu_cancel)
|
||||
};
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(model.getButtonName())
|
||||
.setItems(items, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == 0) {
|
||||
TermuxCommandExecutor.openTermuxBash(MyTermuxActivity.this,
|
||||
model.getExeCommand(), model.getWorkDir());
|
||||
} else if (which == 1) {
|
||||
showButtonDialog(position, model);
|
||||
} else if (which == 2) {
|
||||
showDeleteConfirmDialog(position);
|
||||
}
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showDeleteConfirmDialog(final int position) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.dialog_delete_title))
|
||||
.setMessage(getString(R.string.dialog_delete_message) + mButtonList.get(position).getButtonName())
|
||||
.setPositiveButton(getString(R.string.dialog_confirm), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
TermuxButtonManager.deleteButton(MyTermuxActivity.this, mButtonList, position);
|
||||
refreshList();
|
||||
Toast.makeText(MyTermuxActivity.this, R.string.toast_deleted, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(getString(R.string.dialog_cancel), null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showButtonDialog(final int index, final TermuxButtonModel model) {
|
||||
final boolean isEdit = (model != null);
|
||||
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
layout.setPadding(40, 20, 40, 20);
|
||||
|
||||
final EditText etName = new EditText(this);
|
||||
etName.setHint(R.string.hint_button_name);
|
||||
if (model != null) {
|
||||
etName.setText(model.getButtonName());
|
||||
}
|
||||
layout.addView(etName);
|
||||
|
||||
final EditText etCommand = new EditText(this);
|
||||
etCommand.setHint(R.string.hint_exe_command);
|
||||
if (model != null) {
|
||||
etCommand.setText(model.getExeCommand());
|
||||
}
|
||||
layout.addView(etCommand);
|
||||
|
||||
final EditText etWorkDir = new EditText(this);
|
||||
etWorkDir.setHint(R.string.hint_work_dir);
|
||||
if (model != null) {
|
||||
etWorkDir.setText(model.getWorkDir());
|
||||
}
|
||||
layout.addView(etWorkDir);
|
||||
|
||||
int titleResId = isEdit ? R.string.dialog_edit_title : R.string.dialog_add_title;
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(titleResId)
|
||||
.setView(layout)
|
||||
.setPositiveButton(getString(R.string.dialog_save), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String name = etName.getText().toString().trim();
|
||||
String command = etCommand.getText().toString().trim();
|
||||
String workDir = etWorkDir.getText().toString().trim();
|
||||
if (name.isEmpty() || command.isEmpty()) {
|
||||
Toast.makeText(MyTermuxActivity.this, R.string.toast_fields_required, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
TermuxButtonModel newModel = new TermuxButtonModel();
|
||||
newModel.setButtonName(name);
|
||||
newModel.setExeCommand(command);
|
||||
newModel.setWorkDir(workDir);
|
||||
if (isEdit) {
|
||||
TermuxButtonManager.updateButton(MyTermuxActivity.this, mButtonList, index, newModel);
|
||||
} else {
|
||||
TermuxButtonManager.addButton(MyTermuxActivity.this, mButtonList, newModel);
|
||||
}
|
||||
refreshList();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(getString(R.string.dialog_cancel), null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private class ButtonAdapter extends BaseAdapter {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mButtonList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mButtonList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
TextView tv;
|
||||
if (convertView == null) {
|
||||
tv = new TextView(MyTermuxActivity.this);
|
||||
tv.setPadding(30, 20, 30, 20);
|
||||
tv.setTextSize(16);
|
||||
tv.setMinHeight(80);
|
||||
} else {
|
||||
tv = (TextView) convertView;
|
||||
}
|
||||
|
||||
TermuxButtonModel model = mButtonList.get(position);
|
||||
tv.setText(model.getButtonName() + "\n" + model.getExeCommand());
|
||||
tv.setTextColor(getResources().getColor(android.R.color.white));
|
||||
return tv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package cc.winboll.studio.winboll.models;
|
||||
|
||||
import android.content.Context;
|
||||
import cc.winboll.studio.libappbase.BaseBean;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class TermuxButtonManager {
|
||||
|
||||
public static ArrayList<TermuxButtonModel> loadButtons(Context context) {
|
||||
ArrayList<TermuxButtonModel> list = new ArrayList<TermuxButtonModel>();
|
||||
BaseBean.loadBeanList(context, list, TermuxButtonModel.class);
|
||||
return list;
|
||||
}
|
||||
|
||||
public static boolean saveButtons(Context context, ArrayList<TermuxButtonModel> list) {
|
||||
return BaseBean.saveBeanList(context, list, TermuxButtonModel.class);
|
||||
}
|
||||
|
||||
public static void addButton(Context context, ArrayList<TermuxButtonModel> list, TermuxButtonModel button) {
|
||||
list.add(button);
|
||||
saveButtons(context, list);
|
||||
}
|
||||
|
||||
public static void updateButton(Context context, ArrayList<TermuxButtonModel> list, int index, TermuxButtonModel button) {
|
||||
if (index >= 0 && index < list.size()) {
|
||||
list.set(index, button);
|
||||
saveButtons(context, list);
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteButton(Context context, ArrayList<TermuxButtonModel> list, int index) {
|
||||
if (index >= 0 && index < list.size()) {
|
||||
list.remove(index);
|
||||
saveButtons(context, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
@@ -17,74 +16,20 @@
|
||||
app:titleTextColor="@android:color/white"
|
||||
app:subtitleTextColor="@android:color/white"/>
|
||||
|
||||
<ScrollView
|
||||
<ListView
|
||||
android:id="@+id/list_termux_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0">
|
||||
android:layout_weight="1.0"
|
||||
android:divider="@android:color/darker_gray"
|
||||
android:dividerHeight="1dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<cc.winboll.studio.winboll.views.TermuxButton
|
||||
android:id="@+id/btn_termux"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Termux"
|
||||
android:textSize="18sp"
|
||||
android:padding="16dp"
|
||||
android:backgroundTint="@android:color/holo_blue_dark"
|
||||
app:exeCommand="cd ~"
|
||||
app:workDir="~"
|
||||
app:isCommitted="true"
|
||||
app:commitTitle="打开 Termux"
|
||||
app:commitInfo="打开 Termux 应用"/>
|
||||
|
||||
<cc.winboll.studio.winboll.views.TermuxButton
|
||||
android:id="@+id/btn_termuxworkspaces"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TermuxWorkSpaces"
|
||||
android:textSize="18sp"
|
||||
android:padding="16dp"
|
||||
android:backgroundTint="@android:color/holo_blue_dark"
|
||||
app:exeCommand="cd ~/TermuxWorkSpaces"
|
||||
app:workDir="~"
|
||||
app:isCommitted="false"
|
||||
app:commitTitle="打开 TermuxWorkSpaces"
|
||||
app:commitInfo="打开 Termux 应用,进入 TermuxWorkSpaces 目录。"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="+"
|
||||
android:id="@+id/btn_addtermuxbutton"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
<Button
|
||||
android:id="@+id/btn_add_termux_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/add_termux_button"
|
||||
android:textSize="16sp"
|
||||
android:padding="12dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -13,4 +13,21 @@
|
||||
<string name="toolbar_icon_description">WinBoLL APP</string>
|
||||
<string name="my_termux_activity">MyTermuxActivity</string>
|
||||
<string name="pattern_lock_title">图案密码设置</string>
|
||||
<string name="add_termux_button">+ 添加Termux按钮</string>
|
||||
<string name="menu_execute">执行</string>
|
||||
<string name="menu_edit">编辑</string>
|
||||
<string name="menu_delete">删除</string>
|
||||
<string name="menu_cancel">取消</string>
|
||||
<string name="dialog_delete_title">确认删除</string>
|
||||
<string name="dialog_delete_message">确定要删除</string>
|
||||
<string name="dialog_add_title">添加Termux按钮</string>
|
||||
<string name="dialog_edit_title">编辑Termux按钮</string>
|
||||
<string name="dialog_save">保存</string>
|
||||
<string name="dialog_confirm">确定</string>
|
||||
<string name="dialog_cancel">取消</string>
|
||||
<string name="hint_button_name">按钮名称</string>
|
||||
<string name="hint_exe_command">执行命令</string>
|
||||
<string name="hint_work_dir">工作目录(默认 ~)</string>
|
||||
<string name="toast_deleted">已删除</string>
|
||||
<string name="toast_fields_required">按钮名称和执行命令不能为空</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user