feat: add collapsible button editor sections

This commit is contained in:
7015725
2026-05-12 20:17:11 +08:00
parent 46393fe9ba
commit 53967f77d2
3 changed files with 77 additions and 15 deletions

View File

@@ -560,6 +560,68 @@ FloatBallAppWM.prototype.createButtonEditorSectionCard = function(parent, title,
return box; return box;
}; };
FloatBallAppWM.prototype.createButtonEditorCollapsibleSection = function(parent, title, desc, defaultExpanded) {
var self = this;
var isDark = this.isDarkTheme();
var C = this.ui.colors;
var expanded = defaultExpanded !== false;
var card = new android.widget.LinearLayout(context);
card.setOrientation(android.widget.LinearLayout.VERTICAL);
card.setPadding(this.dp(12), this.dp(10), this.dp(12), this.dp(10));
card.setBackground(this.ui.createRoundDrawable(isDark ? this.withAlpha(C.cardDark, 0.72) : this.withAlpha(C.cardLight, 0.78), this.dp(14)));
var header = new android.widget.LinearLayout(context);
header.setOrientation(android.widget.LinearLayout.HORIZONTAL);
header.setGravity(android.view.Gravity.CENTER_VERTICAL);
var titleBox = new android.widget.LinearLayout(context);
titleBox.setOrientation(android.widget.LinearLayout.VERTICAL);
var tv = new android.widget.TextView(context);
tv.setText(String(title || ""));
tv.setTextColor(isDark ? C.textPriDark : C.textPriLight);
tv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 14);
tv.setTypeface(null, android.graphics.Typeface.BOLD);
titleBox.addView(tv);
if (desc) {
var dv = new android.widget.TextView(context);
dv.setText(String(desc));
dv.setTextColor(isDark ? C.textSecDark : C.textSecLight);
dv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 11);
dv.setPadding(0, this.dp(3), this.dp(8), 0);
titleBox.addView(dv);
}
var titleLp = new android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT);
titleLp.weight = 1;
header.addView(titleBox, titleLp);
var toggleTv = new android.widget.TextView(context);
toggleTv.setText(expanded ? "折叠 ▲" : "展开 ▼");
toggleTv.setTextColor(C.primary);
toggleTv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 12);
toggleTv.setTypeface(null, android.graphics.Typeface.BOLD);
header.addView(toggleTv);
card.addView(header);
var body = new android.widget.LinearLayout(context);
body.setOrientation(android.widget.LinearLayout.VERTICAL);
body.setPadding(0, this.dp(8), 0, 0);
if (!expanded) body.setVisibility(android.view.View.GONE);
card.addView(body);
header.setOnClickListener(new android.view.View.OnClickListener({ onClick: function(v) {
try {
expanded = !expanded;
body.setVisibility(expanded ? android.view.View.VISIBLE : android.view.View.GONE);
toggleTv.setText(expanded ? "折叠 ▲" : "展开 ▼");
self.touchActivity();
} catch(eToggle) { safeLog(null, 'e', "catch " + String(eToggle)); }
}}));
var lp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(0, this.dp(8), 0, this.dp(8));
parent.addView(card, lp);
return body;
};
FloatBallAppWM.prototype.buildButtonEditorPanelView = function() { FloatBallAppWM.prototype.buildButtonEditorPanelView = function() {
var self = this; var self = this;
// # 状态管理editingIndex (null=列表, -1=新增, >=0=编辑) // # 状态管理editingIndex (null=列表, -1=新增, >=0=编辑)
@@ -1014,7 +1076,7 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() {
editHint.setPadding(self.dp(4), 0, 0, self.dp(16)); editHint.setPadding(self.dp(4), 0, 0, self.dp(16));
form.addView(editHint); form.addView(editHint);
self.createButtonEditorSectionCard(form, "基础信息", "按钮名称与基础标识"); var basicSectionBody = self.createButtonEditorCollapsibleSection(form, "基础信息", "按钮名称与基础标识", true);
// 1. 标题 (Title) // 1. 标题 (Title)
var topArea = new android.widget.LinearLayout(context); var topArea = new android.widget.LinearLayout(context);
@@ -1033,9 +1095,9 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() {
titleArea.addView(inputTitle.view); titleArea.addView(inputTitle.view);
topArea.addView(titleArea); topArea.addView(titleArea);
form.addView(topArea); basicSectionBody.addView(topArea);
self.createButtonEditorSectionCard(form, "图标外观", "选择图标来源、ShortX 图标和颜色"); var iconSectionBody = self.createButtonEditorCollapsibleSection(form, "图标外观", "选择图标来源、ShortX 图标和颜色", false);
// 1.5 图标选择(文件路径 或 ShortX 内置图标 二选一) // 1.5 图标选择(文件路径 或 ShortX 内置图标 二选一)
var iconSelectWrap = new android.widget.LinearLayout(context); var iconSelectWrap = new android.widget.LinearLayout(context);
@@ -1065,11 +1127,11 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() {
iconRadioGroup.addView(rbIconFile); iconRadioGroup.addView(rbIconFile);
iconRadioGroup.addView(rbIconShortX); iconRadioGroup.addView(rbIconShortX);
iconSelectWrap.addView(iconRadioGroup); iconSelectWrap.addView(iconRadioGroup);
form.addView(iconSelectWrap); iconSectionBody.addView(iconSelectWrap);
// 1.5a 图标路径(文件方式) // 1.5a 图标路径(文件方式)
var inputIconPath = self.ui.createInputGroup(self, "图标路径 (绝对地址)", targetBtn.iconPath, false, "支持 PNG/JPG 绝对路径,自动安全加载"); var inputIconPath = self.ui.createInputGroup(self, "图标路径 (绝对地址)", targetBtn.iconPath, false, "支持 PNG/JPG 绝对路径,自动安全加载");
form.addView(inputIconPath.view); iconSectionBody.addView(inputIconPath.view);
// 1.5b ShortX 内置图标选择(取消手动名称输入,改为预览 + 图标库选择) // 1.5b ShortX 内置图标选择(取消手动名称输入,改为预览 + 图标库选择)
var normalizedInitShortX = self.normalizeShortXIconName(targetBtn.iconResName, false); var normalizedInitShortX = self.normalizeShortXIconName(targetBtn.iconResName, false);
@@ -1249,7 +1311,7 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() {
shortxQuickRow.setOrientation(android.widget.LinearLayout.HORIZONTAL); shortxQuickRow.setOrientation(android.widget.LinearLayout.HORIZONTAL);
shortxQuickRow.setGravity(android.view.Gravity.CENTER_VERTICAL); shortxQuickRow.setGravity(android.view.Gravity.CENTER_VERTICAL);
shortxQuickRow.setPadding(0, 0, 0, self.dp(8)); shortxQuickRow.setPadding(0, 0, 0, self.dp(8));
form.addView(shortxQuickRow); iconSectionBody.addView(shortxQuickRow);
var shortxPreviewCard = new android.widget.LinearLayout(context); var shortxPreviewCard = new android.widget.LinearLayout(context);
shortxPreviewCard.setOrientation(android.widget.LinearLayout.HORIZONTAL); shortxPreviewCard.setOrientation(android.widget.LinearLayout.HORIZONTAL);
@@ -1564,7 +1626,7 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() {
var defaultTint = targetBtn.iconTint ? String(targetBtn.iconTint) : ""; var defaultTint = targetBtn.iconTint ? String(targetBtn.iconTint) : "";
var currentShortXIconTint = defaultTint; var currentShortXIconTint = defaultTint;
var inputShortXIconTint = self.ui.createInputGroup(self, "图标颜色 (留空跟随主题)", defaultTint, false, "支持 #RRGGBB / #AARRGGBB下方可展开完整调色板"); var inputShortXIconTint = self.ui.createInputGroup(self, "图标颜色 (留空跟随主题)", defaultTint, false, "支持 #RRGGBB / #AARRGGBB下方可展开完整调色板");
form.addView(inputShortXIconTint.view); iconSectionBody.addView(inputShortXIconTint.view);
// # 避免 Rhino 闭包问题:将输入框引用存储到 self.state供颜色选择器回调使用 // # 避免 Rhino 闭包问题:将输入框引用存储到 self.state供颜色选择器回调使用
self.state._btnEditorTintInput = inputShortXIconTint; self.state._btnEditorTintInput = inputShortXIconTint;
@@ -1828,7 +1890,7 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() {
tintPaletteWrap.setOrientation(android.widget.LinearLayout.VERTICAL); tintPaletteWrap.setOrientation(android.widget.LinearLayout.VERTICAL);
tintPaletteWrap.setPadding(0, 0, 0, self.dp(12)); tintPaletteWrap.setPadding(0, 0, 0, self.dp(12));
tintPaletteWrap.setBackground(self.ui.createRoundDrawable(self.withAlpha(cardColor, 0.92), self.dp(14))); tintPaletteWrap.setBackground(self.ui.createRoundDrawable(self.withAlpha(cardColor, 0.92), self.dp(14)));
form.addView(tintPaletteWrap); iconSectionBody.addView(tintPaletteWrap);
tintPaletteState.pickerWrap = tintPaletteWrap; tintPaletteState.pickerWrap = tintPaletteWrap;
var tintPaletteHead = new android.widget.LinearLayout(context); var tintPaletteHead = new android.widget.LinearLayout(context);
@@ -2204,7 +2266,7 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() {
})); }));
self.createButtonEditorSectionCard(form, "动作设置", "选择点击后执行的动作类型与参数"); var actionSectionBody = self.createButtonEditorCollapsibleSection(form, "动作设置", "选择点击后执行的动作类型与参数", true);
// 2. 动作类型(自动换行:用 GridLayout 稳定实现) // 2. 动作类型(自动换行:用 GridLayout 稳定实现)
// 这段代码的主要内容/用途把「Shell/App/广播/Intent/快捷方式」做成会自动换行的单选框区域。 // 这段代码的主要内容/用途把「Shell/App/广播/Intent/快捷方式」做成会自动换行的单选框区域。
@@ -2390,12 +2452,12 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() {
} }
})); }));
} catch(eLC) { safeLog(null, 'e', "catch " + String(eLC)); } } catch(eLC) { safeLog(null, 'e', "catch " + String(eLC)); }
form.addView(typeWrap); actionSectionBody.addView(typeWrap);
// 3. 动态输入区 // 3. 动态输入区
var dynamicContainer = new android.widget.LinearLayout(context); var dynamicContainer = new android.widget.LinearLayout(context);
dynamicContainer.setOrientation(android.widget.LinearLayout.VERTICAL); dynamicContainer.setOrientation(android.widget.LinearLayout.VERTICAL);
form.addView(dynamicContainer); actionSectionBody.addView(dynamicContainer);
// --- Shell --- // --- Shell ---
var shellWrap = new android.widget.LinearLayout(context); var shellWrap = new android.widget.LinearLayout(context);

