Compare commits
30 Commits
855352bfd9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd3452af45 | ||
|
|
39e62ddaa0 | ||
|
|
9de9983b50 | ||
|
|
0cc6439619 | ||
|
|
095f7ccb39 | ||
|
|
757a60d15d | ||
|
|
d347bb190c | ||
|
|
27dd07da49 | ||
|
|
a327ba2657 | ||
|
|
aa4ef421fe | ||
|
|
00508c9cde | ||
|
|
407cd2200c | ||
|
|
1d49609131 | ||
|
|
c62328c419 | ||
|
|
52b13bea19 | ||
|
|
c8f8f46054 | ||
|
|
954caa9d9b | ||
|
|
61eeac6646 | ||
|
|
0aa7cbfbfd | ||
|
|
3f93a42a00 | ||
|
|
7bc4a1bb7d | ||
|
|
a9db5faf1b | ||
|
|
736212fd80 | ||
|
|
83249ab534 | ||
|
|
8fd7a560d8 | ||
|
|
479a23592c | ||
|
|
adc93338cf | ||
|
|
4800536de8 | ||
|
|
fd56e14fc8 | ||
|
|
557950f692 |
23
ToolHub.js
23
ToolHub.js
@@ -33,16 +33,31 @@ function getTrustedShaPath(relPath) { return getCodeDirPath() + ".trusted_sha_"
|
|||||||
function getTrustedVersionPath() { return getCodeDirPath() + ".trusted_manifest_version"; }
|
function getTrustedVersionPath() { return getCodeDirPath() + ".trusted_manifest_version"; }
|
||||||
|
|
||||||
function writeLog(msg) {
|
function writeLog(msg) {
|
||||||
|
var writer = null;
|
||||||
try {
|
try {
|
||||||
var f = new java.io.File(getLogPath());
|
var f = new java.io.File(getLogPath());
|
||||||
var dir = f.getParentFile();
|
var dir = f.getParentFile();
|
||||||
if (dir && !dir.exists()) dir.mkdirs();
|
if (dir && !dir.exists()) dir.mkdirs();
|
||||||
|
try {
|
||||||
|
var maxBytes = 512 * 1024;
|
||||||
|
if (f.exists() && f.length() > maxBytes) {
|
||||||
|
var bak = new java.io.File(String(f.getAbsolutePath()) + ".bak");
|
||||||
|
try { if (bak.exists()) bak.delete(); } catch (eBak0) {}
|
||||||
|
var moved = false;
|
||||||
|
try { moved = f.renameTo(bak); } catch (eMv) { moved = false; }
|
||||||
|
if (!moved) {
|
||||||
|
try { f.delete(); } catch (eDel) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (eTrim) {}
|
||||||
var sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
var sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
var ts = sdf.format(new java.util.Date());
|
var ts = sdf.format(new java.util.Date());
|
||||||
var writer = new java.io.FileWriter(f, true);
|
writer = new java.io.FileWriter(f, true);
|
||||||
writer.write("[" + ts + "] " + String(msg) + "\n");
|
writer.write("[" + ts + "] " + String(msg) + "\n");
|
||||||
writer.close();
|
} catch (e) {
|
||||||
} catch (e) {}
|
} finally {
|
||||||
|
try { if (writer) writer.close(); } catch (eClose) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runShell(cmdArr) {
|
function runShell(cmdArr) {
|
||||||
@@ -341,7 +356,7 @@ function loadScript(relPath) {
|
|||||||
var modules = ["th_01_base.js", "th_02_core.js", "th_03_icon.js", "th_04_theme.js", "th_05_persistence.js",
|
var modules = ["th_01_base.js", "th_02_core.js", "th_03_icon.js", "th_04_theme.js", "th_05_persistence.js",
|
||||||
"th_06_icon_parser.js", "th_07_shortcut.js", "th_08_content.js", "th_09_animation.js",
|
"th_06_icon_parser.js", "th_07_shortcut.js", "th_08_content.js", "th_09_animation.js",
|
||||||
"th_10_shell.js", "th_11_action.js", "th_12_rebuild.js", "th_13_panel_ui.js",
|
"th_10_shell.js", "th_11_action.js", "th_12_rebuild.js", "th_13_panel_ui.js",
|
||||||
"th_14_panels.js", "th_15_extra.js", "th_16_entry.js"];
|
"th_14_panels.js", "th_14_color_picker.js", "th_14_icon_picker.js", "th_14_schema_editor.js", "th_15_extra.js", "th_16_entry.js"];
|
||||||
var __moduleUpdates = [];
|
var __moduleUpdates = [];
|
||||||
var loadErrors = [];
|
var loadErrors = [];
|
||||||
var criticalModules = { "th_01_base.js": true, "th_16_entry.js": true };
|
var criticalModules = { "th_01_base.js": true, "th_16_entry.js": true };
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
458579d31a727c021e5ceb83db751a52aeede6db087679f40bf6f1ebc5114ae4 ToolHub.js
|
01d93690bdfc402ad59d6f51db45e3e057a3ebcbbf146a5667ecc5486e2d3ed6 ToolHub.js
|
||||||
|
|||||||
@@ -100,11 +100,11 @@ var ConfigValidator = {
|
|||||||
LONG_PRESS_TRIGGERED_MOVE_SLOP_DP: { type: "int", min: 8, max: 80, default: 28 },
|
LONG_PRESS_TRIGGERED_MOVE_SLOP_DP: { type: "int", min: 8, max: 80, default: 28 },
|
||||||
LONG_PRESS_VIBRATE_MS: { type: "int", min: 10, max: 100, default: 40 },
|
LONG_PRESS_VIBRATE_MS: { type: "int", min: 10, max: 100, default: 40 },
|
||||||
CLICK_SLOP_DP: { type: "int", min: 2, max: 20, default: 6 },
|
CLICK_SLOP_DP: { type: "int", min: 2, max: 20, default: 6 },
|
||||||
TOOLAPP_BACK_EDGE_WIDTH_DP: { type: "int", min: 1, max: 120, default: 24 },
|
TOOLAPP_BACK_GESTURE_MODE: { type: "enum", values: ["edge", "surface", "off"], default: "surface" },
|
||||||
ENABLE_TOOLAPP_INNER_BACK_STRIPS: { type: "bool", default: false },
|
TOOLAPP_BACK_EDGE_WIDTH_DP: { type: "int", min: 1, max: 120, default: 72 },
|
||||||
ENABLE_TOOLAPP_SCREEN_BACK_STRIPS: { type: "bool", default: true },
|
TOOLAPP_BACK_COMMIT_DISTANCE_DP: { type: "int", min: 1, max: 480, default: 36 },
|
||||||
TOOLAPP_BACK_COMMIT_DISTANCE_DP: { type: "int", min: 1, max: 480, default: 72 },
|
TOOLAPP_BACK_SURFACE_SLOP_DP: { type: "int", min: 8, max: 96, default: 24 },
|
||||||
TOOLAPP_BACK_PROGRESS_DISTANCE_DP: { type: "int", min: 1, max: 720, default: 180 },
|
TOOLAPP_BACK_PROGRESS_DISTANCE_DP: { type: "int", min: 1, max: 720, default: 96 },
|
||||||
|
|
||||||
// 功能开关
|
// 功能开关
|
||||||
ENABLE_SNAP_TO_EDGE: { type: "bool", default: true },
|
ENABLE_SNAP_TO_EDGE: { type: "bool", default: true },
|
||||||
@@ -736,11 +736,11 @@ var ConfigManager = {
|
|||||||
LONG_PRESS_MS: 520,
|
LONG_PRESS_MS: 520,
|
||||||
LONG_PRESS_TRIGGERED_MOVE_SLOP_DP: 28,
|
LONG_PRESS_TRIGGERED_MOVE_SLOP_DP: 28,
|
||||||
CLICK_SLOP_DP: 6,
|
CLICK_SLOP_DP: 6,
|
||||||
TOOLAPP_BACK_EDGE_WIDTH_DP: 24,
|
TOOLAPP_BACK_GESTURE_MODE: "surface",
|
||||||
ENABLE_TOOLAPP_INNER_BACK_STRIPS: false,
|
TOOLAPP_BACK_EDGE_WIDTH_DP: 72,
|
||||||
ENABLE_TOOLAPP_SCREEN_BACK_STRIPS: true,
|
TOOLAPP_BACK_COMMIT_DISTANCE_DP: 36,
|
||||||
TOOLAPP_BACK_COMMIT_DISTANCE_DP: 72,
|
TOOLAPP_BACK_SURFACE_SLOP_DP: 24,
|
||||||
TOOLAPP_BACK_PROGRESS_DISTANCE_DP: 180,
|
TOOLAPP_BACK_PROGRESS_DISTANCE_DP: 96,
|
||||||
ENABLE_BOUNCE: true,
|
ENABLE_BOUNCE: true,
|
||||||
BOUNCE_TIMES: 2,
|
BOUNCE_TIMES: 2,
|
||||||
BOUNCE_MAX_SCALE: 0.88,
|
BOUNCE_MAX_SCALE: 0.88,
|
||||||
@@ -848,12 +848,16 @@ var ConfigManager = {
|
|||||||
{ key: "BOUNCE_STEP_MS", name: "回弹步进时长(ms)", type: "int", min: 20, max: 500, step: 10 },
|
{ key: "BOUNCE_STEP_MS", name: "回弹步进时长(ms)", type: "int", min: 20, max: 500, step: 10 },
|
||||||
{ key: "BOUNCE_DECAY", name: "回弹衰减(0~1)", type: "float", min: 0.30, max: 0.95, step: 0.01 },
|
{ key: "BOUNCE_DECAY", name: "回弹衰减(0~1)", type: "float", min: 0.30, max: 0.95, step: 0.01 },
|
||||||
|
|
||||||
{ type: "section", name: "触摸与手势" },
|
{ type: "section", name: "动作与手势" },
|
||||||
{ key: "CLICK_SLOP_DP", name: "点击位移阈值(dp)", type: "int", min: 1, max: 40, step: 1 },
|
{ key: "CLICK_SLOP_DP", name: "点击位移阈值(dp)", type: "int", min: 1, max: 40, step: 1 },
|
||||||
{ key: "TOOLAPP_BACK_EDGE_WIDTH_DP", name: "返回热区宽度", type: "int", min: 1, max: 120, step: 1 },
|
{ key: "TOOLAPP_BACK_GESTURE_MODE", name: "设置页滑动返回模式", type: "single_choice", options: [
|
||||||
{ key: "ENABLE_TOOLAPP_INNER_BACK_STRIPS", name: "启用页面内左右滑动返回", type: "bool" },
|
{ label: "全表面横滑", value: "surface" },
|
||||||
{ key: "ENABLE_TOOLAPP_SCREEN_BACK_STRIPS", name: "启用屏幕边缘返回热区(排查用)", type: "bool" },
|
{ label: "仅面板内部左右边缘", value: "edge" },
|
||||||
|
{ label: "关闭", value: "off" }
|
||||||
|
]},
|
||||||
|
{ key: "TOOLAPP_BACK_EDGE_WIDTH_DP", name: "内部边缘起手宽度", type: "int", min: 1, max: 120, step: 1 },
|
||||||
{ key: "TOOLAPP_BACK_COMMIT_DISTANCE_DP", name: "设置页返回触发距离", type: "int", min: 1, max: 480, step: 1 },
|
{ key: "TOOLAPP_BACK_COMMIT_DISTANCE_DP", name: "设置页返回触发距离", type: "int", min: 1, max: 480, step: 1 },
|
||||||
|
{ key: "TOOLAPP_BACK_SURFACE_SLOP_DP", name: "表面横滑起手阈值", type: "int", min: 8, max: 96, step: 1 },
|
||||||
{ key: "TOOLAPP_BACK_PROGRESS_DISTANCE_DP", name: "设置页返回动画距离", type: "int", min: 1, max: 720, step: 1 },
|
{ key: "TOOLAPP_BACK_PROGRESS_DISTANCE_DP", name: "设置页返回动画距离", type: "int", min: 1, max: 720, step: 1 },
|
||||||
{ key: "ENABLE_LONG_PRESS", name: "启用长按", type: "bool" },
|
{ key: "ENABLE_LONG_PRESS", name: "启用长按", type: "bool" },
|
||||||
{ key: "LONG_PRESS_MS", name: "长按判定(ms)", type: "int", min: 200, max: 2000, step: 10 },
|
{ key: "LONG_PRESS_MS", name: "长按判定(ms)", type: "int", min: 200, max: 2000, step: 10 },
|
||||||
@@ -892,7 +896,10 @@ var ConfigManager = {
|
|||||||
var needReset = false;
|
var needReset = false;
|
||||||
if (s) {
|
if (s) {
|
||||||
var sStr = JSON.stringify(s);
|
var sStr = JSON.stringify(s);
|
||||||
if (sStr.indexOf("ENABLE_SNAP_TO_EDGE") < 0 || sStr.indexOf("ENABLE_ANIMATIONS") < 0 || sStr.indexOf("BALL_IDLE_ALPHA") < 0 || sStr.indexOf("PANEL_POS_GRAVITY") < 0 || sStr.indexOf("single_choice") < 0 || sStr.indexOf("ball_shortx_icon") < 0 || sStr.indexOf("ball_color") < 0 || sStr.indexOf("SETTINGS_THEME") < 0 || sStr.indexOf("BALL_BG_COLOR_HEX") < 0 || sStr.indexOf("BALL_ICON_SIZE_DP") < 0 || sStr.indexOf("TOOLAPP_BACK_EDGE_WIDTH_DP") < 0 || sStr.indexOf("ENABLE_TOOLAPP_INNER_BACK_STRIPS") < 0 || sStr.indexOf("ENABLE_TOOLAPP_SCREEN_BACK_STRIPS") < 0 || sStr.indexOf("TOOLAPP_BACK_COMMIT_DISTANCE_DP") < 0 || sStr.indexOf("TOOLAPP_BACK_PROGRESS_DISTANCE_DP") < 0 || sStr.indexOf("LONG_PRESS_TRIGGERED_MOVE_SLOP_DP") < 0) {
|
if (sStr.indexOf("ENABLE_SNAP_TO_EDGE") < 0 || sStr.indexOf("ENABLE_ANIMATIONS") < 0 || sStr.indexOf("BALL_IDLE_ALPHA") < 0 || sStr.indexOf("PANEL_POS_GRAVITY") < 0 || sStr.indexOf("single_choice") < 0 || sStr.indexOf("ball_shortx_icon") < 0 || sStr.indexOf("ball_color") < 0 || sStr.indexOf("SETTINGS_THEME") < 0 || sStr.indexOf("BALL_BG_COLOR_HEX") < 0 || sStr.indexOf("BALL_ICON_SIZE_DP") < 0 || sStr.indexOf("TOOLAPP_BACK_GESTURE_MODE") < 0 || sStr.indexOf("TOOLAPP_BACK_EDGE_WIDTH_DP") < 0 || sStr.indexOf("TOOLAPP_BACK_COMMIT_DISTANCE_DP") < 0 || sStr.indexOf("TOOLAPP_BACK_SURFACE_SLOP_DP") < 0 || sStr.indexOf("TOOLAPP_BACK_PROGRESS_DISTANCE_DP") < 0 || sStr.indexOf("LONG_PRESS_TRIGGERED_MOVE_SLOP_DP") < 0) {
|
||||||
|
needReset = true;
|
||||||
|
}
|
||||||
|
if (!needReset && (sStr.indexOf("ENABLE_TOOLAPP_INNER_BACK_STRIPS") >= 0 || sStr.indexOf("ENABLE_TOOLAPP_SCREEN_BACK_STRIPS") >= 0)) {
|
||||||
needReset = true;
|
needReset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -923,10 +930,10 @@ var ConfigManager = {
|
|||||||
if (schemaItemDiffers("BALL_ICON_TINT_HEX", ["name", "type"]) ||
|
if (schemaItemDiffers("BALL_ICON_TINT_HEX", ["name", "type"]) ||
|
||||||
schemaItemDiffers("BALL_ICON_SIZE_DP", ["name", "type", "min", "max", "step"]) ||
|
schemaItemDiffers("BALL_ICON_SIZE_DP", ["name", "type", "min", "max", "step"]) ||
|
||||||
schemaItemDiffers("BALL_BG_COLOR_HEX", ["name", "type"]) ||
|
schemaItemDiffers("BALL_BG_COLOR_HEX", ["name", "type"]) ||
|
||||||
|
schemaItemDiffers("TOOLAPP_BACK_GESTURE_MODE", ["name", "type"]) ||
|
||||||
schemaItemDiffers("TOOLAPP_BACK_EDGE_WIDTH_DP", ["name", "type", "min", "max", "step"]) ||
|
schemaItemDiffers("TOOLAPP_BACK_EDGE_WIDTH_DP", ["name", "type", "min", "max", "step"]) ||
|
||||||
schemaItemDiffers("ENABLE_TOOLAPP_INNER_BACK_STRIPS", ["name", "type"]) ||
|
|
||||||
schemaItemDiffers("ENABLE_TOOLAPP_SCREEN_BACK_STRIPS", ["name", "type"]) ||
|
|
||||||
schemaItemDiffers("TOOLAPP_BACK_COMMIT_DISTANCE_DP", ["name", "type", "min", "max", "step"]) ||
|
schemaItemDiffers("TOOLAPP_BACK_COMMIT_DISTANCE_DP", ["name", "type", "min", "max", "step"]) ||
|
||||||
|
schemaItemDiffers("TOOLAPP_BACK_SURFACE_SLOP_DP", ["name", "type", "min", "max", "step"]) ||
|
||||||
schemaItemDiffers("TOOLAPP_BACK_PROGRESS_DISTANCE_DP", ["name", "type", "min", "max", "step"]) ||
|
schemaItemDiffers("TOOLAPP_BACK_PROGRESS_DISTANCE_DP", ["name", "type", "min", "max", "step"]) ||
|
||||||
schemaItemDiffers("LONG_PRESS_TRIGGERED_MOVE_SLOP_DP", ["name", "type", "min", "max", "step"])) {
|
schemaItemDiffers("LONG_PRESS_TRIGGERED_MOVE_SLOP_DP", ["name", "type", "min", "max", "step"])) {
|
||||||
needReset = true;
|
needReset = true;
|
||||||
@@ -1181,8 +1188,15 @@ function applyRule(rule, kv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =======================【日志:文件写入器(尽力落盘 + 自动清理旧日志)】=======================
|
// =======================【日志:文件写入器(尽力落盘 + 自动清理旧日志)】=======================
|
||||||
// =======================【日志:文件写入器(全局统一目录 + 分级)】=======================
|
function sanitizeLogMessage(msg) {
|
||||||
// 优化后的日志系统(带缓冲,减少文件 IO)
|
try {
|
||||||
|
var s = String(msg == null ? "" : msg);
|
||||||
|
s = s.replace(/(authorization\s*[:=]\s*bearer\s+)[^\s,;]+/ig, "$1[REDACTED]");
|
||||||
|
s = s.replace(/((access_)?token|api[_-]?key|password|passwd|secret)(\s*[=:]\s*)[^\s,;]+/ig, "$1$3[REDACTED]");
|
||||||
|
return s;
|
||||||
|
} catch (e) { return String(msg == null ? "" : msg); }
|
||||||
|
}
|
||||||
|
|
||||||
function ToolHubLogger(procInfo) {
|
function ToolHubLogger(procInfo) {
|
||||||
this.proc = procInfo || {};
|
this.proc = procInfo || {};
|
||||||
this.dir = PATH_LOG_DIR;
|
this.dir = PATH_LOG_DIR;
|
||||||
@@ -1192,17 +1206,10 @@ function ToolHubLogger(procInfo) {
|
|||||||
this.debug = false;
|
this.debug = false;
|
||||||
this.initOk = false;
|
this.initOk = false;
|
||||||
this.lastInitErr = "";
|
this.lastInitErr = "";
|
||||||
|
|
||||||
// 新增:日志缓冲
|
|
||||||
this._buffer = [];
|
|
||||||
this._bufferSize = 20; // 每 20 条写一次磁盘
|
|
||||||
this._flushTimer = null;
|
|
||||||
|
|
||||||
this._initOnce();
|
this._initOnce();
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolHubLogger.prototype._now = function() { return new Date().getTime(); };
|
ToolHubLogger.prototype._now = function() { return new Date().getTime(); };
|
||||||
|
|
||||||
ToolHubLogger.prototype._initOnce = function() {
|
ToolHubLogger.prototype._initOnce = function() {
|
||||||
try {
|
try {
|
||||||
if (FileIO.ensureDir(this.dir)) {
|
if (FileIO.ensureDir(this.dir)) {
|
||||||
@@ -1217,110 +1224,22 @@ ToolHubLogger.prototype._initOnce = function() {
|
|||||||
this.lastInitErr = String(e);
|
this.lastInitErr = String(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ToolHubLogger.prototype.updateConfig = function(cfg) {
|
ToolHubLogger.prototype.updateConfig = function(cfg) {
|
||||||
if (!cfg) return;
|
if (!cfg) return;
|
||||||
if (typeof cfg.LOG_KEEP_DAYS === "number") this.keepDays = cfg.LOG_KEEP_DAYS;
|
if (typeof cfg.LOG_KEEP_DAYS === "number") this.keepDays = cfg.LOG_KEEP_DAYS;
|
||||||
if (typeof cfg.LOG_ENABLE !== "undefined") this.enable = !!cfg.LOG_ENABLE;
|
if (typeof cfg.LOG_ENABLE !== "undefined") this.enable = !!cfg.LOG_ENABLE;
|
||||||
if (typeof cfg.LOG_DEBUG !== "undefined") this.debug = !!cfg.LOG_DEBUG;
|
if (typeof cfg.LOG_DEBUG !== "undefined") this.debug = !!cfg.LOG_DEBUG;
|
||||||
};
|
};
|
||||||
|
|
||||||
ToolHubLogger.prototype._line = function(level, msg) {
|
|
||||||
var ts = this._now();
|
|
||||||
var d = new Date(ts);
|
|
||||||
function pad2(x) { return (x < 10 ? "0" : "") + x; }
|
|
||||||
var t = d.getFullYear() + "-" + pad2(d.getMonth() + 1) + "-" + pad2(d.getDate()) +
|
|
||||||
" " + pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" + pad2(d.getSeconds());
|
|
||||||
return t + " [" + level + "] " + msg + "\n";
|
|
||||||
};
|
|
||||||
|
|
||||||
ToolHubLogger.prototype._scheduleFlush = function() {
|
|
||||||
if (this._flushTimer) try { this._flushTimer.cancel(); } catch(e) {}
|
|
||||||
var self = this;
|
|
||||||
this._flushTimer = new java.util.Timer();
|
|
||||||
this._flushTimer.schedule(new java.util.TimerTask({
|
|
||||||
run: function() { self._flushBuffer(); }
|
|
||||||
}), 3000); // 3秒后强制刷新
|
|
||||||
};
|
|
||||||
|
|
||||||
ToolHubLogger.prototype._flushBuffer = function() {
|
|
||||||
if (this._buffer.length === 0) return;
|
|
||||||
var content = this._buffer.join('');
|
|
||||||
this._buffer = [];
|
|
||||||
var path = this.dir + "/" + this.prefix + "_" + this._ymd() + ".log";
|
|
||||||
FileIO.appendText(path, content);
|
|
||||||
};
|
|
||||||
|
|
||||||
ToolHubLogger.prototype._ymd = function() {
|
ToolHubLogger.prototype._ymd = function() {
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
return "" + d.getFullYear() +
|
return "" + d.getFullYear() +
|
||||||
((d.getMonth() < 9 ? "0" : "") + (d.getMonth() + 1)) +
|
((d.getMonth() < 9 ? "0" : "") + (d.getMonth() + 1)) +
|
||||||
((d.getDate() < 10 ? "0" : "") + d.getDate());
|
((d.getDate() < 10 ? "0" : "") + d.getDate());
|
||||||
};
|
};
|
||||||
|
|
||||||
ToolHubLogger.prototype._write = function(level, msg) {
|
|
||||||
if (!this.enable) return false;
|
|
||||||
this._buffer.push(this._line(level, msg));
|
|
||||||
|
|
||||||
// 缓冲满或错误级别立即写入
|
|
||||||
if (this._buffer.length >= this._bufferSize || level === 'F' || level === 'E') {
|
|
||||||
this._flushBuffer();
|
|
||||||
} else {
|
|
||||||
this._scheduleFlush(); // 延迟写入
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
ToolHubLogger.prototype.d = function(msg) { if (this.debug) this._write("D", msg); };
|
|
||||||
ToolHubLogger.prototype.i = function(msg) { this._write("I", msg); };
|
|
||||||
ToolHubLogger.prototype.w = function(msg) { this._write("W", msg); };
|
|
||||||
ToolHubLogger.prototype.e = function(msg) { this._write("E", msg); };
|
|
||||||
ToolHubLogger.prototype.fatal = function(msg) { this._write("F", msg); this._flushBuffer(); };
|
|
||||||
|
|
||||||
ToolHubLogger.prototype.cleanupOldFiles = function() {
|
|
||||||
try {
|
|
||||||
if (!this.initOk) return false;
|
|
||||||
var dirF = new java.io.File(this.dir);
|
|
||||||
var files = dirF.listFiles();
|
|
||||||
if (!files) return false;
|
|
||||||
var now = this._now();
|
|
||||||
var cutoff = now - this.keepDays * 24 * 60 * 60 * 1000;
|
|
||||||
for (var i = 0; i < files.length; i++) {
|
|
||||||
var f = files[i];
|
|
||||||
if (f && f.isFile() && f.getName().indexOf(this.prefix) === 0 && f.lastModified() < cutoff) {
|
|
||||||
f["delete"]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (e) { return false; };
|
|
||||||
};
|
|
||||||
|
|
||||||
ToolHubLogger.prototype._filePathForToday = function() {
|
ToolHubLogger.prototype._filePathForToday = function() {
|
||||||
var name = this.prefix + "_" + this._ymd(this._now()) + ".log";
|
var name = this.prefix + "_" + this._ymd() + ".log";
|
||||||
return this.dir + "/" + name;
|
return this.dir + "/" + name;
|
||||||
};
|
};
|
||||||
ToolHubLogger.prototype._initOnce = function() {
|
|
||||||
try {
|
|
||||||
// # 尝试创建目录
|
|
||||||
if (FileIO.ensureDir(this.dir)) {
|
|
||||||
this.initOk = true;
|
|
||||||
// # 清理旧日志
|
|
||||||
this.cleanupOldFiles();
|
|
||||||
} else {
|
|
||||||
this.initOk = false;
|
|
||||||
this.lastInitErr = "Mkdirs failed: " + this.dir;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.initOk = false;
|
|
||||||
this.lastInitErr = String(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ToolHubLogger.prototype.updateConfig = function(cfg) {
|
|
||||||
if (!cfg) return;
|
|
||||||
if (typeof cfg.LOG_KEEP_DAYS === "number") this.keepDays = cfg.LOG_KEEP_DAYS;
|
|
||||||
if (typeof cfg.LOG_ENABLE !== "undefined") this.enable = !!cfg.LOG_ENABLE;
|
|
||||||
if (typeof cfg.LOG_DEBUG !== "undefined") this.debug = !!cfg.LOG_DEBUG;
|
|
||||||
};
|
|
||||||
ToolHubLogger.prototype._line = function(level, msg) {
|
ToolHubLogger.prototype._line = function(level, msg) {
|
||||||
var ts = this._now();
|
var ts = this._now();
|
||||||
var d = new Date(ts);
|
var d = new Date(ts);
|
||||||
@@ -1332,7 +1251,7 @@ ToolHubLogger.prototype._line = function(level, msg) {
|
|||||||
proc = " uid=" + String(this.proc.uid) + " pid=" + String(this.proc.pid) + " tid=" + String(this.proc.tid) +
|
proc = " uid=" + String(this.proc.uid) + " pid=" + String(this.proc.pid) + " tid=" + String(this.proc.tid) +
|
||||||
" th=" + String(this.proc.threadName) + " proc=" + String(this.proc.processName);
|
" th=" + String(this.proc.threadName) + " proc=" + String(this.proc.processName);
|
||||||
} catch (e0) {}
|
} catch (e0) {}
|
||||||
return t + " [" + String(level) + "] " + String(msg) + proc + "\n";
|
return t + " [" + String(level) + "] " + sanitizeLogMessage(msg) + proc + "\n";
|
||||||
};
|
};
|
||||||
ToolHubLogger.prototype._writeRaw = function(level, msg) {
|
ToolHubLogger.prototype._writeRaw = function(level, msg) {
|
||||||
if (!this.initOk) return false;
|
if (!this.initOk) return false;
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ function FloatBallAppWM(logger) {
|
|||||||
toolAppBackPreviewView: null,
|
toolAppBackPreviewView: null,
|
||||||
toolAppBackPreviewRoute: null,
|
toolAppBackPreviewRoute: null,
|
||||||
toolAppBackPreviewReady: false,
|
toolAppBackPreviewReady: false,
|
||||||
toolAppScreenBackStrips: [],
|
|
||||||
toolAppTitleView: null,
|
toolAppTitleView: null,
|
||||||
toolAppBackButton: null,
|
toolAppBackButton: null,
|
||||||
settingsGroupKey: null,
|
settingsGroupKey: null,
|
||||||
|
|||||||
@@ -288,7 +288,6 @@ FloatBallAppWM.prototype.applyImmediateEffectsForKey = function(k) {
|
|||||||
try {
|
try {
|
||||||
if (this.L) {
|
if (this.L) {
|
||||||
this.L.enable = !!this.config.LOG_ENABLE;
|
this.L.enable = !!this.config.LOG_ENABLE;
|
||||||
this.L.cfg.LOG_ENABLE = !!this.config.LOG_ENABLE;
|
|
||||||
this.L.i("apply LOG_ENABLE=" + String(this.config.LOG_ENABLE));
|
this.L.i("apply LOG_ENABLE=" + String(this.config.LOG_ENABLE));
|
||||||
}
|
}
|
||||||
} catch(eLE) { safeLog(null, 'e', "catch " + String(eLE)); }
|
} catch(eLE) { safeLog(null, 'e', "catch " + String(eLE)); }
|
||||||
@@ -298,7 +297,6 @@ FloatBallAppWM.prototype.applyImmediateEffectsForKey = function(k) {
|
|||||||
try {
|
try {
|
||||||
if (this.L) {
|
if (this.L) {
|
||||||
this.L.debug = !!this.config.LOG_DEBUG;
|
this.L.debug = !!this.config.LOG_DEBUG;
|
||||||
this.L.cfg.LOG_DEBUG = !!this.config.LOG_DEBUG;
|
|
||||||
this.L.i("apply LOG_DEBUG=" + String(this.config.LOG_DEBUG));
|
this.L.i("apply LOG_DEBUG=" + String(this.config.LOG_DEBUG));
|
||||||
}
|
}
|
||||||
} catch(eLD) { safeLog(null, 'e', "catch " + String(eLD)); }
|
} catch(eLD) { safeLog(null, 'e', "catch " + String(eLD)); }
|
||||||
@@ -310,7 +308,6 @@ FloatBallAppWM.prototype.applyImmediateEffectsForKey = function(k) {
|
|||||||
this.config.LOG_KEEP_DAYS = n;
|
this.config.LOG_KEEP_DAYS = n;
|
||||||
if (this.L) {
|
if (this.L) {
|
||||||
this.L.keepDays = n;
|
this.L.keepDays = n;
|
||||||
this.L.cfg.LOG_KEEP_DAYS = n;
|
|
||||||
this.L.i("apply LOG_KEEP_DAYS=" + String(n));
|
this.L.i("apply LOG_KEEP_DAYS=" + String(n));
|
||||||
this.L.cleanupOldFiles();
|
this.L.cleanupOldFiles();
|
||||||
}
|
}
|
||||||
@@ -319,30 +316,7 @@ FloatBallAppWM.prototype.applyImmediateEffectsForKey = function(k) {
|
|||||||
}
|
}
|
||||||
if (k === "BALL_SIZE_DP" || k === "BALL_PNG_MODE" || k === "BALL_ICON_TYPE" || k === "BALL_ICON_FILE_PATH" || k === "BALL_ICON_RES_ID" || k === "BALL_ICON_RES_NAME" || k === "BALL_ICON_SIZE_DP" || k === "BALL_ICON_TINT_HEX" || k === "BALL_BG_COLOR_HEX") { this.rebuildBallForNewSize(); return; }
|
if (k === "BALL_SIZE_DP" || k === "BALL_PNG_MODE" || k === "BALL_ICON_TYPE" || k === "BALL_ICON_FILE_PATH" || k === "BALL_ICON_RES_ID" || k === "BALL_ICON_RES_NAME" || k === "BALL_ICON_SIZE_DP" || k === "BALL_ICON_TINT_HEX" || k === "BALL_BG_COLOR_HEX") { this.rebuildBallForNewSize(); return; }
|
||||||
|
|
||||||
if (k === "TOOLAPP_BACK_EDGE_WIDTH_DP" || k === "ENABLE_TOOLAPP_INNER_BACK_STRIPS") {
|
if (k === "TOOLAPP_BACK_EDGE_WIDTH_DP") {
|
||||||
try {
|
|
||||||
if (this.state.toolAppActive) {
|
|
||||||
if (k === "TOOLAPP_BACK_EDGE_WIDTH_DP" && this.updateToolAppInnerBackEdgeWidth) {
|
|
||||||
this.updateToolAppInnerBackEdgeWidth();
|
|
||||||
} else if (this.showToolApp) {
|
|
||||||
this.showToolApp(this.state.toolAppRoute || "settings", false);
|
|
||||||
}
|
|
||||||
if (this.refreshToolAppScreenBackStrips) this.refreshToolAppScreenBackStrips();
|
|
||||||
}
|
|
||||||
} catch(eBackStrip) {
|
|
||||||
safeLog(this.L, "w", "apply back strip fail: " + String(eBackStrip));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k === "ENABLE_TOOLAPP_SCREEN_BACK_STRIPS") {
|
|
||||||
try {
|
|
||||||
if (this.state.toolAppActive && this.refreshToolAppScreenBackStrips) {
|
|
||||||
this.refreshToolAppScreenBackStrips();
|
|
||||||
}
|
|
||||||
} catch(eScreenBackStrip) {
|
|
||||||
safeLog(this.L, "w", "apply screen back strip fail: " + String(eScreenBackStrip));
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ FloatBallAppWM.prototype.safeRemoveView = function(v, whichName) {
|
|||||||
try {
|
try {
|
||||||
if (!v) return { ok: true, skipped: true };
|
if (!v) return { ok: true, skipped: true };
|
||||||
try { if (this.unregisterPanelPredictiveBack) this.unregisterPanelPredictiveBack(v); } catch (eBack) {}
|
try { if (this.unregisterPanelPredictiveBack) this.unregisterPanelPredictiveBack(v); } catch (eBack) {}
|
||||||
try { if (whichName === "viewerPanel" && this.state && String(this.state.viewerPanelType || "") === "tool_app" && this.hideToolAppScreenBackStrips) this.hideToolAppScreenBackStrips(); } catch (eStrip) {}
|
|
||||||
this.state.wm.removeView(v);
|
this.state.wm.removeView(v);
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -196,7 +195,6 @@ FloatBallAppWM.prototype.hideViewerPanel = function() {
|
|||||||
this.state.toolAppBackPreviewView = null;
|
this.state.toolAppBackPreviewView = null;
|
||||||
this.state.toolAppBackPreviewRoute = null;
|
this.state.toolAppBackPreviewRoute = null;
|
||||||
this.state.toolAppBackPreviewReady = false;
|
this.state.toolAppBackPreviewReady = false;
|
||||||
try { if (this.hideToolAppScreenBackStrips) this.hideToolAppScreenBackStrips(); } catch (eStrip) {}
|
|
||||||
this.state.toolAppTitleView = null;
|
this.state.toolAppTitleView = null;
|
||||||
this.state.toolAppBackButton = null;
|
this.state.toolAppBackButton = null;
|
||||||
}
|
}
|
||||||
@@ -608,7 +606,6 @@ FloatBallAppWM.prototype._clearHeavyCachesIfAllHidden = function(reason) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
FloatBallAppWM.prototype.hideAllPanels = function() {
|
FloatBallAppWM.prototype.hideAllPanels = function() {
|
||||||
try { if (this.hideToolAppScreenBackStrips) this.hideToolAppScreenBackStrips(); } catch (eStrip) {}
|
|
||||||
this.hideMainPanel();
|
this.hideMainPanel();
|
||||||
this.hideSettingsPanel();
|
this.hideSettingsPanel();
|
||||||
this.hideViewerPanel();
|
this.hideViewerPanel();
|
||||||
@@ -995,10 +992,6 @@ FloatBallAppWM.prototype.onScreenChangedReflow = function(reason) {
|
|||||||
try { this.state.wm.updateViewLayout(this.state.ballRoot, this.state.ballLp); } catch(eU) { safeLog(null, 'e', "catch " + String(eU)); }
|
try { this.state.wm.updateViewLayout(this.state.ballRoot, this.state.ballLp); } catch(eU) { safeLog(null, 'e', "catch " + String(eU)); }
|
||||||
this.savePos(this.state.ballLp.x, this.state.ballLp.y);
|
this.savePos(this.state.ballLp.x, this.state.ballLp.y);
|
||||||
|
|
||||||
if (this.state.toolAppActive && this.refreshToolAppScreenBackStrips) {
|
|
||||||
try { this.refreshToolAppScreenBackStrips(); } catch(eBackStrip) { safeLog(this.L, 'w', "screen reflow refresh tool app back strips fail: " + String(eBackStrip)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
safeLog(this.L, 'i',
|
safeLog(this.L, 'i',
|
||||||
"screen reflow reason=" + String(reason || "") +
|
"screen reflow reason=" + String(reason || "") +
|
||||||
" old=" + oldW + "x" + oldH +
|
" old=" + oldW + "x" + oldH +
|
||||||
|
|||||||
@@ -21,24 +21,23 @@ FloatBallAppWM.prototype.execButtonAction = function(btn, idx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (t === "open_viewer") {
|
if (t === "open_viewer") {
|
||||||
var logPath = (this.L && this.L._filePathForToday) ? this.L._filePathForToday() : "";
|
function tailLogText(path, maxLen) {
|
||||||
if (!logPath) logPath = PATH_LOG_DIR + "/ShortX_ToolHub_" + (new java.text.SimpleDateFormat("yyyyMMdd").format(new java.util.Date())) + ".log";
|
var txt = FileIO.readText(path);
|
||||||
|
if (!txt) return "(日志文件不存在或为空: " + path + ")";
|
||||||
var content = FileIO.readText(logPath);
|
txt = String(txt);
|
||||||
if (!content) content = "(日志文件不存在或为空: " + logPath + ")";
|
if (txt.length > maxLen) txt = "[...前略...]\n" + txt.substring(txt.length - maxLen);
|
||||||
|
|
||||||
if (content.length > 30000) {
|
|
||||||
content = "[...前略...]\n" + content.substring(content.length - 30000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 简单的按行倒序,方便查看最新日志
|
|
||||||
try {
|
try {
|
||||||
var lines = content.split("\n");
|
var lines = txt.split("\n");
|
||||||
if (lines.length > 1) {
|
if (lines.length > 1) txt = lines.reverse().join("\n");
|
||||||
content = lines.reverse().join("\n");
|
|
||||||
}
|
|
||||||
} catch(eRev) { safeLog(null, 'e', "catch " + String(eRev)); }
|
} catch(eRev) { safeLog(null, 'e', "catch " + String(eRev)); }
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
|
var runLogPath = (this.L && this.L._filePathForToday) ? this.L._filePathForToday() : "";
|
||||||
|
if (!runLogPath) runLogPath = PATH_LOG_DIR + "/ShortX_ToolHub_" + (new java.text.SimpleDateFormat("yyyyMMdd").format(new java.util.Date())) + ".log";
|
||||||
|
var initLogPath = PATH_LOG_DIR + "/init.log";
|
||||||
|
var content = "【启动/更新日志】\n" + tailLogText(initLogPath, 15000) +
|
||||||
|
"\n\n【运行日志】\n" + tailLogText(runLogPath, 15000);
|
||||||
|
if (content.length > 32000) content = content.substring(0, 32000) + "\n[...后略...]";
|
||||||
this.showViewerPanel("今日日志 (倒序)", content);
|
this.showViewerPanel("今日日志 (倒序)", content);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -132,7 +131,7 @@ return;
|
|||||||
if (r && r.ok) return;
|
if (r && r.ok) return;
|
||||||
|
|
||||||
this.toast("shell 广播桥发送失败");
|
this.toast("shell 广播桥发送失败");
|
||||||
safeLog(this.L, 'e', "shell all failed cmd_b64=" + cmdB64 + " ret=" + JSON.stringify(r || {}));
|
safeLog(this.L, 'e', "shell all failed cmd_b64_len=" + String(cmdB64 ? cmdB64.length : 0) + " ret=" + JSON.stringify(r || {}));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
558
code/th_14_color_picker.js
Normal file
558
code/th_14_color_picker.js
Normal file
@@ -0,0 +1,558 @@
|
|||||||
|
// ToolHub - 颜色选择器弹窗模块
|
||||||
|
// 依赖:th_14_panels.js 中的 showPopupOverlay()、th_04_theme.js 主题工具、th_06_icon_parser.js 图标解析。
|
||||||
|
|
||||||
|
FloatBallAppWM.prototype.showColorPickerPopup = function(opts) {
|
||||||
|
var self = this;
|
||||||
|
var opt = opts || {};
|
||||||
|
var currentColor = String(opt.currentColor || "");
|
||||||
|
var currentIconName = String(opt.currentIconName || "");
|
||||||
|
var onSelect = (typeof opt.onSelect === "function") ? opt.onSelect : null;
|
||||||
|
var onDismiss = (typeof opt.onDismiss === "function") ? opt.onDismiss : null;
|
||||||
|
|
||||||
|
var PT = this.getIslandPickerTheme ? this.getIslandPickerTheme() : null;
|
||||||
|
var isDark = PT ? PT.isDark : this.isDarkTheme();
|
||||||
|
var C = this.ui.colors;
|
||||||
|
var T = PT ? PT.T : this.getAnimalIslandTheme();
|
||||||
|
var textColor = PT ? PT.text : (isDark ? C.textPriDark : C.textPriLight);
|
||||||
|
var subTextColor = PT ? PT.sub : (isDark ? C.textSecDark : C.textSecLight);
|
||||||
|
|
||||||
|
function getThemeTintHex() {
|
||||||
|
try {
|
||||||
|
if (self.ui.colors && self.ui.colors.accent) {
|
||||||
|
var c = self.ui.colors.accent;
|
||||||
|
return "#" + ("00000000" + (c >>> 0).toString(16)).slice(-8);
|
||||||
|
}
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
return "#FF4081";
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildArgbHex(alphaByte, rgbHex) {
|
||||||
|
var a = ("00" + (Math.max(0, Math.min(255, Number(alphaByte || 0))) >>> 0).toString(16)).slice(-2);
|
||||||
|
var rgb = String(rgbHex || "000000").replace(/^#/, "");
|
||||||
|
if (rgb.length === 3) rgb = rgb.split("").map(function(c){ return c+c; }).join("");
|
||||||
|
if (rgb.length > 6) rgb = rgb.slice(-6);
|
||||||
|
while (rgb.length < 6) rgb = "0" + rgb;
|
||||||
|
return "#" + a + rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractTintRgbHex(hex) {
|
||||||
|
var h = String(hex || "").replace(/^#/, "");
|
||||||
|
if (h.length >= 8) return h.slice(-6);
|
||||||
|
if (h.length === 6) return h;
|
||||||
|
if (h.length === 3) return h.split("").map(function(c){ return c+c; }).join("");
|
||||||
|
return "000000";
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractTintAlphaByte(hex) {
|
||||||
|
var h = String(hex || "").replace(/^#/, "");
|
||||||
|
if (h.length >= 8) return parseInt(h.slice(0, 2), 16);
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeTintColorValue(val) {
|
||||||
|
var s = String(val || "").trim();
|
||||||
|
if (!s) return "";
|
||||||
|
if (s.charAt(0) === "#") s = s.substring(1);
|
||||||
|
if (/^[0-9A-Fa-f]{1,8}$/.test(s)) {
|
||||||
|
while (s.length < 6) s = "0" + s;
|
||||||
|
if (s.length === 6) s = "FF" + s;
|
||||||
|
else if (s.length > 8) s = s.substring(0, 8);
|
||||||
|
return "#" + s.toUpperCase();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
var commonTintHexValues = [
|
||||||
|
"#FFFF0000", "#FFFF5722", "#FFFF9800", "#FFFFC107", "#FFFFEB3B",
|
||||||
|
"#FFCDDC39", "#FF8BC34A", "#FF4CAF50", "#FF009688", "#FF00BCD4",
|
||||||
|
"#FF03A9F4", "#FF2196F3", "#FF3F51B5", "#FF673AB7", "#FF9C27B0",
|
||||||
|
"#FFE91E63", "#FF795548", "#FF9E9E9E", "#FF607D8B", "#FF000000", "#FFFFFFFF"
|
||||||
|
];
|
||||||
|
|
||||||
|
// ========== 最近使用颜色 ==========
|
||||||
|
var RECENT_COLORS_KEY = "color_picker_recent";
|
||||||
|
var MAX_RECENT_COLORS = 8;
|
||||||
|
var recentColors = [];
|
||||||
|
try {
|
||||||
|
var recentSaved = self.loadPanelState(RECENT_COLORS_KEY);
|
||||||
|
if (recentSaved && recentSaved.colors && recentSaved.colors.length) {
|
||||||
|
var rc;
|
||||||
|
for (rc = 0; rc < recentSaved.colors.length && rc < MAX_RECENT_COLORS; rc++) {
|
||||||
|
var rn = normalizeTintColorValue(recentSaved.colors[rc], false);
|
||||||
|
if (rn) recentColors.push(rn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(eRecentLoad) { safeLog(null, 'e', "catch " + String(eRecentLoad)); }
|
||||||
|
|
||||||
|
function saveRecentColors() {
|
||||||
|
try {
|
||||||
|
self.savePanelState(RECENT_COLORS_KEY, { colors: recentColors.slice(0, MAX_RECENT_COLORS) });
|
||||||
|
} catch(eRecentSave) { safeLog(null, 'e', "catch " + String(eRecentSave)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushRecentColor(hex) {
|
||||||
|
var normalized = normalizeTintColorValue(hex, false);
|
||||||
|
if (!normalized) return;
|
||||||
|
var next = [normalized];
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < recentColors.length; i++) {
|
||||||
|
if (recentColors[i] !== normalized) {
|
||||||
|
next.push(recentColors[i]);
|
||||||
|
}
|
||||||
|
if (next.length >= MAX_RECENT_COLORS) break;
|
||||||
|
}
|
||||||
|
recentColors = next;
|
||||||
|
saveRecentColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedColor = currentColor;
|
||||||
|
var isFollowTheme = !currentColor;
|
||||||
|
var currentBaseRgbHex = extractTintRgbHex(currentColor);
|
||||||
|
var currentAlphaByte = extractTintAlphaByte(currentColor);
|
||||||
|
var alphaSeek = null;
|
||||||
|
var alphaValTv = null;
|
||||||
|
var updatePreviewFn = function() {};
|
||||||
|
var updateValueTvFn = function() {};
|
||||||
|
var refreshRecentGridFn = function() {};
|
||||||
|
var refreshCommonGridFn = function() {};
|
||||||
|
var syncRgbSeeksFn = function() {};
|
||||||
|
|
||||||
|
// 操作按钮:对齐设置页/按钮管理页的 chip + 主按钮视觉。
|
||||||
|
function createColorPanelActionButton(label, primary, onClick) {
|
||||||
|
var b = new android.widget.TextView(context);
|
||||||
|
b.setText(label);
|
||||||
|
b.setGravity(android.view.Gravity.CENTER);
|
||||||
|
b.setSingleLine(true);
|
||||||
|
b.setTypeface(null, android.graphics.Typeface.BOLD);
|
||||||
|
try { b.setIncludeFontPadding(false); } catch(eFontPad) {}
|
||||||
|
if (primary) {
|
||||||
|
b.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 15);
|
||||||
|
b.setTextColor(android.graphics.Color.WHITE);
|
||||||
|
b.setPadding(self.dp(18), 0, self.dp(18), 0);
|
||||||
|
try { b.setMinHeight(self.dp(52)); } catch(eMinH1) {}
|
||||||
|
try { b.setBackground(self.ui.createStrokeDrawable(T.primaryDeep, self.withAlpha(T.brown || T.primaryDeep, isDark ? 0.28 : 0.18), self.dp(1), self.dp(26))); } catch(eBg1) {}
|
||||||
|
try { b.setElevation(self.dp(1)); } catch(eElev) {}
|
||||||
|
} else {
|
||||||
|
b.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 15);
|
||||||
|
b.setTextColor(T.brown || T.sub);
|
||||||
|
b.setPadding(self.dp(16), 0, self.dp(16), 0);
|
||||||
|
try { b.setMinHeight(self.dp(52)); } catch(eMinH2) {}
|
||||||
|
try { b.setBackground(self.ui.createStrokeDrawable(T.card2 || T.card, self.withAlpha(T.stroke || T.brown, isDark ? 0.42 : 0.55), self.dp(1), self.dp(26))); } catch(eBg2) {}
|
||||||
|
try { b.setElevation(self.dp(1)); } catch(eElev2) {}
|
||||||
|
}
|
||||||
|
try { b.setClickable(true); b.setFocusable(true); } catch(eClickable) {}
|
||||||
|
b.setOnClickListener(new android.view.View.OnClickListener({
|
||||||
|
onClick: function(v) {
|
||||||
|
self.touchActivity();
|
||||||
|
try { if (onClick) onClick(v); } catch(eBtn) { safeLog(self.L, 'e', "color panel action err=" + String(eBtn)); }
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
var popupResult = self.showPopupOverlay({
|
||||||
|
title: "换颜色",
|
||||||
|
onDismiss: onDismiss,
|
||||||
|
builder: function(content, closePopup) {
|
||||||
|
// 图标预览区
|
||||||
|
var previewRow = new android.widget.LinearLayout(context);
|
||||||
|
previewRow.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
previewRow.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
previewRow.setPadding(self.dp(12), self.dp(10), self.dp(12), self.dp(10));
|
||||||
|
previewRow.setBackground(self.ui.createStrokeDrawable(T.primarySoft, self.withAlpha(T.primaryDeep, isDark ? 0.24 : 0.18), self.dp(1), self.dp(18)));
|
||||||
|
|
||||||
|
var previewIv = new android.widget.ImageView(context);
|
||||||
|
previewIv.setLayoutParams(new android.widget.LinearLayout.LayoutParams(self.dp(48), self.dp(48)));
|
||||||
|
previewIv.setScaleType(android.widget.ImageView.ScaleType.FIT_CENTER);
|
||||||
|
previewRow.addView(previewIv);
|
||||||
|
|
||||||
|
var previewLabel = new android.widget.TextView(context);
|
||||||
|
previewLabel.setText("小图标试衣间");
|
||||||
|
previewLabel.setTextColor(subTextColor);
|
||||||
|
previewLabel.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 12);
|
||||||
|
previewLabel.setPadding(self.dp(12), 0, 0, 0);
|
||||||
|
previewRow.addView(previewLabel);
|
||||||
|
|
||||||
|
content.addView(previewRow);
|
||||||
|
|
||||||
|
function updatePreview() {
|
||||||
|
try {
|
||||||
|
var dr = null;
|
||||||
|
if (currentIconName) {
|
||||||
|
try { dr = self.getShortXIconDrawable(currentIconName); } catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
}
|
||||||
|
if (dr) {
|
||||||
|
if (!isFollowTheme && selectedColor) {
|
||||||
|
try {
|
||||||
|
var parsed = android.graphics.Color.parseColor(selectedColor);
|
||||||
|
dr.setColorFilter(parsed, android.graphics.PorterDuff.Mode.SRC_IN);
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
} else {
|
||||||
|
try { dr.clearColorFilter(); } catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
}
|
||||||
|
previewIv.setImageDrawable(dr);
|
||||||
|
} else {
|
||||||
|
previewIv.setImageDrawable(null);
|
||||||
|
}
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
}
|
||||||
|
updatePreviewFn = updatePreview;
|
||||||
|
updatePreview();
|
||||||
|
|
||||||
|
// ========== 最近使用颜色 ==========
|
||||||
|
var recentTitle = new android.widget.TextView(context);
|
||||||
|
recentTitle.setText("最近用过的小颜色");
|
||||||
|
recentTitle.setTextColor(subTextColor);
|
||||||
|
recentTitle.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 12);
|
||||||
|
recentTitle.setPadding(self.dp(12), self.dp(8), self.dp(12), self.dp(4));
|
||||||
|
content.addView(recentTitle);
|
||||||
|
|
||||||
|
var recentGrid = new android.widget.GridLayout(context);
|
||||||
|
recentGrid.setColumnCount(8);
|
||||||
|
recentGrid.setPadding(self.dp(8), self.dp(4), self.dp(8), self.dp(4));
|
||||||
|
content.addView(recentGrid);
|
||||||
|
|
||||||
|
var recentEmptyTv = new android.widget.TextView(context);
|
||||||
|
recentEmptyTv.setText("还没有最近颜色");
|
||||||
|
recentEmptyTv.setTextColor(subTextColor);
|
||||||
|
recentEmptyTv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 11);
|
||||||
|
recentEmptyTv.setPadding(self.dp(12), self.dp(4), self.dp(12), self.dp(8));
|
||||||
|
recentEmptyTv.setVisibility(android.view.View.GONE);
|
||||||
|
content.addView(recentEmptyTv);
|
||||||
|
|
||||||
|
function refreshRecentGrid() {
|
||||||
|
try {
|
||||||
|
recentGrid.removeAllViews();
|
||||||
|
if (!recentColors.length) {
|
||||||
|
recentEmptyTv.setVisibility(android.view.View.VISIBLE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
recentEmptyTv.setVisibility(android.view.View.GONE);
|
||||||
|
var ri;
|
||||||
|
for (ri = 0; ri < recentColors.length && ri < MAX_RECENT_COLORS; ri++) {
|
||||||
|
(function(hex) {
|
||||||
|
var cell = new android.widget.FrameLayout(context);
|
||||||
|
var margin = self.dp(3);
|
||||||
|
try {
|
||||||
|
var lp = new android.widget.GridLayout.LayoutParams();
|
||||||
|
lp.width = self.dp(28);
|
||||||
|
lp.height = self.dp(28);
|
||||||
|
lp.setMargins(margin, margin, margin, margin);
|
||||||
|
cell.setLayoutParams(lp);
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
|
||||||
|
var swatch = new android.view.View(context);
|
||||||
|
swatch.setLayoutParams(new android.widget.FrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams.MATCH_PARENT, android.widget.FrameLayout.LayoutParams.MATCH_PARENT));
|
||||||
|
try {
|
||||||
|
var bg = new android.graphics.drawable.GradientDrawable();
|
||||||
|
bg.setColor(android.graphics.Color.parseColor(hex));
|
||||||
|
bg.setCornerRadius(self.dp(5));
|
||||||
|
swatch.setBackground(bg);
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
cell.addView(swatch);
|
||||||
|
|
||||||
|
if (selectedColor === hex) {
|
||||||
|
try {
|
||||||
|
var border = new android.graphics.drawable.GradientDrawable();
|
||||||
|
border.setColor(android.graphics.Color.TRANSPARENT);
|
||||||
|
border.setCornerRadius(self.dp(5));
|
||||||
|
border.setStroke(self.dp(2), T.primaryDeep);
|
||||||
|
cell.setForeground(border);
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.setOnClickListener(new android.view.View.OnClickListener({
|
||||||
|
onClick: function() {
|
||||||
|
self.touchActivity();
|
||||||
|
isFollowTheme = false;
|
||||||
|
selectedColor = hex;
|
||||||
|
currentBaseRgbHex = extractTintRgbHex(hex);
|
||||||
|
currentAlphaByte = extractTintAlphaByte(hex);
|
||||||
|
updatePreview();
|
||||||
|
updateValueTv();
|
||||||
|
refreshRecentGrid();
|
||||||
|
refreshCommonGrid();
|
||||||
|
syncRgbSeeks();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
recentGrid.addView(cell);
|
||||||
|
})(recentColors[ri]);
|
||||||
|
}
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
}
|
||||||
|
refreshRecentGridFn = refreshRecentGrid;
|
||||||
|
refreshRecentGrid();
|
||||||
|
|
||||||
|
// 21 色常用颜色
|
||||||
|
var commonTitle = new android.widget.TextView(context);
|
||||||
|
commonTitle.setText("糖果常用色");
|
||||||
|
commonTitle.setTextColor(subTextColor);
|
||||||
|
commonTitle.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 12);
|
||||||
|
commonTitle.setPadding(self.dp(12), self.dp(8), self.dp(12), self.dp(4));
|
||||||
|
content.addView(commonTitle);
|
||||||
|
|
||||||
|
var commonGrid = new android.widget.GridLayout(context);
|
||||||
|
commonGrid.setColumnCount(7);
|
||||||
|
commonGrid.setPadding(self.dp(8), self.dp(4), self.dp(8), self.dp(8));
|
||||||
|
var ci;
|
||||||
|
for (ci = 0; ci < commonTintHexValues.length; ci++) {
|
||||||
|
(function(hex) {
|
||||||
|
var cell = new android.widget.FrameLayout(context);
|
||||||
|
var margin = self.dp(4);
|
||||||
|
try {
|
||||||
|
var lp = new android.widget.GridLayout.LayoutParams();
|
||||||
|
lp.width = self.dp(32);
|
||||||
|
lp.height = self.dp(32);
|
||||||
|
lp.setMargins(margin, margin, margin, margin);
|
||||||
|
cell.setLayoutParams(lp);
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
|
||||||
|
var swatch = new android.view.View(context);
|
||||||
|
swatch.setLayoutParams(new android.widget.FrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams.MATCH_PARENT, android.widget.FrameLayout.LayoutParams.MATCH_PARENT));
|
||||||
|
try {
|
||||||
|
var bg = new android.graphics.drawable.GradientDrawable();
|
||||||
|
bg.setColor(android.graphics.Color.parseColor(hex));
|
||||||
|
bg.setCornerRadius(self.dp(6));
|
||||||
|
swatch.setBackground(bg);
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
cell.addView(swatch);
|
||||||
|
|
||||||
|
if (selectedColor === hex) {
|
||||||
|
try {
|
||||||
|
var border = new android.graphics.drawable.GradientDrawable();
|
||||||
|
border.setColor(android.graphics.Color.TRANSPARENT);
|
||||||
|
border.setCornerRadius(self.dp(6));
|
||||||
|
border.setStroke(self.dp(3), T.primaryDeep);
|
||||||
|
cell.setForeground(border);
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.setOnClickListener(new android.view.View.OnClickListener({
|
||||||
|
onClick: function() {
|
||||||
|
self.touchActivity();
|
||||||
|
isFollowTheme = false;
|
||||||
|
selectedColor = hex;
|
||||||
|
currentBaseRgbHex = extractTintRgbHex(hex);
|
||||||
|
currentAlphaByte = extractTintAlphaByte(hex);
|
||||||
|
updatePreview();
|
||||||
|
updateValueTv();
|
||||||
|
refreshRecentGrid();
|
||||||
|
refreshCommonGrid();
|
||||||
|
syncRgbSeeks();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
commonGrid.addView(cell);
|
||||||
|
})(commonTintHexValues[ci]);
|
||||||
|
}
|
||||||
|
content.addView(commonGrid);
|
||||||
|
|
||||||
|
function refreshCommonGrid() {
|
||||||
|
try {
|
||||||
|
var count = commonGrid.getChildCount();
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
var cell = commonGrid.getChildAt(i);
|
||||||
|
if (!cell) continue;
|
||||||
|
try { cell.setForeground(null); } catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
}
|
||||||
|
var idx = commonTintHexValues.indexOf(selectedColor);
|
||||||
|
if (idx >= 0 && idx < count) {
|
||||||
|
var matchedCell = commonGrid.getChildAt(idx);
|
||||||
|
if (matchedCell) {
|
||||||
|
try {
|
||||||
|
var border = new android.graphics.drawable.GradientDrawable();
|
||||||
|
border.setColor(android.graphics.Color.TRANSPARENT);
|
||||||
|
border.setCornerRadius(self.dp(6));
|
||||||
|
border.setStroke(self.dp(3), T.primaryDeep);
|
||||||
|
matchedCell.setForeground(border);
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
}
|
||||||
|
refreshCommonGridFn = refreshCommonGrid;
|
||||||
|
|
||||||
|
// 颜色值显示
|
||||||
|
var valueTv = new android.widget.TextView(context);
|
||||||
|
valueTv.setTextColor(textColor);
|
||||||
|
valueTv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 13);
|
||||||
|
valueTv.setPadding(self.dp(12), self.dp(4), self.dp(12), self.dp(4));
|
||||||
|
content.addView(valueTv);
|
||||||
|
|
||||||
|
function updateValueTv() {
|
||||||
|
valueTv.setText(isFollowTheme ? "当前:跟随岛屿主题" : ("当前:" + (selectedColor || "无")));
|
||||||
|
}
|
||||||
|
updateValueTvFn = updateValueTv;
|
||||||
|
updateValueTv();
|
||||||
|
|
||||||
|
// RGB 滑块
|
||||||
|
var rgbLabels = ["R", "G", "B"];
|
||||||
|
var rgbSeeks = [];
|
||||||
|
var rgbValTvs = [];
|
||||||
|
var ri;
|
||||||
|
for (ri = 0; ri < 3; ri++) {
|
||||||
|
(function(idx) {
|
||||||
|
var row = new android.widget.LinearLayout(context);
|
||||||
|
row.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
row.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
row.setPadding(self.dp(12), self.dp(4), self.dp(12), self.dp(4));
|
||||||
|
|
||||||
|
var label = new android.widget.TextView(context);
|
||||||
|
label.setText(rgbLabels[idx]);
|
||||||
|
label.setTextColor(textColor);
|
||||||
|
label.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 12);
|
||||||
|
label.setMinWidth(self.dp(20));
|
||||||
|
row.addView(label);
|
||||||
|
|
||||||
|
var seek = new android.widget.SeekBar(context);
|
||||||
|
seek.setMax(255);
|
||||||
|
var seekLp = new android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 1);
|
||||||
|
seekLp.setMargins(self.dp(8), 0, self.dp(8), 0);
|
||||||
|
seek.setLayoutParams(seekLp);
|
||||||
|
row.addView(seek);
|
||||||
|
rgbSeeks.push(seek);
|
||||||
|
|
||||||
|
var valTv = new android.widget.TextView(context);
|
||||||
|
valTv.setTextColor(subTextColor);
|
||||||
|
valTv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 11);
|
||||||
|
valTv.setMinWidth(self.dp(28));
|
||||||
|
row.addView(valTv);
|
||||||
|
rgbValTvs.push(valTv);
|
||||||
|
|
||||||
|
seek.setOnSeekBarChangeListener(new android.widget.SeekBar.OnSeekBarChangeListener({
|
||||||
|
onProgressChanged: function(s, progress, fromUser) {
|
||||||
|
if (!fromUser) return;
|
||||||
|
valTv.setText(String(progress));
|
||||||
|
var r = rgbSeeks[0].getProgress();
|
||||||
|
var g = rgbSeeks[1].getProgress();
|
||||||
|
var b = rgbSeeks[2].getProgress();
|
||||||
|
var hex = ("00" + (r >>> 0).toString(16)).slice(-2) + ("00" + (g >>> 0).toString(16)).slice(-2) + ("00" + (b >>> 0).toString(16)).slice(-2);
|
||||||
|
currentBaseRgbHex = hex;
|
||||||
|
isFollowTheme = false;
|
||||||
|
selectedColor = buildArgbHex(currentAlphaByte, currentBaseRgbHex);
|
||||||
|
updatePreview();
|
||||||
|
updateValueTv();
|
||||||
|
refreshRecentGrid();
|
||||||
|
refreshCommonGrid();
|
||||||
|
},
|
||||||
|
onStartTrackingTouch: function() {},
|
||||||
|
onStopTrackingTouch: function() {}
|
||||||
|
}));
|
||||||
|
|
||||||
|
content.addView(row);
|
||||||
|
})(ri);
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncRgbSeeks() {
|
||||||
|
try {
|
||||||
|
var initR = parseInt(currentBaseRgbHex.slice(0, 2), 16) || 0;
|
||||||
|
var initG = parseInt(currentBaseRgbHex.slice(2, 4), 16) || 0;
|
||||||
|
var initB = parseInt(currentBaseRgbHex.slice(4, 6), 16) || 0;
|
||||||
|
rgbSeeks[0].setProgress(initR);
|
||||||
|
rgbSeeks[1].setProgress(initG);
|
||||||
|
rgbSeeks[2].setProgress(initB);
|
||||||
|
rgbValTvs[0].setText(String(initR));
|
||||||
|
rgbValTvs[1].setText(String(initG));
|
||||||
|
rgbValTvs[2].setText(String(initB));
|
||||||
|
} catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
}
|
||||||
|
syncRgbSeeksFn = syncRgbSeeks;
|
||||||
|
syncRgbSeeks();
|
||||||
|
|
||||||
|
// 透明度滑块
|
||||||
|
var alphaRow = new android.widget.LinearLayout(context);
|
||||||
|
alphaRow.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
alphaRow.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
alphaRow.setPadding(self.dp(12), self.dp(4), self.dp(12), self.dp(8));
|
||||||
|
|
||||||
|
var alphaLabel = new android.widget.TextView(context);
|
||||||
|
alphaLabel.setText("A");
|
||||||
|
alphaLabel.setTextColor(textColor);
|
||||||
|
alphaLabel.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 12);
|
||||||
|
alphaLabel.setMinWidth(self.dp(20));
|
||||||
|
alphaRow.addView(alphaLabel);
|
||||||
|
|
||||||
|
alphaSeek = new android.widget.SeekBar(context);
|
||||||
|
alphaSeek.setMax(255);
|
||||||
|
var alphaSeekLp = new android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 1);
|
||||||
|
alphaSeekLp.setMargins(self.dp(8), 0, self.dp(8), 0);
|
||||||
|
alphaSeek.setLayoutParams(alphaSeekLp);
|
||||||
|
alphaRow.addView(alphaSeek);
|
||||||
|
|
||||||
|
alphaValTv = new android.widget.TextView(context);
|
||||||
|
alphaValTv.setTextColor(subTextColor);
|
||||||
|
alphaValTv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 11);
|
||||||
|
alphaValTv.setMinWidth(self.dp(28));
|
||||||
|
alphaRow.addView(alphaValTv);
|
||||||
|
|
||||||
|
alphaSeek.setOnSeekBarChangeListener(new android.widget.SeekBar.OnSeekBarChangeListener({
|
||||||
|
onProgressChanged: function(s, progress, fromUser) {
|
||||||
|
if (!fromUser) return;
|
||||||
|
alphaValTv.setText(String(progress));
|
||||||
|
currentAlphaByte = progress;
|
||||||
|
isFollowTheme = false;
|
||||||
|
selectedColor = buildArgbHex(currentAlphaByte, currentBaseRgbHex);
|
||||||
|
updatePreview();
|
||||||
|
updateValueTv();
|
||||||
|
refreshRecentGrid();
|
||||||
|
refreshCommonGrid();
|
||||||
|
},
|
||||||
|
onStartTrackingTouch: function() {},
|
||||||
|
onStopTrackingTouch: function() {}
|
||||||
|
}));
|
||||||
|
|
||||||
|
alphaSeek.setProgress(currentAlphaByte);
|
||||||
|
alphaValTv.setText(String(currentAlphaByte));
|
||||||
|
content.addView(alphaRow);
|
||||||
|
|
||||||
|
// 底部操作按钮放到 showPopupOverlay 的固定 footer 中,避免默认首屏看不到。
|
||||||
|
},
|
||||||
|
footerBuilder: function(footer, closePopup) {
|
||||||
|
var actionRow = new android.widget.LinearLayout(context);
|
||||||
|
actionRow.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
actionRow.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
actionRow.setPadding(self.dp(10), self.dp(6), self.dp(10), self.dp(4));
|
||||||
|
|
||||||
|
var btnClear = createColorPanelActionButton("恢复默认", false, function() {
|
||||||
|
isFollowTheme = true;
|
||||||
|
selectedColor = "";
|
||||||
|
currentAlphaByte = 255;
|
||||||
|
try { updatePreviewFn(); } catch(eUp) {}
|
||||||
|
try { updateValueTvFn(); } catch(eVal) {}
|
||||||
|
try { refreshRecentGridFn(); } catch(eRecent) {}
|
||||||
|
try { refreshCommonGridFn(); } catch(eCommon) {}
|
||||||
|
try { syncRgbSeeksFn(); } catch(eSync) {}
|
||||||
|
try { if (alphaSeek) alphaSeek.setProgress(255); } catch(eAlphaSeek) {}
|
||||||
|
try { if (alphaValTv) alphaValTv.setText("255"); } catch(eAlphaTv) {}
|
||||||
|
});
|
||||||
|
var clearLp = new android.widget.LinearLayout.LayoutParams(0, self.dp(52));
|
||||||
|
clearLp.weight = 1;
|
||||||
|
clearLp.setMargins(0, 0, self.dp(6), 0);
|
||||||
|
actionRow.addView(btnClear, clearLp);
|
||||||
|
|
||||||
|
var btnOk = createColorPanelActionButton("保存颜色", true, function() {
|
||||||
|
try {
|
||||||
|
var finalColor = isFollowTheme ? "" : String(selectedColor || "");
|
||||||
|
if (!isFollowTheme && selectedColor) pushRecentColor(selectedColor);
|
||||||
|
if (typeof onSelect === "function") {
|
||||||
|
try { onSelect(finalColor); } catch(eOnSelect) { safeLog(self.L, 'e', "colorPicker onSelect err=" + String(eOnSelect)); }
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
safeLog(self.L, 'e', "colorPicker confirm err=" + String(e));
|
||||||
|
}
|
||||||
|
closePopup();
|
||||||
|
});
|
||||||
|
var okLp = new android.widget.LinearLayout.LayoutParams(0, self.dp(52));
|
||||||
|
okLp.weight = 1;
|
||||||
|
okLp.setMargins(self.dp(6), 0, 0, 0);
|
||||||
|
actionRow.addView(btnOk, okLp);
|
||||||
|
|
||||||
|
footer.addView(actionRow, new android.widget.LinearLayout.LayoutParams(
|
||||||
|
android.widget.LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return popupResult;
|
||||||
|
};
|
||||||
509
code/th_14_icon_picker.js
Normal file
509
code/th_14_icon_picker.js
Normal file
@@ -0,0 +1,509 @@
|
|||||||
|
// @version 1.0.0
|
||||||
|
// ToolHub - ShortX 图标选择器模块
|
||||||
|
//
|
||||||
|
// 阶段 1:承载 showShortXIconPickerPopup。
|
||||||
|
// 目的:在新增模块下载、验签、eval 链路已稳定后,迁移 ShortX 图标选择器主体。
|
||||||
|
// 注意:加载顺序必须位于 th_14_panels.js 之后、th_15_extra.js 之前。
|
||||||
|
|
||||||
|
FloatBallAppWM.prototype.showShortXIconPickerPopup = function(opts) {
|
||||||
|
var self = this;
|
||||||
|
var opt = opts || {};
|
||||||
|
var currentName = String(opt.currentName || "");
|
||||||
|
var onSelect = (typeof opt.onSelect === "function") ? opt.onSelect : null;
|
||||||
|
var onDismissCb = (typeof opt.onDismiss === "function") ? opt.onDismiss : null;
|
||||||
|
|
||||||
|
var catalog = [];
|
||||||
|
try { catalog = self.getShortXIconCatalog() || []; } catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
if (!catalog.length) {
|
||||||
|
try { catalog = self.getShortXIconCatalog(true) || []; } catch(e2) { safeLog(null, 'e', "catch " + String(e2)); }
|
||||||
|
}
|
||||||
|
if (!catalog.length) {
|
||||||
|
self.toast("图标库未加载");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedName = currentName;
|
||||||
|
var popupState = { currentPage: 0, filter: "全部" };
|
||||||
|
var PT = self.getIslandPickerTheme ? self.getIslandPickerTheme() : null;
|
||||||
|
var isDark = PT ? PT.isDark : self.isDarkTheme();
|
||||||
|
var C = self.ui.colors;
|
||||||
|
var T = PT ? PT.T : self.getAnimalIslandTheme();
|
||||||
|
var textColor = PT ? PT.text : (isDark ? C.textPriDark : C.textPriLight);
|
||||||
|
var subTextColor = PT ? PT.sub : (isDark ? C.textSecDark : C.textSecLight);
|
||||||
|
var cardColor = PT ? PT.card2 : (isDark ? C.cardDark : C.cardLight);
|
||||||
|
var wm = self.state.wm;
|
||||||
|
var filterTags = ["全部", "常用", "最近", "收藏", "线框", "实心"];
|
||||||
|
var filterViews = [];
|
||||||
|
var FAVORITE_ICONS_KEY = "shortx_icon_favorites";
|
||||||
|
var favoriteIcons = [];
|
||||||
|
var favoriteMap = {};
|
||||||
|
|
||||||
|
function rebuildFavoriteMap() {
|
||||||
|
favoriteMap = {};
|
||||||
|
for (var fi = 0; fi < favoriteIcons.length; fi++) {
|
||||||
|
var fn = String(favoriteIcons[fi] || "");
|
||||||
|
if (fn) favoriteMap[fn] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadFavoriteIcons() {
|
||||||
|
favoriteIcons = [];
|
||||||
|
try {
|
||||||
|
var saved = self.loadPanelState ? self.loadPanelState(FAVORITE_ICONS_KEY) : null;
|
||||||
|
var arr = saved && saved.icons ? saved.icons : [];
|
||||||
|
for (var li = 0; li < arr.length && favoriteIcons.length < 300; li++) {
|
||||||
|
var name = String(arr[li] || "");
|
||||||
|
if (name && !favoriteMap[name]) {
|
||||||
|
favoriteIcons.push(name);
|
||||||
|
favoriteMap[name] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(eFavLoad) { safeLog(null, 'e', "catch " + String(eFavLoad)); }
|
||||||
|
rebuildFavoriteMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveFavoriteIcons() {
|
||||||
|
try {
|
||||||
|
if (self.savePanelState) self.savePanelState(FAVORITE_ICONS_KEY, { icons: favoriteIcons.slice(0, 300) });
|
||||||
|
} catch(eFavSave) { safeLog(null, 'e', "catch " + String(eFavSave)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFavoriteIcon(name) {
|
||||||
|
return !!favoriteMap[String(name || "")];
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleFavoriteIcon(name) {
|
||||||
|
name = String(name || "");
|
||||||
|
if (!name) return false;
|
||||||
|
var next = [];
|
||||||
|
var existed = false;
|
||||||
|
for (var ti = 0; ti < favoriteIcons.length; ti++) {
|
||||||
|
var oldName = String(favoriteIcons[ti] || "");
|
||||||
|
if (!oldName) continue;
|
||||||
|
if (oldName === name) { existed = true; continue; }
|
||||||
|
next.push(oldName);
|
||||||
|
}
|
||||||
|
if (!existed) next.unshift(name);
|
||||||
|
favoriteIcons = next.slice(0, 300);
|
||||||
|
rebuildFavoriteMap();
|
||||||
|
saveFavoriteIcons();
|
||||||
|
return !existed;
|
||||||
|
}
|
||||||
|
loadFavoriteIcons();
|
||||||
|
|
||||||
|
function matchesFilter(entry, f) {
|
||||||
|
if (!entry) return false;
|
||||||
|
if (!f || f === "全部") return true;
|
||||||
|
var n = String(entry.shortName || entry.name || "").toLowerCase();
|
||||||
|
if (f === "常用") return n.indexOf("home") >= 0 || n.indexOf("share") >= 0 || n.indexOf("search") >= 0 || n.indexOf("settings") >= 0 || n.indexOf("add") >= 0 || n.indexOf("back") >= 0 || n.indexOf("close") >= 0;
|
||||||
|
if (f === "最近") return selectedName && String(entry.name) === String(selectedName);
|
||||||
|
if (f === "收藏") return isFavoriteIcon(entry.name);
|
||||||
|
if (f === "线框") return n.indexOf("outline") >= 0 || n.indexOf("line") >= 0 || n.indexOf("stroke") >= 0 || n.indexOf("border") >= 0;
|
||||||
|
if (f === "实心") return n.indexOf("fill") >= 0 || n.indexOf("solid") >= 0 || n.indexOf("round") >= 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterCatalog(q) {
|
||||||
|
var qLower = String(q || "").toLowerCase();
|
||||||
|
var out = [];
|
||||||
|
for (var i = 0; i < catalog.length; i++) {
|
||||||
|
var entry = catalog[i];
|
||||||
|
if (!entry) continue;
|
||||||
|
if (!matchesFilter(entry, popupState.filter)) continue;
|
||||||
|
if (qLower) {
|
||||||
|
var n = String(entry.shortName || entry.name).toLowerCase();
|
||||||
|
if (n.indexOf(qLower) < 0) continue;
|
||||||
|
}
|
||||||
|
out.push(entry);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dm = context.getResources().getDisplayMetrics();
|
||||||
|
var sw = dm.widthPixels;
|
||||||
|
var sh = dm.heightPixels;
|
||||||
|
var panelWidth = Math.round(sw * 0.92);
|
||||||
|
var panelHeight = Math.round(sh * 0.90);
|
||||||
|
try {
|
||||||
|
if (self.calculateToolAppLayout) {
|
||||||
|
var toolLayout = self.calculateToolAppLayout(null);
|
||||||
|
if (toolLayout && toolLayout.width > 0) panelWidth = toolLayout.width;
|
||||||
|
if (toolLayout && toolLayout.height > 0) panelHeight = toolLayout.height;
|
||||||
|
}
|
||||||
|
} catch(eLayout) { safeLog(null, 'e', "catch " + String(eLayout)); }
|
||||||
|
if (panelWidth > self.dp(560)) panelWidth = self.dp(560);
|
||||||
|
if (panelWidth < self.dp(320)) panelWidth = Math.min(sw - self.dp(16), self.dp(320));
|
||||||
|
if (panelHeight > sh - self.dp(24)) panelHeight = sh - self.dp(24);
|
||||||
|
if (panelHeight < self.dp(460)) panelHeight = Math.min(sh - self.dp(16), self.dp(460));
|
||||||
|
|
||||||
|
var padH = self.dp(14);
|
||||||
|
var padV = self.dp(12);
|
||||||
|
var gap = self.dp(8);
|
||||||
|
var colCount = 5;
|
||||||
|
var availW = panelWidth - padH * 2 - self.dp(10) * 2;
|
||||||
|
var cellW = Math.floor((availW - gap * (colCount - 1)) / colCount);
|
||||||
|
if (cellW < self.dp(46)) cellW = self.dp(46);
|
||||||
|
var iconSize = Math.max(self.dp(23), Math.min(self.dp(30), Math.floor(cellW * 0.46)));
|
||||||
|
var cellH = self.dp(70);
|
||||||
|
var headerH = self.dp(176);
|
||||||
|
var bottomH = self.dp(58);
|
||||||
|
var maxGridH = Math.max(self.dp(250), panelHeight - headerH - bottomH);
|
||||||
|
var rowCount = Math.max(3, Math.floor(maxGridH / (cellH + gap)));
|
||||||
|
var pageSize = colCount * rowCount;
|
||||||
|
|
||||||
|
var rootOverlay = new android.widget.FrameLayout(context);
|
||||||
|
try { rootOverlay.setBackgroundColor(self.withAlpha(isDark ? 0xFF000000 : 0xFFFFFFFF, isDark ? 0.58 : 0.42)); }
|
||||||
|
catch(eOverlayBg) { rootOverlay.setBackgroundColor(0x33000000); }
|
||||||
|
rootOverlay.setClickable(true);
|
||||||
|
|
||||||
|
var card = new android.widget.LinearLayout(context);
|
||||||
|
card.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
|
card.setPadding(padH, padV, padH, padV);
|
||||||
|
card.setBackground(self.ui.createStrokeDrawable(T.card, self.withAlpha(T.primaryDeep, isDark ? 0.28 : 0.22), self.dp(1), self.dp(24)));
|
||||||
|
try { card.setElevation(self.dp(10)); } catch(eCardElev) { safeLog(null, 'e', "catch " + String(eCardElev)); }
|
||||||
|
|
||||||
|
var cardLp = new android.widget.FrameLayout.LayoutParams(panelWidth, panelHeight);
|
||||||
|
cardLp.gravity = android.view.Gravity.CENTER;
|
||||||
|
card.setLayoutParams(cardLp);
|
||||||
|
rootOverlay.addView(card);
|
||||||
|
|
||||||
|
var overlayLp = new android.view.WindowManager.LayoutParams(
|
||||||
|
android.view.WindowManager.LayoutParams.MATCH_PARENT,
|
||||||
|
android.view.WindowManager.LayoutParams.MATCH_PARENT,
|
||||||
|
android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
|
||||||
|
android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
|
||||||
|
android.graphics.PixelFormat.TRANSLUCENT
|
||||||
|
);
|
||||||
|
overlayLp.softInputMode = android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
|
||||||
|
| android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
|
||||||
|
|
||||||
|
try { wm.addView(rootOverlay, overlayLp); } catch(eAdd) {
|
||||||
|
safeLog(self.L, 'e', "icon picker addView fail: " + String(eAdd));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isDismissed = false;
|
||||||
|
function dismiss() {
|
||||||
|
if (isDismissed) return;
|
||||||
|
isDismissed = true;
|
||||||
|
try { wm.removeView(rootOverlay); } catch(e) { safeLog(null, 'e', "catch " + String(e)); }
|
||||||
|
if (typeof onDismissCb === "function") {
|
||||||
|
try { onDismissCb(); } catch(eD) { safeLog(null, 'e', "catch " + String(eD)); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rootOverlay.setOnClickListener(new android.view.View.OnClickListener({ onClick: function() { dismiss(); } }));
|
||||||
|
card.setOnClickListener(new android.view.View.OnClickListener({ onClick: function() { } }));
|
||||||
|
|
||||||
|
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);
|
||||||
|
titleBox.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
titleBox.setLayoutParams(new android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 1));
|
||||||
|
|
||||||
|
var titleTv = new android.widget.TextView(context);
|
||||||
|
titleTv.setText("岛上图标库");
|
||||||
|
titleTv.setTextColor(textColor);
|
||||||
|
titleTv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 17);
|
||||||
|
titleTv.setTypeface(null, android.graphics.Typeface.BOLD);
|
||||||
|
titleBox.addView(titleTv);
|
||||||
|
|
||||||
|
var countTv = new android.widget.TextView(context);
|
||||||
|
countTv.setText("共 " + catalog.length + " 个图标");
|
||||||
|
countTv.setTextColor(subTextColor);
|
||||||
|
countTv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 11);
|
||||||
|
titleBox.addView(countTv);
|
||||||
|
header.addView(titleBox);
|
||||||
|
|
||||||
|
var closeBtn = self.ui.createFlatButton(self, "✕", T.primaryDeep, function() { dismiss(); });
|
||||||
|
closeBtn.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 18);
|
||||||
|
closeBtn.setTypeface(null, android.graphics.Typeface.BOLD);
|
||||||
|
closeBtn.setPadding(self.dp(8), 0, self.dp(8), 0);
|
||||||
|
try { closeBtn.setBackground(self.ui.createStrokeDrawable(T.primarySoft, self.withAlpha(T.primaryDeep, isDark ? 0.30 : 0.22), self.dp(1), self.dp(18))); } catch(eCloseBg) {}
|
||||||
|
header.addView(closeBtn, new android.widget.LinearLayout.LayoutParams(self.dp(42), self.dp(38)));
|
||||||
|
card.addView(header);
|
||||||
|
|
||||||
|
var searchEt = new android.widget.EditText(context);
|
||||||
|
searchEt.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 14);
|
||||||
|
searchEt.setTextColor(textColor);
|
||||||
|
try { searchEt.setHintTextColor(subTextColor); } catch(eHint) { safeLog(null, 'e', "catch " + String(eHint)); }
|
||||||
|
searchEt.setHint("寻找岛上图标,如 share / home");
|
||||||
|
searchEt.setSingleLine(true);
|
||||||
|
searchEt.setFocusable(true);
|
||||||
|
searchEt.setFocusableInTouchMode(true);
|
||||||
|
searchEt.setPadding(self.dp(14), self.dp(10), self.dp(14), self.dp(10));
|
||||||
|
searchEt.setBackground(self.ui.createStrokeDrawable(T.card2, self.withAlpha(T.primaryDeep, isDark ? 0.24 : 0.18), self.dp(1), self.dp(20)));
|
||||||
|
var searchLp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, self.dp(46));
|
||||||
|
searchLp.setMargins(0, self.dp(10), 0, self.dp(8));
|
||||||
|
card.addView(searchEt, searchLp);
|
||||||
|
searchEt.setOnClickListener(new android.view.View.OnClickListener({
|
||||||
|
onClick: function(v) {
|
||||||
|
self.touchActivity();
|
||||||
|
try {
|
||||||
|
v.requestFocus();
|
||||||
|
var imm = context.getSystemService(android.content.Context.INPUT_METHOD_SERVICE);
|
||||||
|
if (imm) imm.showSoftInput(v, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
|
||||||
|
} catch(eIme) { safeLog(null, 'e', "catch " + String(eIme)); }
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
var filterScroll = new android.widget.HorizontalScrollView(context);
|
||||||
|
filterScroll.setHorizontalScrollBarEnabled(false);
|
||||||
|
var filterRow = new android.widget.LinearLayout(context);
|
||||||
|
filterRow.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
filterRow.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
filterRow.setPadding(0, 0, 0, 0);
|
||||||
|
filterScroll.addView(filterRow);
|
||||||
|
var filterLp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, self.dp(36));
|
||||||
|
filterLp.setMargins(0, 0, 0, self.dp(4));
|
||||||
|
card.addView(filterScroll, filterLp);
|
||||||
|
|
||||||
|
function refreshFilterTags() {
|
||||||
|
try {
|
||||||
|
for (var i = 0; i < filterViews.length; i++) {
|
||||||
|
var item = filterViews[i];
|
||||||
|
if (!item || !item.view) continue;
|
||||||
|
var active = item.name === popupState.filter;
|
||||||
|
item.view.setTextColor(active ? T.onPrimary : T.primaryDeep);
|
||||||
|
item.view.setTypeface(null, active ? android.graphics.Typeface.BOLD : android.graphics.Typeface.NORMAL);
|
||||||
|
item.view.setBackground(self.ui.createStrokeDrawable(active ? T.primary : T.primarySoft, self.withAlpha(T.primaryDeep, active ? 0.36 : 0.18), self.dp(1), self.dp(16)));
|
||||||
|
}
|
||||||
|
} catch(eTags) { safeLog(null, 'e', "catch " + String(eTags)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var ft = 0; ft < filterTags.length; ft++) {
|
||||||
|
(function(tag) {
|
||||||
|
var chip = new android.widget.TextView(context);
|
||||||
|
chip.setText(tag);
|
||||||
|
chip.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 12);
|
||||||
|
chip.setGravity(android.view.Gravity.CENTER);
|
||||||
|
chip.setPadding(self.dp(12), 0, self.dp(12), 0);
|
||||||
|
chip.setSingleLine(true);
|
||||||
|
chip.setClickable(true);
|
||||||
|
chip.setOnClickListener(new android.view.View.OnClickListener({
|
||||||
|
onClick: function() {
|
||||||
|
self.touchActivity();
|
||||||
|
popupState.filter = tag;
|
||||||
|
popupState.currentPage = 0;
|
||||||
|
refreshFilterTags();
|
||||||
|
renderGrid();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
var chipLp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, self.dp(30));
|
||||||
|
chipLp.setMargins(0, 0, self.dp(7), 0);
|
||||||
|
filterRow.addView(chip, chipLp);
|
||||||
|
filterViews.push({ name: tag, view: chip });
|
||||||
|
})(filterTags[ft]);
|
||||||
|
}
|
||||||
|
refreshFilterTags();
|
||||||
|
|
||||||
|
var pageBar = new android.widget.LinearLayout(context);
|
||||||
|
pageBar.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
pageBar.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
pageBar.setPadding(self.dp(2), 0, self.dp(2), self.dp(4));
|
||||||
|
var pageBarLp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, self.dp(34));
|
||||||
|
card.addView(pageBar, pageBarLp);
|
||||||
|
|
||||||
|
var btnPrev = self.ui.createFlatButton(self, "上一页", self.withAlpha(T.primaryDeep, 0.72), function() {
|
||||||
|
if (popupState.currentPage > 0) { popupState.currentPage--; renderGrid(); }
|
||||||
|
});
|
||||||
|
pageBar.addView(btnPrev, new android.widget.LinearLayout.LayoutParams(self.dp(78), self.dp(30)));
|
||||||
|
|
||||||
|
var pageInfo = new android.widget.TextView(context);
|
||||||
|
pageInfo.setTextColor(self.withAlpha(textColor, 0.76));
|
||||||
|
pageInfo.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 12);
|
||||||
|
pageInfo.setGravity(android.view.Gravity.CENTER);
|
||||||
|
pageInfo.setLayoutParams(new android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 1));
|
||||||
|
pageBar.addView(pageInfo);
|
||||||
|
|
||||||
|
var btnNext = self.ui.createFlatButton(self, "下一页", self.withAlpha(T.primaryDeep, 0.72), function() {
|
||||||
|
popupState.currentPage++;
|
||||||
|
renderGrid();
|
||||||
|
});
|
||||||
|
pageBar.addView(btnNext, new android.widget.LinearLayout.LayoutParams(self.dp(78), self.dp(30)));
|
||||||
|
|
||||||
|
var gridScroll = new android.widget.ScrollView(context);
|
||||||
|
gridScroll.setVerticalScrollBarEnabled(false);
|
||||||
|
gridScroll.setOverScrollMode(android.view.View.OVER_SCROLL_NEVER);
|
||||||
|
gridScroll.setLayoutParams(new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, 0, 1));
|
||||||
|
card.addView(gridScroll);
|
||||||
|
|
||||||
|
var grid = new android.widget.GridLayout(context);
|
||||||
|
grid.setColumnCount(colCount);
|
||||||
|
grid.setPadding(self.dp(10), self.dp(6), self.dp(10), self.dp(8));
|
||||||
|
gridScroll.addView(grid);
|
||||||
|
|
||||||
|
var selectRow = new android.widget.LinearLayout(context);
|
||||||
|
selectRow.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
selectRow.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
selectRow.setPadding(self.dp(12), self.dp(8), self.dp(12), self.dp(8));
|
||||||
|
selectRow.setBackground(self.ui.createStrokeDrawable(T.card2, self.withAlpha(T.primaryDeep, isDark ? 0.22 : 0.16), self.dp(1), self.dp(22)));
|
||||||
|
var selectRowLp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, self.dp(58));
|
||||||
|
selectRowLp.setMargins(0, self.dp(6), 0, 0);
|
||||||
|
card.addView(selectRow, selectRowLp);
|
||||||
|
|
||||||
|
var selectNameTv = new android.widget.TextView(context);
|
||||||
|
selectNameTv.setTextColor(textColor);
|
||||||
|
selectNameTv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 13);
|
||||||
|
selectNameTv.setSingleLine(true);
|
||||||
|
try { selectNameTv.setEllipsize(android.text.TextUtils.TruncateAt.END); } catch(eEll) {}
|
||||||
|
selectNameTv.setLayoutParams(new android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 1));
|
||||||
|
selectRow.addView(selectNameTv);
|
||||||
|
|
||||||
|
var selectConfirm = self.ui.createSolidButton(self, "带回小岛", T.primary, T.onPrimary, function() {
|
||||||
|
self.touchActivity();
|
||||||
|
try {
|
||||||
|
if (typeof onSelect === "function") onSelect(selectedName);
|
||||||
|
} catch(eSelect) {
|
||||||
|
safeLog(self.L, 'e', "icon onSelect err=" + String(eSelect));
|
||||||
|
}
|
||||||
|
dismiss();
|
||||||
|
});
|
||||||
|
var confirmLp = new android.widget.LinearLayout.LayoutParams(self.dp(104), self.dp(42));
|
||||||
|
confirmLp.setMargins(self.dp(10), 0, 0, 0);
|
||||||
|
selectRow.addView(selectConfirm, confirmLp);
|
||||||
|
|
||||||
|
function updateSelectedLabel() {
|
||||||
|
try {
|
||||||
|
selectNameTv.setText(selectedName ? ("已选:" + String(selectedName)) : "还没选图标");
|
||||||
|
} catch(eLabel) { safeLog(null, 'e', "catch " + String(eLabel)); }
|
||||||
|
}
|
||||||
|
updateSelectedLabel();
|
||||||
|
|
||||||
|
function renderGrid() {
|
||||||
|
try {
|
||||||
|
grid.removeAllViews();
|
||||||
|
var q = String(searchEt.getText() || "");
|
||||||
|
var matched = filterCatalog(q);
|
||||||
|
var totalPages = Math.max(1, Math.ceil(matched.length / pageSize));
|
||||||
|
if (popupState.currentPage >= totalPages) popupState.currentPage = totalPages - 1;
|
||||||
|
if (popupState.currentPage < 0) popupState.currentPage = 0;
|
||||||
|
var start = popupState.currentPage * pageSize;
|
||||||
|
var pageItems = matched.slice(start, start + pageSize);
|
||||||
|
|
||||||
|
pageInfo.setText("第 " + (popupState.currentPage + 1) + " / " + totalPages + " 页");
|
||||||
|
btnPrev.setEnabled(popupState.currentPage > 0);
|
||||||
|
btnNext.setEnabled(popupState.currentPage < totalPages - 1);
|
||||||
|
|
||||||
|
if (pageItems.length === 0) {
|
||||||
|
var emptyTv = new android.widget.TextView(context);
|
||||||
|
emptyTv.setText(popupState.filter === "收藏" ? "收藏夹还空着,点图标左上角 ☆ 收藏" : "没有找到这枚小图标");
|
||||||
|
emptyTv.setTextColor(subTextColor);
|
||||||
|
emptyTv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 14);
|
||||||
|
emptyTv.setGravity(android.view.Gravity.CENTER);
|
||||||
|
emptyTv.setPadding(0, self.dp(60), 0, self.dp(60));
|
||||||
|
grid.addView(emptyTv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.setColumnCount(colCount);
|
||||||
|
for (var idx = 0; idx < pageItems.length; idx++) {
|
||||||
|
(function(item) {
|
||||||
|
var frame = new android.widget.FrameLayout(context);
|
||||||
|
frame.setClickable(true);
|
||||||
|
var isSelected = selectedName === item.name;
|
||||||
|
var frameBg = isSelected ? T.primarySoft : self.withAlpha(cardColor, 0.96);
|
||||||
|
var frameStroke = isSelected ? self.withAlpha(T.primaryDeep, isDark ? 0.50 : 0.42) : self.withAlpha(T.primaryDeep, isDark ? 0.18 : 0.12);
|
||||||
|
frame.setBackground(self.ui.createStrokeDrawable(frameBg, frameStroke, isSelected ? self.dp(2) : self.dp(1), self.dp(15)));
|
||||||
|
|
||||||
|
var cell = new android.widget.LinearLayout(context);
|
||||||
|
cell.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
|
cell.setGravity(android.view.Gravity.CENTER);
|
||||||
|
cell.setPadding(self.dp(4), self.dp(6), self.dp(4), self.dp(5));
|
||||||
|
frame.addView(cell, new android.widget.FrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams.MATCH_PARENT, android.widget.FrameLayout.LayoutParams.MATCH_PARENT));
|
||||||
|
|
||||||
|
var iv = new android.widget.ImageView(context);
|
||||||
|
iv.setLayoutParams(new android.widget.LinearLayout.LayoutParams(iconSize, iconSize));
|
||||||
|
iv.setScaleType(android.widget.ImageView.ScaleType.FIT_CENTER);
|
||||||
|
try {
|
||||||
|
var dr = self.getShortXIconDrawable(item.name);
|
||||||
|
if (dr) { iv.setImageDrawable(dr); }
|
||||||
|
} catch(eIcon) { safeLog(null, 'e', "catch " + String(eIcon)); }
|
||||||
|
cell.addView(iv);
|
||||||
|
|
||||||
|
var tv = new android.widget.TextView(context);
|
||||||
|
tv.setText(String(item.shortName || item.name));
|
||||||
|
tv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 9);
|
||||||
|
tv.setGravity(android.view.Gravity.CENTER);
|
||||||
|
tv.setMaxLines(1);
|
||||||
|
try { tv.setEllipsize(android.text.TextUtils.TruncateAt.END); } catch(eTvEll) {}
|
||||||
|
tv.setPadding(self.dp(2), self.dp(5), self.dp(2), 0);
|
||||||
|
tv.setTextColor(isSelected ? T.primaryDeep : subTextColor);
|
||||||
|
cell.addView(tv, new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT));
|
||||||
|
|
||||||
|
var favBtn = new android.widget.TextView(context);
|
||||||
|
favBtn.setText(isFavoriteIcon(item.name) ? "★" : "☆");
|
||||||
|
favBtn.setTextColor(isFavoriteIcon(item.name) ? T.primaryDeep : self.withAlpha(T.primaryDeep, 0.52));
|
||||||
|
favBtn.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 13);
|
||||||
|
favBtn.setGravity(android.view.Gravity.CENTER);
|
||||||
|
favBtn.setTypeface(null, android.graphics.Typeface.BOLD);
|
||||||
|
favBtn.setBackground(self.ui.createRoundDrawable(isFavoriteIcon(item.name) ? T.primarySoft : self.withAlpha(T.card, 0.88), self.dp(9)));
|
||||||
|
favBtn.setClickable(true);
|
||||||
|
favBtn.setOnClickListener(new android.view.View.OnClickListener({
|
||||||
|
onClick: function() {
|
||||||
|
self.touchActivity();
|
||||||
|
var added = toggleFavoriteIcon(item.name);
|
||||||
|
try { self.toast(added ? "已收藏到小岛" : "已取消收藏"); } catch(eFavToast) {}
|
||||||
|
if (popupState.filter === "收藏") popupState.currentPage = 0;
|
||||||
|
renderGrid();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
var favLp = new android.widget.FrameLayout.LayoutParams(self.dp(18), self.dp(18));
|
||||||
|
favLp.gravity = android.view.Gravity.TOP | android.view.Gravity.LEFT;
|
||||||
|
favLp.setMargins(self.dp(4), self.dp(4), 0, 0);
|
||||||
|
frame.addView(favBtn, favLp);
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
var badge = new android.widget.TextView(context);
|
||||||
|
badge.setText("✓");
|
||||||
|
badge.setTextColor(T.onPrimary);
|
||||||
|
badge.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 10);
|
||||||
|
badge.setGravity(android.view.Gravity.CENTER);
|
||||||
|
badge.setTypeface(null, android.graphics.Typeface.BOLD);
|
||||||
|
badge.setBackground(self.ui.createRoundDrawable(T.primary, self.dp(9)));
|
||||||
|
var badgeLp = new android.widget.FrameLayout.LayoutParams(self.dp(18), self.dp(18));
|
||||||
|
badgeLp.gravity = android.view.Gravity.TOP | android.view.Gravity.RIGHT;
|
||||||
|
badgeLp.setMargins(0, self.dp(4), self.dp(4), 0);
|
||||||
|
frame.addView(badge, badgeLp);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.setOnClickListener(new android.view.View.OnClickListener({
|
||||||
|
onClick: function() {
|
||||||
|
self.touchActivity();
|
||||||
|
selectedName = item.name;
|
||||||
|
updateSelectedLabel();
|
||||||
|
renderGrid();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
var cellLp = new android.widget.GridLayout.LayoutParams();
|
||||||
|
cellLp.width = cellW;
|
||||||
|
cellLp.height = cellH;
|
||||||
|
var col = idx % colCount;
|
||||||
|
var mr = (col === colCount - 1) ? 0 : gap;
|
||||||
|
cellLp.setMargins(0, 0, mr, gap);
|
||||||
|
frame.setLayoutParams(cellLp);
|
||||||
|
grid.addView(frame);
|
||||||
|
})(pageItems[idx]);
|
||||||
|
}
|
||||||
|
} catch(eRender) {
|
||||||
|
safeLog(self.L, 'e', "renderShortXIconGrid err=" + String(eRender));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchEt.addTextChangedListener(new android.text.TextWatcher({
|
||||||
|
beforeTextChanged: function() {},
|
||||||
|
onTextChanged: function() {
|
||||||
|
self.touchActivity();
|
||||||
|
popupState.currentPage = 0;
|
||||||
|
renderGrid();
|
||||||
|
},
|
||||||
|
afterTextChanged: function() {}
|
||||||
|
}));
|
||||||
|
|
||||||
|
renderGrid();
|
||||||
|
|
||||||
|
return { close: dismiss };
|
||||||
|
};
|
||||||
1038
code/th_14_panels.js
1038
code/th_14_panels.js
File diff suppressed because it is too large
Load Diff
392
code/th_14_schema_editor.js
Normal file
392
code/th_14_schema_editor.js
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
// ToolHub - 高级蓝图编辑器模块
|
||||||
|
// 依赖:th_14_panels.js 的设置页主题/基础 UI,th_05_persistence.js 的 ConfigManager。
|
||||||
|
// 加载顺序:th_14_panels.js 之后,th_15_extra.js 之前。
|
||||||
|
|
||||||
|
FloatBallAppWM.prototype.buildSchemaEditorPanelView = function() {
|
||||||
|
var self = this;
|
||||||
|
if (this.state.editingSchemaIndex === undefined) this.state.editingSchemaIndex = null;
|
||||||
|
|
||||||
|
if (!this.state.keepSchemaEditorState || !this.state.tempSchema) {
|
||||||
|
var current = ConfigManager.loadSchema();
|
||||||
|
this.state.tempSchema = JSON.parse(JSON.stringify(current));
|
||||||
|
}
|
||||||
|
this.state.keepSchemaEditorState = false;
|
||||||
|
|
||||||
|
var schema = this.state.tempSchema || [];
|
||||||
|
var isEditing = (this.state.editingSchemaIndex !== null && this.state.editingSchemaIndex !== undefined);
|
||||||
|
var isDark = this.isDarkTheme();
|
||||||
|
var C = this.ui.colors;
|
||||||
|
var T = this.getAnimalIslandTheme ? this.getAnimalIslandTheme() : null;
|
||||||
|
try { if (this.applySettingsTheme) this.applySettingsTheme(T, isDark, C, this.state.pendingUserCfg || this.config); } catch(eTheme) {}
|
||||||
|
|
||||||
|
var bgColor = T && T.bg ? T.bg : (isDark ? C.bgDark : C.bgLight);
|
||||||
|
var cardColor = T && T.card ? T.card : (isDark ? C.cardDark : C.cardLight);
|
||||||
|
var textColor = T && T.text ? T.text : (isDark ? C.textPriDark : C.textPriLight);
|
||||||
|
var subTextColor = T && T.sub ? T.sub : (isDark ? C.textSecDark : C.textSecLight);
|
||||||
|
var primaryColor = T && T.primary ? T.primary : C.primary;
|
||||||
|
var primaryDeep = T && T.primaryDeep ? T.primaryDeep : C.primary;
|
||||||
|
var primarySoft = T && T.primarySoft ? T.primarySoft : self.withAlpha(primaryColor, isDark ? 0.22 : 0.12);
|
||||||
|
var strokeColor = T && T.stroke ? T.stroke : (isDark ? C.dividerDark : C.dividerLight);
|
||||||
|
var inputBgColor = isDark ? C.inputBgDark : C.inputBgLight;
|
||||||
|
var dangerColor = C.danger || C.error || 0xffd32f2f;
|
||||||
|
|
||||||
|
function lpFullWrap() {
|
||||||
|
return new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addWithMargins(parent, view, l, t, r, b) {
|
||||||
|
var lp = lpFullWrap();
|
||||||
|
lp.setMargins(self.dp(l || 0), self.dp(t || 0), self.dp(r || 0), self.dp(b || 0));
|
||||||
|
parent.addView(view, lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeText(txt, sp, color, bold) {
|
||||||
|
var tv = new android.widget.TextView(context);
|
||||||
|
tv.setText(String(txt || ""));
|
||||||
|
tv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, sp || 13);
|
||||||
|
tv.setTextColor(color || textColor);
|
||||||
|
if (bold) tv.setTypeface(null, android.graphics.Typeface.BOLD);
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeChip(txt, color, onClick) {
|
||||||
|
var tv = new android.widget.TextView(context);
|
||||||
|
tv.setText(String(txt || ""));
|
||||||
|
tv.setTextColor(color || primaryDeep);
|
||||||
|
tv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 12);
|
||||||
|
tv.setGravity(android.view.Gravity.CENTER);
|
||||||
|
tv.setTypeface(null, android.graphics.Typeface.BOLD);
|
||||||
|
tv.setMinHeight(self.dp(32));
|
||||||
|
tv.setPadding(self.dp(10), 0, self.dp(10), 0);
|
||||||
|
try { tv.setBackground(self.ui.createStrokeDrawable(self.withAlpha(color || primaryColor, isDark ? 0.16 : 0.08), self.withAlpha(color || primaryColor, isDark ? 0.45 : 0.28), self.dp(1), self.dp(16))); } catch(eBg) {}
|
||||||
|
if (onClick) {
|
||||||
|
tv.setOnClickListener(new android.view.View.OnClickListener({ onClick: function(v) {
|
||||||
|
try { self.touchActivity(); } catch(eTouch) {}
|
||||||
|
try { onClick(v); } catch(eClick) { safeLog(null, 'e', "schema chip click err=" + String(eClick)); }
|
||||||
|
}}));
|
||||||
|
}
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showToast(msg) { try { self.toast(String(msg || "")); } catch(eToast) {} }
|
||||||
|
|
||||||
|
function refreshPanel() {
|
||||||
|
self.state.keepSchemaEditorState = true;
|
||||||
|
self.showPanelAvoidBall("schema_editor");
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearDraft() {
|
||||||
|
self.state.schemaEditingDraft = null;
|
||||||
|
self.state.schemaEditingDraftIndex = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeItem(item) {
|
||||||
|
var it = item || {};
|
||||||
|
it.type = String(it.type || "bool");
|
||||||
|
if (it.type !== "section") {
|
||||||
|
it.key = String(it.key || "").trim();
|
||||||
|
}
|
||||||
|
it.name = String(it.name || it.key || "").trim();
|
||||||
|
if (it.type === "section") {
|
||||||
|
delete it.key; delete it.min; delete it.max; delete it.step; delete it.action;
|
||||||
|
} else if (it.type === "bool" || it.type === "text") {
|
||||||
|
delete it.min; delete it.max; delete it.step; delete it.action;
|
||||||
|
} else if (it.type === "int" || it.type === "float") {
|
||||||
|
delete it.action;
|
||||||
|
if (it.min === "" || isNaN(Number(it.min))) delete it.min; else it.min = Number(it.min);
|
||||||
|
if (it.max === "" || isNaN(Number(it.max))) delete it.max; else it.max = Number(it.max);
|
||||||
|
if (it.step === "" || isNaN(Number(it.step))) delete it.step; else it.step = Number(it.step);
|
||||||
|
} else if (it.type === "action") {
|
||||||
|
delete it.min; delete it.max; delete it.step;
|
||||||
|
it.action = String(it.action || "").trim();
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateItem(item) {
|
||||||
|
if (!item.name) return "请填写显示名字";
|
||||||
|
if (item.type !== "section" && !item.key) return "请填写配置键";
|
||||||
|
if (item.type === "action" && !item.action) return "请填写动作 ID";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
var panel = this.ui.createStyledPanel(this, 16);
|
||||||
|
try { panel.setBackground(this.ui.createRoundDrawable(bgColor, this.dp(20))); } catch(ePanelBg) {}
|
||||||
|
|
||||||
|
if (!isEditing) {
|
||||||
|
var topCard = new android.widget.LinearLayout(context);
|
||||||
|
topCard.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
|
topCard.setPadding(self.dp(14), self.dp(12), self.dp(14), self.dp(12));
|
||||||
|
try { topCard.setBackground(self.ui.createStrokeDrawable(cardColor, self.withAlpha(strokeColor, isDark ? 0.32 : 0.42), self.dp(1), self.dp(20))); } catch(eTopBg) {}
|
||||||
|
|
||||||
|
var titleRow = new android.widget.LinearLayout(context);
|
||||||
|
titleRow.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
titleRow.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
var titleBox = new android.widget.LinearLayout(context);
|
||||||
|
titleBox.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
|
titleBox.addView(makeText("岛屿蓝图", 17, textColor, true));
|
||||||
|
titleBox.addView(makeText("这里会改变设置页结构,建议只在需要整理入口时使用", 12, subTextColor, false));
|
||||||
|
titleRow.addView(titleBox, new android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 1));
|
||||||
|
titleRow.addView(makeChip("添加", primaryDeep, function() {
|
||||||
|
self.state.editingSchemaIndex = -1;
|
||||||
|
clearDraft();
|
||||||
|
if (self.state.toolAppActive && self.pushToolAppPage) self.pushToolAppPage("schema_editor");
|
||||||
|
else refreshPanel();
|
||||||
|
}));
|
||||||
|
topCard.addView(titleRow);
|
||||||
|
|
||||||
|
var stat = makeText("共 " + schema.length + " 个蓝图项 · 保存后才会生效", 12, subTextColor, false);
|
||||||
|
stat.setPadding(0, self.dp(8), 0, 0);
|
||||||
|
topCard.addView(stat);
|
||||||
|
addWithMargins(panel, topCard, 0, 0, 0, 8);
|
||||||
|
|
||||||
|
var scroll = new android.widget.ScrollView(context);
|
||||||
|
try { scroll.setVerticalScrollBarEnabled(false); scroll.setOverScrollMode(android.view.View.OVER_SCROLL_NEVER); } catch(eScroll) {}
|
||||||
|
var list = new android.widget.LinearLayout(context);
|
||||||
|
list.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
|
list.setPadding(0, self.dp(2), 0, self.dp(10));
|
||||||
|
|
||||||
|
if (!schema.length) {
|
||||||
|
var empty = makeText("蓝图列表为空,可点上方“添加”创建新项。", 13, subTextColor, false);
|
||||||
|
empty.setGravity(android.view.Gravity.CENTER);
|
||||||
|
empty.setPadding(self.dp(12), self.dp(24), self.dp(12), self.dp(24));
|
||||||
|
list.addView(empty, lpFullWrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < schema.length; i++) {
|
||||||
|
(function(idx) {
|
||||||
|
var item = schema[idx] || {};
|
||||||
|
var card = new android.widget.LinearLayout(context);
|
||||||
|
card.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
|
card.setPadding(self.dp(13), self.dp(11), self.dp(13), self.dp(10));
|
||||||
|
try { card.setBackground(self.ui.createStrokeDrawable(cardColor, self.withAlpha(strokeColor, isDark ? 0.28 : 0.36), self.dp(1), self.dp(18))); card.setElevation(self.dp(1)); } catch(eCardBg) {}
|
||||||
|
|
||||||
|
var row = new android.widget.LinearLayout(context);
|
||||||
|
row.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
row.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
var badge = makeText(item.type === "section" ? "分组" : String(item.type || "项"), 11, primaryDeep, true);
|
||||||
|
badge.setGravity(android.view.Gravity.CENTER);
|
||||||
|
badge.setPadding(self.dp(8), self.dp(3), self.dp(8), self.dp(3));
|
||||||
|
try { badge.setBackground(self.ui.createStrokeDrawable(primarySoft, self.withAlpha(primaryDeep, 0.25), self.dp(1), self.dp(12))); } catch(eBadge) {}
|
||||||
|
row.addView(badge);
|
||||||
|
|
||||||
|
var info = new android.widget.LinearLayout(context);
|
||||||
|
info.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
|
info.setPadding(self.dp(10), 0, 0, 0);
|
||||||
|
var nameTv = makeText(String(item.name || item.key || "未命名蓝图项"), 14, textColor, true);
|
||||||
|
info.addView(nameTv);
|
||||||
|
var sub = item.type === "section" ? "分组标题" : ("配置键:" + String(item.key || "未填写"));
|
||||||
|
info.addView(makeText(sub, 11, subTextColor, false));
|
||||||
|
row.addView(info, new android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 1));
|
||||||
|
card.addView(row);
|
||||||
|
|
||||||
|
var actions = new android.widget.LinearLayout(context);
|
||||||
|
actions.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
actions.setGravity(android.view.Gravity.RIGHT | android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
actions.setPadding(0, self.dp(9), 0, 0);
|
||||||
|
if (idx > 0) actions.addView(makeChip("上搬", subTextColor, function() { var tmp = schema[idx]; schema[idx] = schema[idx - 1]; schema[idx - 1] = tmp; refreshPanel(); }));
|
||||||
|
if (idx < schema.length - 1) actions.addView(makeChip("下搬", subTextColor, function() { var tmp = schema[idx]; schema[idx] = schema[idx + 1]; schema[idx + 1] = tmp; refreshPanel(); }));
|
||||||
|
actions.addView(makeChip("编辑", primaryDeep, function() {
|
||||||
|
self.state.editingSchemaIndex = idx;
|
||||||
|
clearDraft();
|
||||||
|
if (self.state.toolAppActive && self.pushToolAppPage) self.pushToolAppPage("schema_editor");
|
||||||
|
else refreshPanel();
|
||||||
|
}));
|
||||||
|
actions.addView(makeChip("移除", dangerColor, function() { schema.splice(idx, 1); refreshPanel(); }));
|
||||||
|
card.addView(actions);
|
||||||
|
addWithMargins(list, card, 2, 4, 2, 6);
|
||||||
|
})(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
scroll.addView(list);
|
||||||
|
panel.addView(scroll, new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, 0, 1));
|
||||||
|
|
||||||
|
var bottom = new android.widget.LinearLayout(context);
|
||||||
|
bottom.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
bottom.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
bottom.setPadding(0, self.dp(8), 0, 0);
|
||||||
|
var resetBtn = makeChip("恢复默认蓝图", dangerColor, function() {
|
||||||
|
ConfigManager.resetSchema();
|
||||||
|
self.state.tempSchema = null;
|
||||||
|
clearDraft();
|
||||||
|
showToast("已恢复默认蓝图");
|
||||||
|
refreshPanel();
|
||||||
|
});
|
||||||
|
bottom.addView(resetBtn, new android.widget.LinearLayout.LayoutParams(0, self.dp(42), 1));
|
||||||
|
var saveBtn = self.ui.createSolidButton(self, "保存蓝图", primaryColor, T && T.onPrimary ? T.onPrimary : android.graphics.Color.WHITE, function() {
|
||||||
|
ConfigManager.saveSchema(schema);
|
||||||
|
self.state.tempSchema = null;
|
||||||
|
clearDraft();
|
||||||
|
showToast("蓝图已保存");
|
||||||
|
if (self.state.toolAppActive && self.popToolAppPage) {
|
||||||
|
self.state.editingSchemaIndex = null;
|
||||||
|
self.popToolAppPage("schema_save_all");
|
||||||
|
} else {
|
||||||
|
self.hideAllPanels();
|
||||||
|
self.showPanelAvoidBall("settings");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var saveLp = new android.widget.LinearLayout.LayoutParams(0, self.dp(42), 1);
|
||||||
|
saveLp.setMargins(self.dp(8), 0, 0, 0);
|
||||||
|
bottom.addView(saveBtn, saveLp);
|
||||||
|
panel.addView(bottom, lpFullWrap());
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
var editIdx = this.state.editingSchemaIndex;
|
||||||
|
if (this.state.schemaEditingDraftIndex !== editIdx || !this.state.schemaEditingDraft) {
|
||||||
|
var baseItem = (editIdx === -1) ? { type: "bool", name: "", key: "" } : (schema[editIdx] ? JSON.parse(JSON.stringify(schema[editIdx])) : { type: "bool", name: "", key: "" });
|
||||||
|
this.state.schemaEditingDraft = baseItem;
|
||||||
|
this.state.schemaEditingDraftIndex = editIdx;
|
||||||
|
}
|
||||||
|
var editItem = this.state.schemaEditingDraft;
|
||||||
|
if (!editItem.type) editItem.type = "bool";
|
||||||
|
|
||||||
|
var formCard = new android.widget.LinearLayout(context);
|
||||||
|
formCard.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
|
formCard.setPadding(self.dp(14), self.dp(12), self.dp(14), self.dp(12));
|
||||||
|
try { formCard.setBackground(self.ui.createStrokeDrawable(cardColor, self.withAlpha(strokeColor, isDark ? 0.32 : 0.42), self.dp(1), self.dp(20))); } catch(eFormBg) {}
|
||||||
|
|
||||||
|
var editTitle = makeText(editIdx === -1 ? "添加蓝图项" : "整理蓝图项", 17, textColor, true);
|
||||||
|
formCard.addView(editTitle);
|
||||||
|
var editHint = makeText("修改后先“暂存”,回到列表再统一保存蓝图。", 12, subTextColor, false);
|
||||||
|
editHint.setPadding(0, self.dp(4), 0, self.dp(10));
|
||||||
|
formCard.addView(editHint);
|
||||||
|
|
||||||
|
var schemaInlineNotice = makeText("", 12, primaryDeep, false);
|
||||||
|
schemaInlineNotice.setPadding(self.dp(12), self.dp(8), self.dp(12), self.dp(8));
|
||||||
|
schemaInlineNotice.setVisibility(android.view.View.GONE);
|
||||||
|
function updateSchemaInlineNotice(msg, kind) {
|
||||||
|
try {
|
||||||
|
var color = String(kind || "info") === "error" ? dangerColor : primaryDeep;
|
||||||
|
schemaInlineNotice.setText(String(msg || ""));
|
||||||
|
schemaInlineNotice.setTextColor(color);
|
||||||
|
schemaInlineNotice.setBackground(self.ui.createStrokeDrawable(self.withAlpha(color, isDark ? 0.18 : 0.08), self.withAlpha(color, isDark ? 0.42 : 0.25), self.dp(1), self.dp(14)));
|
||||||
|
schemaInlineNotice.setVisibility(android.view.View.VISIBLE);
|
||||||
|
} catch(eNotice) {}
|
||||||
|
}
|
||||||
|
formCard.addView(schemaInlineNotice, lpFullWrap());
|
||||||
|
|
||||||
|
var scroll2 = new android.widget.ScrollView(context);
|
||||||
|
try { scroll2.setVerticalScrollBarEnabled(false); scroll2.setOverScrollMode(android.view.View.OVER_SCROLL_NEVER); } catch(eScroll2) {}
|
||||||
|
var form = new android.widget.LinearLayout(context);
|
||||||
|
form.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
|
scroll2.addView(form);
|
||||||
|
|
||||||
|
function createInput(label, key, inputType, hint) {
|
||||||
|
var box = new android.widget.LinearLayout(context);
|
||||||
|
box.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
|
box.setPadding(0, 0, 0, self.dp(10));
|
||||||
|
box.addView(makeText(label, 12, subTextColor, false));
|
||||||
|
var et = new android.widget.EditText(context);
|
||||||
|
et.setText(String(editItem[key] !== undefined && editItem[key] !== null ? editItem[key] : ""));
|
||||||
|
et.setTextColor(textColor);
|
||||||
|
et.setHint(String(hint || ""));
|
||||||
|
et.setHintTextColor(self.withAlpha(subTextColor, 0.55));
|
||||||
|
et.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 14);
|
||||||
|
et.setSingleLine(true);
|
||||||
|
et.setBackground(self.ui.createStrokeDrawable(inputBgColor, self.withAlpha(strokeColor, 0.55), self.dp(1), self.dp(12)));
|
||||||
|
et.setPadding(self.dp(12), self.dp(7), self.dp(12), self.dp(7));
|
||||||
|
if (inputType) et.setInputType(inputType);
|
||||||
|
box.addView(et, lpFullWrap());
|
||||||
|
form.addView(box, lpFullWrap());
|
||||||
|
return { input: et, getValue: function() { return String(et.getText()); } };
|
||||||
|
}
|
||||||
|
|
||||||
|
var inputName = null;
|
||||||
|
var inputKey = null;
|
||||||
|
var inputMin = null;
|
||||||
|
var inputMax = null;
|
||||||
|
var inputStep = null;
|
||||||
|
var inputAction = null;
|
||||||
|
|
||||||
|
function syncDraftFromInputs() {
|
||||||
|
try {
|
||||||
|
if (inputName) editItem.name = inputName.getValue();
|
||||||
|
if (inputKey) editItem.key = inputKey.getValue();
|
||||||
|
if (inputMin) editItem.min = inputMin.getValue();
|
||||||
|
if (inputMax) editItem.max = inputMax.getValue();
|
||||||
|
if (inputStep) editItem.step = inputStep.getValue();
|
||||||
|
if (inputAction) editItem.action = inputAction.getValue();
|
||||||
|
self.state.schemaEditingDraft = editItem;
|
||||||
|
self.state.schemaEditingDraftIndex = editIdx;
|
||||||
|
} catch(eSync) { safeLog(null, 'e', "schema draft sync err=" + String(eSync)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
var typeRow = new android.widget.LinearLayout(context);
|
||||||
|
typeRow.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
typeRow.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
typeRow.setPadding(0, 0, 0, self.dp(10));
|
||||||
|
typeRow.addView(makeText("项目类型", 12, subTextColor, false), new android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 1));
|
||||||
|
var types = ["section", "bool", "int", "float", "text", "action"];
|
||||||
|
var typeNames = { section: "分组标题", bool: "开关", int: "整数", float: "小数", text: "文本", action: "动作入口" };
|
||||||
|
typeRow.addView(makeChip(typeNames[String(editItem.type)] || String(editItem.type), primaryDeep, function() {
|
||||||
|
syncDraftFromInputs();
|
||||||
|
var currIdx = types.indexOf(String(editItem.type || "bool"));
|
||||||
|
if (currIdx < 0) currIdx = 1;
|
||||||
|
editItem.type = types[(currIdx + 1) % types.length];
|
||||||
|
self.state.schemaEditingDraft = editItem;
|
||||||
|
self.state.schemaEditingDraftIndex = editIdx;
|
||||||
|
refreshPanel();
|
||||||
|
}));
|
||||||
|
form.addView(typeRow, lpFullWrap());
|
||||||
|
|
||||||
|
inputName = createInput("显示名字", "name", android.text.InputType.TYPE_CLASS_TEXT, "例如:漂浮气球");
|
||||||
|
if (editItem.type !== "section") {
|
||||||
|
inputKey = createInput("配置键", "key", android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS, "例如:BALL_SIZE_DP");
|
||||||
|
}
|
||||||
|
if (editItem.type === "int" || editItem.type === "float") {
|
||||||
|
inputMin = createInput("最小值", "min", android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED, "可留空");
|
||||||
|
inputMax = createInput("最大值", "max", android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED, "可留空");
|
||||||
|
inputStep = createInput("步进", "step", android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL, "可留空");
|
||||||
|
}
|
||||||
|
if (editItem.type === "action") {
|
||||||
|
inputAction = createInput("动作 ID", "action", android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS, "例如:open_btn_mgr");
|
||||||
|
}
|
||||||
|
|
||||||
|
formCard.addView(scroll2, new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, 0, 1));
|
||||||
|
panel.addView(formCard, new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, 0, 1));
|
||||||
|
|
||||||
|
var editBottom = new android.widget.LinearLayout(context);
|
||||||
|
editBottom.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
|
editBottom.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
|
editBottom.setPadding(0, self.dp(8), 0, 0);
|
||||||
|
editBottom.addView(makeChip("不改了", subTextColor, function() {
|
||||||
|
clearDraft();
|
||||||
|
self.state.editingSchemaIndex = null;
|
||||||
|
if (self.state.toolAppActive && self.popToolAppPage) {
|
||||||
|
self.state.keepSchemaEditorState = true;
|
||||||
|
self.popToolAppPage("schema_edit_back");
|
||||||
|
} else refreshPanel();
|
||||||
|
}), new android.widget.LinearLayout.LayoutParams(0, self.dp(42), 1));
|
||||||
|
|
||||||
|
var saveDraftBtn = self.ui.createSolidButton(self, "暂存蓝图项", primaryColor, T && T.onPrimary ? T.onPrimary : android.graphics.Color.WHITE, function() {
|
||||||
|
try {
|
||||||
|
syncDraftFromInputs();
|
||||||
|
normalizeItem(editItem);
|
||||||
|
var err = validateItem(editItem);
|
||||||
|
if (err) {
|
||||||
|
updateSchemaInlineNotice(err, "error");
|
||||||
|
try { scroll2.fullScroll(android.view.View.FOCUS_UP); } catch(eFocusUp) {}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (editIdx === -1) schema.push(JSON.parse(JSON.stringify(editItem)));
|
||||||
|
else schema[editIdx] = JSON.parse(JSON.stringify(editItem));
|
||||||
|
clearDraft();
|
||||||
|
self.state.editingSchemaIndex = null;
|
||||||
|
if (self.state.toolAppActive && self.popToolAppPage) {
|
||||||
|
self.state.keepSchemaEditorState = true;
|
||||||
|
self.popToolAppPage("schema_edit_save");
|
||||||
|
} else refreshPanel();
|
||||||
|
} catch(eSave) {
|
||||||
|
updateSchemaInlineNotice("暂存失败:" + String(eSave), "error");
|
||||||
|
try { scroll2.fullScroll(android.view.View.FOCUS_UP); } catch(eFocusUp2) {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var saveDraftLp = new android.widget.LinearLayout.LayoutParams(0, self.dp(42), 1);
|
||||||
|
saveDraftLp.setMargins(self.dp(8), 0, 0, 0);
|
||||||
|
editBottom.addView(saveDraftBtn, saveDraftLp);
|
||||||
|
panel.addView(editBottom, lpFullWrap());
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -128,17 +128,6 @@ FloatBallAppWM.prototype.close = function() {
|
|||||||
|
|
||||||
safeLog(this.L, 'i', "close done");
|
safeLog(this.L, 'i', "close done");
|
||||||
|
|
||||||
// # 清理日志定时器
|
|
||||||
try {
|
|
||||||
if (this.L) {
|
|
||||||
try { this.L._flushBuffer(); } catch (eFlushLog0) { safeLog(this.L, 'e', "logger flush fail: " + String(eFlushLog0)); }
|
|
||||||
if (this.L._flushTimer) {
|
|
||||||
this.L._flushTimer.cancel();
|
|
||||||
this.L._flushTimer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (eLog) {}
|
|
||||||
|
|
||||||
// # 清空缓存
|
// # 清空缓存
|
||||||
try {
|
try {
|
||||||
this._iconLru = null;
|
this._iconLru = null;
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
"alg": "SHA256withRSA",
|
"alg": "SHA256withRSA",
|
||||||
"files": {
|
"files": {
|
||||||
"th_01_base.js": {
|
"th_01_base.js": {
|
||||||
"sha256": "f8651c6ec22e7d06bb3ef2097ee8909523b149afbf5d8b34f9b5c79d8507598a",
|
"sha256": "e465a92b21f6819079255719bfe41c28a42ff3716f1d29b399897bc299ef92ec",
|
||||||
"size": 57150
|
"size": 54633
|
||||||
},
|
},
|
||||||
"th_02_core.js": {
|
"th_02_core.js": {
|
||||||
"sha256": "3c5c498d200e961d48fc9ca3f885475e770ecb32b83ec6a89d23df3f88aed1c9",
|
"sha256": "7bfd21df21c137595c3e2a8724b3eb3f0cce82ef0dd18b732de08e9be30b2ba3",
|
||||||
"size": 4664
|
"size": 4631
|
||||||
},
|
},
|
||||||
"th_03_icon.js": {
|
"th_03_icon.js": {
|
||||||
"sha256": "717f7f37474d3616c2cd944581455f600020a850ec8812100d0546ec1302c987",
|
"sha256": "717f7f37474d3616c2cd944581455f600020a850ec8812100d0546ec1302c987",
|
||||||
@@ -18,8 +18,8 @@
|
|||||||
"size": 42568
|
"size": 42568
|
||||||
},
|
},
|
||||||
"th_05_persistence.js": {
|
"th_05_persistence.js": {
|
||||||
"sha256": "59fc504c04f6ea397faee33567a773fca175379cba812c37b8ae8c626bc34002",
|
"sha256": "7fd2a62275bd26fcd940202057480fca7a8a800eaeb1fcb9d52003e255d1ef60",
|
||||||
"size": 15861
|
"size": 14763
|
||||||
},
|
},
|
||||||
"th_06_icon_parser.js": {
|
"th_06_icon_parser.js": {
|
||||||
"sha256": "25b95a5df634a7ee359f3ab798e4d3154a71c24016f7b4bf8a658096644b2484",
|
"sha256": "25b95a5df634a7ee359f3ab798e4d3154a71c24016f7b4bf8a658096644b2484",
|
||||||
@@ -34,16 +34,16 @@
|
|||||||
"size": 7938
|
"size": 7938
|
||||||
},
|
},
|
||||||
"th_09_animation.js": {
|
"th_09_animation.js": {
|
||||||
"sha256": "2570ffbbc33fa2318e27c5e99c4e78e1bf96c7da8ec134053acda009207488cb",
|
"sha256": "7c4b673869978f9015b8641bd2266fc7bbd2131f96338b4bb9c12fab11c50468",
|
||||||
"size": 42007
|
"size": 41346
|
||||||
},
|
},
|
||||||
"th_10_shell.js": {
|
"th_10_shell.js": {
|
||||||
"sha256": "0ed793079c2f6ba7d29f4c0d411705cb72419f45f572cbe37ed32ac16527a8bc",
|
"sha256": "0ed793079c2f6ba7d29f4c0d411705cb72419f45f572cbe37ed32ac16527a8bc",
|
||||||
"size": 1094
|
"size": 1094
|
||||||
},
|
},
|
||||||
"th_11_action.js": {
|
"th_11_action.js": {
|
||||||
"sha256": "a0142d26621f3d076bd1b749f2885af2c0806c9f206e362a3b3680a5d2312b31",
|
"sha256": "1ba348415e891093bcf49619d950e9653e1c7323c3d35f74f6f71bec14b7c9e6",
|
||||||
"size": 13545
|
"size": 13838
|
||||||
},
|
},
|
||||||
"th_12_rebuild.js": {
|
"th_12_rebuild.js": {
|
||||||
"sha256": "7b820e813d2dd8866778fefe8bfeb6aca227bb1a32a89d318de830178f19824f",
|
"sha256": "7b820e813d2dd8866778fefe8bfeb6aca227bb1a32a89d318de830178f19824f",
|
||||||
@@ -53,20 +53,32 @@
|
|||||||
"sha256": "9052e01ccdc0af29615ef8e72550d7d312240f9ab36ebfb66e673c92ab2e4b9c",
|
"sha256": "9052e01ccdc0af29615ef8e72550d7d312240f9ab36ebfb66e673c92ab2e4b9c",
|
||||||
"size": 22308
|
"size": 22308
|
||||||
},
|
},
|
||||||
|
"th_14_color_picker.js": {
|
||||||
|
"sha256": "2f6378fbb718d4b31cf11d3047cee6b32af93cfbb932442da29dd05225881432",
|
||||||
|
"size": 23870
|
||||||
|
},
|
||||||
|
"th_14_icon_picker.js": {
|
||||||
|
"sha256": "1df5c4bf82e68de24d7b89c852a4d9878768451effe086e8ddb86620ecc98c35",
|
||||||
|
"size": 23906
|
||||||
|
},
|
||||||
"th_14_panels.js": {
|
"th_14_panels.js": {
|
||||||
"sha256": "4b73af93ff5b8fa8ffadf76f936732b93a32ccff8a6623b96f9ad3bbb8114ec8",
|
"sha256": "33ed77006c3857a9eb93a72363a557ad87c425531e9d9d88eebc4bc8b4b28065",
|
||||||
"size": 304993
|
"size": 276124
|
||||||
|
},
|
||||||
|
"th_14_schema_editor.js": {
|
||||||
|
"sha256": "5669d0b5a16f770bed24eedee24203df57f7cbc7910c840931e533adac1ef146",
|
||||||
|
"size": 20484
|
||||||
},
|
},
|
||||||
"th_15_extra.js": {
|
"th_15_extra.js": {
|
||||||
"sha256": "5fcd5a8146c6bc68e8adc6660c9b12d1f918d7a5a83e00d745a7e18e34ad6f39",
|
"sha256": "2c4e560b793ee54f9338cc44bd41a056cbf8688560f9494920322c88d04be219",
|
||||||
"size": 112080
|
"size": 128697
|
||||||
},
|
},
|
||||||
"th_16_entry.js": {
|
"th_16_entry.js": {
|
||||||
"sha256": "6c59d9891cd010647f84c3db93f1cf95c7bbfb758470ea21044bf72eb8ff73d1",
|
"sha256": "652aa70214a9419923785e528a067d3828094fde48fc9c8c57cfda1e08206e25",
|
||||||
"size": 12799
|
"size": 12479
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"keyId": "toolhub-targets-2026-rsa3072",
|
"keyId": "toolhub-targets-2026-rsa3072",
|
||||||
"schema": 2,
|
"schema": 2,
|
||||||
"version": 20260521224041
|
"version": 20260522222851
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
OcvlczPduvM0/xKzxRszzLAAOoXdCJ5vj0tf38jAHCYmPA+w0E2JSHIR3uSdr7tBNS42SeBnoHctm9PL00HyaytJvS/N+QIUo8oe6UWK5kVxx5xfeMqmwScGHV6tt93BVc03SwAKepaQZE0dBOFpsEGADwuoVHUEuwsFgRlc6Wl3UuGhcDVrALXgYlZBLy51fs8DmBHxK5CM26Oi2pLC/mI2VpwqMkx64VmsJtgbtVwQdFmwM2Y7tRUf9bGFkPld2gSvWyAAEk/Zul/6z61DHwCSmk0HIuIUb/yFBRxDtBhgQx50jUtKu6JEHhEMFe/eLkb/lfwXPmNIuoHIF89/t8Rf7k7cd5ZrolqeVR0uYcXlmJ3i8nadasnJn1NJh6YobbnmLOoC1NQm5mw2l8e0Q0B+5HEG2NyfxVHxgh1dIvGll2MroJqzpNMTeUW7adE3UBc/wgTO8s6MBAhs+lNLFikgtMvCEDczwymPOn2wBuRxrUY+Ni1UJveGcbNhmUUH
|
Wt5bWVBi/YnfXYbb1pEQNWYaD0nbZ6QqW1NKp791UCjKV+Qlen6Tt9NNDYCDYwITODZAp3FPJfAzVkKawUX/ROh9u81UExKBvXGJJ5JQT9PwbrbP1JJ3oPV3CDFUTfwMCc7ev2c5R6hL+29CXEksRYXH+bqGW9fTvOAYeHsa8rRZTPXyAvH2f36XTuc7wXHvKpwLjmPZt68Ep4ICEJFi+wHZPS3r2qljsYFUmbSRCRPuv/E4pqVIz33vWaF3gepQgeNVAjnJ8c2dmQhjKiZ0wIOmOQqwNbDXjNYZNUrXoaPzJV/6OIzJRK8MyDWQbiWBwZwm3CJCZKfdI1qR1TGScInWOBBGhJ7IDilElGTHd6wwQsw4Y4h6KBqLaWT5bzxp2x+vRTXYYdc6RGR0yaauWVTqCCE2zf4Z6IfRNht/2+BZ4VG4W7WhEN72zdbPihfsJcxPUjQklN5gp3PScEI9PwymlecsDHOHmDSYFER3TUai3Uds7DQiTYjVxSTpce0f
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ MODULES = [
|
|||||||
"th_05_persistence.js", "th_06_icon_parser.js", "th_07_shortcut.js",
|
"th_05_persistence.js", "th_06_icon_parser.js", "th_07_shortcut.js",
|
||||||
"th_08_content.js", "th_09_animation.js", "th_10_shell.js",
|
"th_08_content.js", "th_09_animation.js", "th_10_shell.js",
|
||||||
"th_11_action.js", "th_12_rebuild.js", "th_13_panel_ui.js",
|
"th_11_action.js", "th_12_rebuild.js", "th_13_panel_ui.js",
|
||||||
"th_14_panels.js", "th_15_extra.js", "th_16_entry.js",
|
"th_14_panels.js", "th_14_color_picker.js", "th_14_icon_picker.js",
|
||||||
|
"th_14_schema_editor.js", "th_15_extra.js", "th_16_entry.js",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user