From bbb0e2219887b6b695be2a7aa80db6f4911dacc5 Mon Sep 17 00:00:00 2001 From: LaizyBoy Date: Wed, 13 May 2026 11:28:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20MyTermuxActivity=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=B8=BA=20TermuxButton=20=E5=88=97=E8=A1=A8=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - models/TermuxButtonManager: 新增数据管理层,支持 CRUD 及 JSON 文件持久化 - MyTermuxActivity: 替换硬编码按钮为 ListView,支持点击执行、长按编辑/删除 - layout/activity_my_termux: 布局重构,替换 ScrollView 为 ListView + 添加按钮 - strings.xml: 新增 17 条中文字符串资源 --- libwinboll/build.properties | 4 +- winboll/build.properties | 4 +- .../applications/MyTermuxActivity.java | 236 +++++++++++++++--- .../winboll/models/TermuxButtonManager.java | 37 +++ .../main/res/layout/activity_my_termux.xml | 81 +----- winboll/src/main/res/values/strings.xml | 17 ++ 6 files changed, 269 insertions(+), 110 deletions(-) create mode 100644 winboll/src/main/java/cc/winboll/studio/winboll/models/TermuxButtonManager.java diff --git a/libwinboll/build.properties b/libwinboll/build.properties index e3303fd..ae97a49 100644 --- a/libwinboll/build.properties +++ b/libwinboll/build.properties @@ -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 diff --git a/winboll/build.properties b/winboll/build.properties index e3303fd..ae97a49 100644 --- a/winboll/build.properties +++ b/winboll/build.properties @@ -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 diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/applications/MyTermuxActivity.java b/winboll/src/main/java/cc/winboll/studio/winboll/applications/MyTermuxActivity.java index 5e7bddd..6bd2b29 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/applications/MyTermuxActivity.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/applications/MyTermuxActivity.java @@ -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 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(); + 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 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; + } } } diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/models/TermuxButtonManager.java b/winboll/src/main/java/cc/winboll/studio/winboll/models/TermuxButtonManager.java new file mode 100644 index 0000000..456a2a2 --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/models/TermuxButtonManager.java @@ -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 loadButtons(Context context) { + ArrayList list = new ArrayList(); + BaseBean.loadBeanList(context, list, TermuxButtonModel.class); + return list; + } + + public static boolean saveButtons(Context context, ArrayList list) { + return BaseBean.saveBeanList(context, list, TermuxButtonModel.class); + } + + public static void addButton(Context context, ArrayList list, TermuxButtonModel button) { + list.add(button); + saveButtons(context, list); + } + + public static void updateButton(Context context, ArrayList 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 list, int index) { + if (index >= 0 && index < list.size()) { + list.remove(index); + saveButtons(context, list); + } + } +} diff --git a/winboll/src/main/res/layout/activity_my_termux.xml b/winboll/src/main/res/layout/activity_my_termux.xml index 4334b51..f7417f5 100644 --- a/winboll/src/main/res/layout/activity_my_termux.xml +++ b/winboll/src/main/res/layout/activity_my_termux.xml @@ -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"> - + android:layout_weight="1.0" + android:divider="@android:color/darker_gray" + android:dividerHeight="1dp"/> - - - - - - - - - - - - - - - - -