fix(ui): 将设置面板的图标和颜色选择器改为内嵌式,修复 AlertDialog 在后台无法弹出问题

- ball_shortx_icon: 使用内嵌 ListView + 搜索框替代 AlertDialog
- ball_color: 使用内嵌调色板网格 + 输入框替代 AlertDialog
- 添加展开/收起按钮,与按钮编辑器的交互模式保持一致
- 移除所有 AlertDialog.Builder 调用(在 ShortX 后台服务环境无法显示)
This commit is contained in:
Hermes
2026-04-20 16:24:20 +08:00
parent f2c80112c1
commit b5e7695d1a

View File

@@ -364,7 +364,7 @@ FloatBallAppWM.prototype.createSettingItemView = function(item, parent, needDivi
row.addView(rg); row.addView(rg);
parent.addView(row); parent.addView(row);
} else if (item.type === "ball_shortx_icon") { } else if (item.type === "ball_shortx_icon") {
// === 悬浮球 ShortX 图标选择器 === // === 悬浮球 ShortX 图标选择器(内嵌式,无 AlertDialog===
row.setOrientation(android.widget.LinearLayout.VERTICAL); row.setOrientation(android.widget.LinearLayout.VERTICAL);
var tv = new android.widget.TextView(context); var tv = new android.widget.TextView(context);
tv.setText(String(item.name)); tv.setText(String(item.name));
@@ -383,11 +383,11 @@ FloatBallAppWM.prototype.createSettingItemView = function(item, parent, needDivi
previewIv.setLayoutParams(previewIvLp); previewIv.setLayoutParams(previewIvLp);
previewIv.setScaleType(android.widget.ImageView.ScaleType.FIT_CENTER); previewIv.setScaleType(android.widget.ImageView.ScaleType.FIT_CENTER);
try { try {
var curIconName = String(self.getPendingValue(item.key) || ""); var curIconName0 = String(self.getPendingValue(item.key) || "");
var curTint = String(self.getPendingValue("BALL_ICON_TINT_HEX") || ""); var curTint0 = String(self.getPendingValue("BALL_ICON_TINT_HEX") || "");
if (curIconName) { if (curIconName0) {
var dr = self.resolveShortXDrawable(curIconName, curTint); var dr0 = self.resolveShortXDrawable(curIconName0, curTint0);
if (dr) previewIv.setImageDrawable(dr); if (dr0) previewIv.setImageDrawable(dr0);
} }
} catch(ePreview) {} } catch(ePreview) {}
iconRow.addView(previewIv); iconRow.addView(previewIv);
@@ -400,62 +400,77 @@ FloatBallAppWM.prototype.createSettingItemView = function(item, parent, needDivi
nameTv.setLayoutParams(nameTvLp); nameTv.setLayoutParams(nameTvLp);
iconRow.addView(nameTv); iconRow.addView(nameTv);
var btnPick = self.ui.createFlatButton(self, "选择", primary, function() { // 展开/收起状态
self.touchActivity(); var iconPickerExpanded = false;
var btnPick = self.ui.createFlatButton(self, "展开图标库", primary, function() {
iconPickerExpanded = !iconPickerExpanded;
btnPick.setText(iconPickerExpanded ? "收起图标库" : "展开图标库");
iconPickerWrap.setVisibility(iconPickerExpanded ? android.view.View.VISIBLE : android.view.View.GONE);
if (iconPickerExpanded) {
try { try {
var catalog = self.getShortXIconCatalog(); if (!iconListView.getAdapter() || iconListView.getAdapter().getCount() === 0) {
if (!catalog || catalog.length === 0) { var catalog0 = self.getShortXIconCatalog();
if (!catalog0 || catalog0.length === 0) {
self.toast("图标库未加载,请检查 ShortX 是否安装"); self.toast("图标库未加载,请检查 ShortX 是否安装");
iconPickerExpanded = false;
btnPick.setText("展开图标库");
iconPickerWrap.setVisibility(android.view.View.GONE);
return; return;
} }
var adapterData0 = [];
var ii;
for (ii = 0; ii < catalog0.length; ii++) {
adapterData0.push(String(catalog0[ii].shortName || catalog0[ii].name));
}
var adapter0 = new android.widget.ArrayAdapter(context, android.R.layout.simple_list_item_1, adapterData0);
iconListView.setAdapter(adapter0);
}
} catch(eLoad) {
self.toast("加载图标库失败: " + String(eLoad));
}
}
});
iconRow.addView(btnPick);
row.addView(iconRow);
var dialogView = new android.widget.LinearLayout(context); // 内嵌图标选择区域
dialogView.setOrientation(android.widget.LinearLayout.VERTICAL); var iconPickerWrap = new android.widget.LinearLayout(context);
dialogView.setPadding(self.dp(16), self.dp(16), self.dp(16), self.dp(16)); iconPickerWrap.setOrientation(android.widget.LinearLayout.VERTICAL);
iconPickerWrap.setVisibility(android.view.View.GONE);
iconPickerWrap.setPadding(0, self.dp(8), 0, 0);
var searchEt = new android.widget.EditText(context); var searchEt = new android.widget.EditText(context);
searchEt.setHint("搜索图标..."); searchEt.setHint("搜索图标...");
searchEt.setTextColor(textColor); searchEt.setTextColor(textColor);
searchEt.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 14); searchEt.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 13);
searchEt.setBackground(self.ui.createRoundDrawable(isDark ? C.inputBgDark : C.inputBgLight, self.dp(6))); searchEt.setBackground(self.ui.createRoundDrawable(isDark ? C.inputBgDark : C.inputBgLight, self.dp(6)));
searchEt.setPadding(self.dp(8), self.dp(8), self.dp(8), self.dp(8)); searchEt.setPadding(self.dp(8), self.dp(6), self.dp(8), self.dp(6));
searchEt.setSingleLine(true); searchEt.setSingleLine(true);
dialogView.addView(searchEt); iconPickerWrap.addView(searchEt);
var listView = new android.widget.ListView(context); var iconListView = new android.widget.ListView(context);
var listLp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, self.dp(360)); var listLp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, self.dp(280));
listLp.topMargin = self.dp(8); listLp.topMargin = self.dp(6);
listView.setLayoutParams(listLp); iconListView.setLayoutParams(listLp);
dialogView.addView(listView); iconPickerWrap.addView(iconListView);
var adapterData = []; iconListView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener({
var i;
for (i = 0; i < catalog.length; i++) {
adapterData.push(String(catalog[i].shortName || catalog[i].name));
}
var adapter = new android.widget.ArrayAdapter(context, android.R.layout.simple_list_item_1, adapterData);
listView.setAdapter(adapter);
var dialog = new android.app.AlertDialog.Builder(context)
.setTitle("选择 ShortX 图标")
.setView(dialogView)
.setNegativeButton("取消", null)
.create();
listView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener({
onItemClick: function(parent, view, position, id) { onItemClick: function(parent, view, position, id) {
try { try {
var selectedName = String(adapter.getItem(position)); var adapter1 = iconListView.getAdapter();
var selectedName = String(adapter1.getItem(position));
self.setPendingValue(item.key, selectedName); self.setPendingValue(item.key, selectedName);
nameTv.setText(selectedName); nameTv.setText(selectedName);
try { try {
var tint = String(self.getPendingValue("BALL_ICON_TINT_HEX") || ""); var tint1 = String(self.getPendingValue("BALL_ICON_TINT_HEX") || "");
var dr = self.resolveShortXDrawable(selectedName, tint); var dr1 = self.resolveShortXDrawable(selectedName, tint1);
if (dr) previewIv.setImageDrawable(dr); if (dr1) previewIv.setImageDrawable(dr1);
else previewIv.setImageDrawable(null); else previewIv.setImageDrawable(null);
} catch(eDr) {} } catch(eDr) {}
dialog.dismiss(); iconPickerExpanded = false;
btnPick.setText("展开图标库");
iconPickerWrap.setVisibility(android.view.View.GONE);
if (self.state.previewMode) self.rebuildBallForNewSize(true); if (self.state.previewMode) self.rebuildBallForNewSize(true);
} catch(eClick) {} } catch(eClick) {}
} }
@@ -466,30 +481,25 @@ FloatBallAppWM.prototype.createSettingItemView = function(item, parent, needDivi
onTextChanged: function(s, start, before, count) {}, onTextChanged: function(s, start, before, count) {},
afterTextChanged: function(s) { afterTextChanged: function(s) {
try { try {
var catalog1 = self.getShortXIconCatalog();
var q = String(s).toLowerCase(); var q = String(s).toLowerCase();
var filtered = []; var filtered = [];
var j; var j;
for (j = 0; j < catalog.length; j++) { for (j = 0; j < catalog1.length; j++) {
var n = String(catalog[j].shortName || catalog[j].name).toLowerCase(); var n = String(catalog1[j].shortName || catalog1[j].name).toLowerCase();
if (n.indexOf(q) >= 0) filtered.push(String(catalog[j].shortName || catalog[j].name)); if (n.indexOf(q) >= 0) filtered.push(String(catalog1[j].shortName || catalog1[j].name));
} }
var newAdapter = new android.widget.ArrayAdapter(context, android.R.layout.simple_list_item_1, filtered); var newAdapter = new android.widget.ArrayAdapter(context, android.R.layout.simple_list_item_1, filtered);
listView.setAdapter(newAdapter); iconListView.setAdapter(newAdapter);
} catch(eFilter) {} } catch(eFilter) {}
} }
})); }));
dialog.show(); row.addView(iconPickerWrap);
} catch(eDialog) {
self.toast("打开图标选择器失败: " + String(eDialog));
}
});
iconRow.addView(btnPick);
row.addView(iconRow);
parent.addView(row); parent.addView(row);
} else if (item.type === "ball_color") { } else if (item.type === "ball_color") {
// === 悬浮球图标颜色选择器 === // === 悬浮球图标颜色选择器(内嵌式,无 AlertDialog===
row.setOrientation(android.widget.LinearLayout.VERTICAL); row.setOrientation(android.widget.LinearLayout.VERTICAL);
var tv = new android.widget.TextView(context); var tv = new android.widget.TextView(context);
tv.setText(String(item.name)); tv.setText(String(item.name));
@@ -507,9 +517,9 @@ FloatBallAppWM.prototype.createSettingItemView = function(item, parent, needDivi
colorDotLp.rightMargin = self.dp(10); colorDotLp.rightMargin = self.dp(10);
colorDot.setLayoutParams(colorDotLp); colorDot.setLayoutParams(colorDotLp);
try { try {
var curHex = String(self.getPendingValue(item.key) || ""); var curHex0 = String(self.getPendingValue(item.key) || "");
if (curHex) { if (curHex0) {
colorDot.setBackground(self.ui.createRoundDrawable(android.graphics.Color.parseColor(curHex), self.dp(14))); colorDot.setBackground(self.ui.createRoundDrawable(android.graphics.Color.parseColor(curHex0), self.dp(14)));
} else { } else {
colorDot.setBackground(self.ui.createRoundDrawable(0xFFCCCCCC | 0, self.dp(14))); colorDot.setBackground(self.ui.createRoundDrawable(0xFFCCCCCC | 0, self.dp(14)));
} }
@@ -526,25 +536,26 @@ FloatBallAppWM.prototype.createSettingItemView = function(item, parent, needDivi
colorValueTv.setLayoutParams(colorValueLp); colorValueTv.setLayoutParams(colorValueLp);
colorRow.addView(colorValueTv); colorRow.addView(colorValueTv);
var commonColors = [ var paletteExpanded = false;
"#F44336", "#E91E63", "#9C27B0", "#673AB7", "#3F51B5",
"#2196F3", "#03A9F4", "#00BCD4", "#009688", "#4CAF50",
"#8BC34A", "#CDDC39", "#FFEB3B", "#FFC107", "#FF9800",
"#FF5722", "#795548", "#9E9E9E", "#607D8B", "#000000", "#FFFFFF"
];
var btnColor = self.ui.createFlatButton(self, "调色板", primary, function() { var btnColor = self.ui.createFlatButton(self, "展开调色板", primary, function() {
self.touchActivity(); paletteExpanded = !paletteExpanded;
try { btnColor.setText(paletteExpanded ? "收起调色板" : "展开调色板");
var dialogView = new android.widget.LinearLayout(context); paletteWrap.setVisibility(paletteExpanded ? android.view.View.VISIBLE : android.view.View.GONE);
dialogView.setOrientation(android.widget.LinearLayout.VERTICAL); });
dialogView.setPadding(self.dp(16), self.dp(16), self.dp(16), self.dp(16)); colorRow.addView(btnColor);
row.addView(colorRow);
var paletteWrap = new android.widget.LinearLayout(context);
paletteWrap.setOrientation(android.widget.LinearLayout.VERTICAL);
paletteWrap.setVisibility(android.view.View.GONE);
paletteWrap.setPadding(0, self.dp(8), 0, 0);
var scroll = new android.widget.ScrollView(context); var scroll = new android.widget.ScrollView(context);
var scrollBox = new android.widget.LinearLayout(context); var scrollBox = new android.widget.LinearLayout(context);
scrollBox.setOrientation(android.widget.LinearLayout.VERTICAL); scrollBox.setOrientation(android.widget.LinearLayout.VERTICAL);
scroll.addView(scrollBox); scroll.addView(scrollBox);
dialogView.addView(scroll); paletteWrap.addView(scroll);
var grid = new android.widget.GridLayout(context); var grid = new android.widget.GridLayout(context);
try { grid.setColumnCount(5); } catch(e){} try { grid.setColumnCount(5); } catch(e){}
@@ -552,6 +563,13 @@ FloatBallAppWM.prototype.createSettingItemView = function(item, parent, needDivi
grid.setLayoutParams(gridLp); grid.setLayoutParams(gridLp);
scrollBox.addView(grid); scrollBox.addView(grid);
var commonColors = [
"#F44336", "#E91E63", "#9C27B0", "#673AB7", "#3F51B5",
"#2196F3", "#03A9F4", "#00BCD4", "#009688", "#4CAF50",
"#8BC34A", "#CDDC39", "#FFEB3B", "#FFC107", "#FF9800",
"#FF5722", "#795548", "#9E9E9E", "#607D8B", "#000000", "#FFFFFF"
];
var ci; var ci;
for (ci = 0; ci < commonColors.length; ci++) { for (ci = 0; ci < commonColors.length; ci++) {
(function(hex) { (function(hex) {
@@ -577,21 +595,22 @@ FloatBallAppWM.prototype.createSettingItemView = function(item, parent, needDivi
var inputEt = new android.widget.EditText(context); var inputEt = new android.widget.EditText(context);
inputEt.setHint("手动输入 #RRGGBB"); inputEt.setHint("手动输入 #RRGGBB");
inputEt.setTextColor(textColor); inputEt.setTextColor(textColor);
inputEt.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 14); inputEt.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 13);
inputEt.setBackground(self.ui.createRoundDrawable(isDark ? C.inputBgDark : C.inputBgLight, self.dp(6))); inputEt.setBackground(self.ui.createRoundDrawable(isDark ? C.inputBgDark : C.inputBgLight, self.dp(6)));
inputEt.setPadding(self.dp(8), self.dp(8), self.dp(8), self.dp(8)); inputEt.setPadding(self.dp(8), self.dp(6), self.dp(8), self.dp(6));
inputEt.setSingleLine(true); inputEt.setSingleLine(true);
inputEt.setText(String(self.getPendingValue(item.key) || "")); inputEt.setText(String(self.getPendingValue(item.key) || ""));
var inputLp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT); var inputLp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT);
inputLp.topMargin = self.dp(12); inputLp.topMargin = self.dp(10);
inputEt.setLayoutParams(inputLp); inputEt.setLayoutParams(inputLp);
scrollBox.addView(inputEt); scrollBox.addView(inputEt);
var dialog = new android.app.AlertDialog.Builder(context) var btnRow = new android.widget.LinearLayout(context);
.setTitle("选择图标颜色") btnRow.setOrientation(android.widget.LinearLayout.HORIZONTAL);
.setView(dialogView) btnRow.setGravity(android.view.Gravity.END);
.setPositiveButton("确定", new android.content.DialogInterface.OnClickListener({ btnRow.setPadding(0, self.dp(8), 0, 0);
onClick: function(dlg, which) {
var btnConfirm = self.ui.createFlatButton(self, "确定", primary, function() {
try { try {
var val = String(inputEt.getText() || "").replace(/^\s+|\s+$/g, ""); var val = String(inputEt.getText() || "").replace(/^\s+|\s+$/g, "");
if (val) { if (val) {
@@ -605,21 +624,30 @@ FloatBallAppWM.prototype.createSettingItemView = function(item, parent, needDivi
colorValueTv.setText("默认"); colorValueTv.setText("默认");
try { colorDot.setBackground(self.ui.createRoundDrawable(0xFFCCCCCC | 0, self.dp(14))); } catch(eDot4) {} try { colorDot.setBackground(self.ui.createRoundDrawable(0xFFCCCCCC | 0, self.dp(14))); } catch(eDot4) {}
} }
paletteExpanded = false;
btnColor.setText("展开调色板");
paletteWrap.setVisibility(android.view.View.GONE);
if (self.state.previewMode) self.rebuildBallForNewSize(true); if (self.state.previewMode) self.rebuildBallForNewSize(true);
} catch(eOk) { } catch(eOk) {
self.toast("颜色格式无效"); self.toast("颜色格式无效");
} }
}
}))
.setNegativeButton("取消", null)
.create();
dialog.show();
} catch(eDialog) {
self.toast("打开调色板失败: " + String(eDialog));
}
}); });
colorRow.addView(btnColor); btnRow.addView(btnConfirm);
row.addView(colorRow);
var btnClear = self.ui.createFlatButton(self, "清空", secColor, function() {
self.setPendingValue(item.key, "");
colorValueTv.setText("默认");
try { colorDot.setBackground(self.ui.createRoundDrawable(0xFFCCCCCC | 0, self.dp(14))); } catch(eDot5) {}
inputEt.setText("");
paletteExpanded = false;
btnColor.setText("展开调色板");
paletteWrap.setVisibility(android.view.View.GONE);
if (self.state.previewMode) self.rebuildBallForNewSize(true);
});
btnRow.addView(btnClear);
scrollBox.addView(btnRow);
row.addView(paletteWrap);
parent.addView(row); parent.addView(row);
} else { } else {