diff --git a/code/th_02_core.js b/code/th_02_core.js index d73c771..89e939a 100644 --- a/code/th_02_core.js +++ b/code/th_02_core.js @@ -77,6 +77,9 @@ function FloatBallAppWM(logger) { pendingUserCfg: null, pendingDirty: false, + // 按钮管理首页:搜索过滤状态 + buttonManagerQuery: "", + closing: false }; diff --git a/code/th_14_panels.js b/code/th_14_panels.js index fe32a29..b97e813 100644 --- a/code/th_14_panels.js +++ b/code/th_14_panels.js @@ -494,6 +494,72 @@ function __scDrawableToBitmap(drawable, targetPx) { } } + +FloatBallAppWM.prototype.matchesButtonManagerQuery = function(btnCfg, query) { + try { + var q = String(query || "").replace(/^\s+|\s+$/g, "").toLowerCase(); + if (!q) return true; + var b = btnCfg || {}; + var hay = String(b.title || "") + " " + String(b.type || "") + " " + String(b.cmd || "") + " " + String(b.pkg || "") + " " + String(b.action || "") + " " + String(b.intent || "") + " " + String(b.shortcutName || "") + " " + String(b.iconResName || ""); + return hay.toLowerCase().indexOf(q) >= 0; + } catch(e) { return true; } +}; + +FloatBallAppWM.prototype.createButtonManagerSummaryCard = function(parent, totalCount, enabledCount, disabledCount) { + var isDark = this.isDarkTheme(); + var C = this.ui.colors; + var card = new android.widget.LinearLayout(context); + card.setOrientation(android.widget.LinearLayout.VERTICAL); + card.setPadding(this.dp(14), this.dp(10), this.dp(14), this.dp(10)); + card.setBackground(this.ui.createRoundDrawable(isDark ? this.withAlpha(C.cardDark, 0.88) : this.withAlpha(C.cardLight, 0.92), this.dp(14))); + try { card.setElevation(this.dp(2)); } catch(eElev) { safeLog(null, 'e', "catch " + String(eElev)); } + + var title = new android.widget.TextView(context); + title.setText("按钮管理首页"); + title.setTextColor(isDark ? C.textPriDark : C.textPriLight); + title.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 15); + title.setTypeface(null, android.graphics.Typeface.BOLD); + card.addView(title); + + var sub = new android.widget.TextView(context); + sub.setText("共 " + totalCount + " 个 · 已启用 " + enabledCount + " · 已禁用 " + disabledCount); + sub.setTextColor(isDark ? C.textSecDark : C.textSecLight); + sub.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 12); + sub.setPadding(0, this.dp(4), 0, 0); + card.addView(sub); + + var lp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT); + lp.setMargins(this.dp(2), this.dp(2), this.dp(2), this.dp(8)); + parent.addView(card, lp); +}; + +FloatBallAppWM.prototype.createButtonEditorSectionCard = function(parent, title, desc) { + var isDark = this.isDarkTheme(); + var C = this.ui.colors; + var box = new android.widget.LinearLayout(context); + box.setOrientation(android.widget.LinearLayout.VERTICAL); + box.setPadding(this.dp(12), this.dp(10), this.dp(12), this.dp(10)); + box.setBackground(this.ui.createRoundDrawable(isDark ? this.withAlpha(C.cardDark, 0.72) : this.withAlpha(C.cardLight, 0.78), this.dp(14))); + 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); + box.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), 0, 0); + box.addView(dv); + } + 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(box, lp); + return box; +}; + FloatBallAppWM.prototype.buildButtonEditorPanelView = function() { var self = this; // # 状态管理:editingIndex (null=列表, -1=新增, >=0=编辑) @@ -578,6 +644,41 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() { // 暴露 Header 给 DragListener panel.setTag(header); + var enabledCount = 0; + var disabledCount = 0; + try { + for (var ci = 0; ci < buttons.length; ci++) { + if (buttons[ci] && buttons[ci].enabled === false) disabledCount++; + else enabledCount++; + } + } catch(eCnt) { safeLog(null, 'e', "catch " + String(eCnt)); } + self.createButtonManagerSummaryCard(panel, buttons.length, enabledCount, disabledCount); + + var searchRow = new android.widget.LinearLayout(context); + searchRow.setOrientation(android.widget.LinearLayout.HORIZONTAL); + searchRow.setGravity(android.view.Gravity.CENTER_VERTICAL); + searchRow.setPadding(0, 0, 0, self.dp(8)); + var searchInput = self.ui.createInputGroup(self, "搜索按钮", self.state.buttonManagerQuery || "", false, "标题 / 类型 / 包名 / 命令"); + var searchInputLp = new android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT); + searchInputLp.weight = 1; + searchRow.addView(searchInput.view, searchInputLp); + var btnSearch = self.ui.createFlatButton(self, "搜索", C.primary, function() { + try { self.state.buttonManagerQuery = String(searchInput.getValue ? searchInput.getValue() : ""); } catch(eQ) { self.state.buttonManagerQuery = ""; } + self.state.btnEditorListScrollY = 0; + refreshPanel(); + }); + searchRow.addView(btnSearch); + var btnClearSearch = self.ui.createFlatButton(self, "清空", subTextColor, function() { + self.state.buttonManagerQuery = ""; + self.state.btnEditorListScrollY = 0; + refreshPanel(); + }); + searchRow.addView(btnClearSearch); + panel.addView(searchRow); + + var activeQuery = String(self.state.buttonManagerQuery || ""); + var visibleCount = 0; + // 列表区域 var scroll = new android.widget.ScrollView(context); __btnEditorListScroll = scroll; // # 列表滚动位置保持:让 refreshPanel 能拿到当前列表的滚动位置 @@ -589,6 +690,8 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() { for (var i = 0; i < buttons.length; i++) { (function(idx) { var btnCfg = buttons[idx]; + if (!self.matchesButtonManagerQuery(btnCfg, activeQuery)) return; + visibleCount++; // # 启用/禁用状态:禁用项在按钮页不显示,但在管理页需要标识出来 var __enabled = true; @@ -805,7 +908,7 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() { } // 空状态提示 - if (buttons.length === 0) { + if (visibleCount === 0) { var emptyBox = new android.widget.LinearLayout(context); emptyBox.setOrientation(android.widget.LinearLayout.VERTICAL); emptyBox.setGravity(android.view.Gravity.CENTER); @@ -819,7 +922,7 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() { emptyBox.addView(emptyIcon); var emptyTv = new android.widget.TextView(context); - emptyTv.setText("暂无按钮,点击右上角新增"); + emptyTv.setText(activeQuery ? "没有匹配的按钮,点清空查看全部" : "暂无按钮,点击右上角新增"); emptyTv.setTextColor(subTextColor); emptyTv.setPadding(0, self.dp(16), 0, 0); emptyBox.addView(emptyTv); @@ -911,6 +1014,8 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() { editHint.setPadding(self.dp(4), 0, 0, self.dp(16)); form.addView(editHint); + self.createButtonEditorSectionCard(form, "基础信息", "按钮名称与基础标识"); + // 1. 标题 (Title) var topArea = new android.widget.LinearLayout(context); topArea.setOrientation(android.widget.LinearLayout.HORIZONTAL); @@ -930,6 +1035,8 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() { form.addView(topArea); + self.createButtonEditorSectionCard(form, "图标外观", "选择图标来源、ShortX 图标和颜色"); + // 1.5 图标选择(文件路径 或 ShortX 内置图标 二选一) var iconSelectWrap = new android.widget.LinearLayout(context); iconSelectWrap.setOrientation(android.widget.LinearLayout.VERTICAL); @@ -2097,6 +2204,8 @@ FloatBallAppWM.prototype.buildButtonEditorPanelView = function() { })); + self.createButtonEditorSectionCard(form, "动作设置", "选择点击后执行的动作类型与参数"); + // 2. 动作类型(自动换行:用 GridLayout 稳定实现) // 这段代码的主要内容/用途:把「Shell/App/广播/Intent/快捷方式」做成会自动换行的单选框区域。 // 说明:之前用"多行 LinearLayout + 手工测量"在部分 ROM/布局时序下会出现宽度为 0 或不渲染,导致"单选框看不见"。 diff --git a/manifest.json b/manifest.json index 3663bad..2660869 100644 --- a/manifest.json +++ b/manifest.json @@ -6,8 +6,8 @@ "size": 52546 }, "th_02_core.js": { - "sha256": "3ccdff641f8cd1e185812f24df0baf65c7749a320d29549340f884575ac4fa9d", - "size": 4127 + "sha256": "24363adc7156feda5c2f1fcbb84c96a4378ffec4b40251bd27d0123329acf054", + "size": 4203 }, "th_03_icon.js": { "sha256": "717f7f37474d3616c2cd944581455f600020a850ec8812100d0546ec1302c987", @@ -54,8 +54,8 @@ "size": 20386 }, "th_14_panels.js": { - "sha256": "c65a2ac74f69f3763f5effd8533a27d1e1bd47660c9f2beb8961ad60d012058a", - "size": 226409 + "sha256": "5ed0c2ece79efe2d67e3c0b6f85e8e2b24980d4a46de3fafc7a461940801a936", + "size": 231980 }, "th_15_extra.js": { "sha256": "b48c16ea5cbe5b9033d593eb18ef3028c0d661c65cbf2ad8f3f650ee55bbe2e4", @@ -68,5 +68,5 @@ }, "keyId": "toolhub-targets-2026-rsa3072", "schema": 2, - "version": 20260512093034 + "version": 20260512111055 } diff --git a/manifest.sig b/manifest.sig index a402f5d..a26d210 100644 --- a/manifest.sig +++ b/manifest.sig @@ -1 +1 @@ -QeDCiPelzRAPjhtoPyf6861/eQKyfrIqV66PERJbtyu0n8oJsw34JQxQQE5DjMURszMTjV/scS8cxytrSJtb81W1vqE3LGbRwDdVHt6Wdf+n62HMkRGdg7MzBQma5AVVMPsw3ElvfVf5q46nRsgrCmRXJ4j5d3a8SqlTm+HxtsmaDOjGn+mqZynnHFgGwbj0YQtQXYE+9GUt/tk34ffksG30k0+fRkQ71zsCad9XAHrUMHDJvHOCIZNg+rpqYlZDXxZsTyiXSCmb+IcW5G8jZMDo6K5D650a8TYdh1MfcBl7S0qhsuPPNwqxm9SbtWHwoKg4EDlpKNrRRXupm/4kIGRD+VVMYnsmbIUyGwr561JXqD1IgjyuJY52SQIG+ZEaLy77c/1JQ8tuxzufTcKfIyhr5Q/hbnZ6sRZ9eD791q68ZfQ7HZ9Gzv6kD+3rnnvLNC0kwWnpeeZipa9+qu1xbWkBSWj++Fu9ZBD9CHrB30zF7Tqg2gk3XR8bPttonU0M +G+Vg48mDhYHupFhgZdH7mx2kn6AJiHNOVBfkuULMURTDG4yNeIomcjldi/mw9zTdDrgzmcHnvJEe/YnisYF21bwJ0OE7fWVTHqjWQFQq3SHMIWVjWaP2Jz7r+tinvAQfpGgOj3lDPddDthIMd59hCs1vcM2LWT/RegEGybVquv9LBnHybIuawYuuJeFP5jptKghw016FZ7veLpIlvij7RwptgUyknT6VaKpcsRIInTtlvUPvjrMNqfN2rH1X+OhzaxFEhUnxBU5P2m5TLZsb70hCy456GaBN8i0yOanIMWCfNy9gkUzYwW87Vf5qEvKU4Y+/Vp9mKcevN6O7DrKsOld6TXqFYyf0k4cw5SOq/mSZEmMaJejrwXkXeK/VNwn1zKqGWx/Vax3mWfYl5zdO9QoPMjWx0WRVqBwMaUV6lnWx4WOwhONyOhbwYhg85DgnzO+dtxyJsDwh3F9w3sjNoqwQTVWTAklvh6lhlOB9dR6ZL8sqLFoh0DOewEK7qYIC