View File

@@ -54,8 +54,8 @@
"size": 20386 "size": 20386
}, },
"th_14_panels.js": { "th_14_panels.js": {
"sha256": "5ed0c2ece79efe2d67e3c0b6f85e8e2b24980d4a46de3fafc7a461940801a936", "sha256": "d4feca93a07646e39eb3c6be5067e02ecbc621af01a505252aaef68deed94770",
"size": 231980 "size": 235051
}, },
"th_15_extra.js": { "th_15_extra.js": {
"sha256": "b48c16ea5cbe5b9033d593eb18ef3028c0d661c65cbf2ad8f3f650ee55bbe2e4", "sha256": "b48c16ea5cbe5b9033d593eb18ef3028c0d661c65cbf2ad8f3f650ee55bbe2e4",
@@ -68,5 +68,5 @@
}, },
"keyId": "toolhub-targets-2026-rsa3072", "keyId": "toolhub-targets-2026-rsa3072",
"schema": 2, "schema": 2,
"version": 20260512120949 "version": 20260512121643
} }

View File

@@ -1 +1 @@
gU+hIRBv2e9XZsdjiMYpra5GZEETvN6tJJ7+4JCk0UogctlzVFOkk+oab5QPfjIgZLlHxE46oonrycaMlMeOoiH8eYZtEQgwrMqLnuWDuTeGNb3pkIaXCyRbZWMd8CCODZWbzlljgwYt9p1L9J7Ovu0D3hFfS4EgwqB5OSYVkkhO/RGs+JbAFmNIRFVMiU8Uw0K7tTIwLxlvHf6SHuMeFQi2XVemHn23bXrbhzgO3Mn+QStkGn1bF5HMNHN1IF5UU6a2YG0pb4eApwVW9xKzYlAhBloOC/6r4eOvixT0FiVA+2bRdffFCf3bfxv51XmNwLcQp+PV9vn4bpSiqEsLUVZ72uyW90Q7F4FPl4+Ef5BP5ICMMDJ/943zA0L5uBErhlVn44yeuh/bzZ19Tvjs+xPEtsUmx0qQ7I6tC0uDe6pq6QYLwUmWaNMZTDlIbWCBK+GfBS6BZ2a83Q6P/pRG1eF7qJnXUdfckX5QedBIDd7UyzpeCD5qpeGXNQ9ZZ5d/ T7fLDXlMfshFhc7sDZ+9KvkgYpaH1gcTZvSbuKCD3JI43+8qAP9ecprlEajPfvLg59LzEZrZSGo7wG8z8JTSJ2zAKXhAWfmA73W9dohCvdcTcdGLQcQurCOXMYC8qIvB6b1UcUryeQ/2k+5loGOkP77jbOU/qe3/STfz7Al081idVKwSmRmcyqYRszgG2Xy88y3WMgAS1As+tP/sJ4NlOEYjAG/GJr6PmFHMk9t5tqbcUQyWoYhU1rbvbzaPsKCYXycctxvqayidWXMYlpp2+1J/0QRDOSKd/ha2VJfrty+I+e4Sy4mQUYdrTLnjzTyhg5ZGQANqCEvW9RguATwPNxAZfZZwyZiNUfJEJtYjC9nGDAmVIVDCuv8kH0bIPwjsbtn7LBvFR0WE6HVw29jpYpriAy0jQPoYypZDlWsq49X0W6Np4dufXawgSlOvMzrSBk8yr9dgcgsH7QCvp8Yf/oz47JY+9sUqSsRZCrRDld5oLRlD9ZznJkld6wxjJ2dk