fix: add ToolApp edge swipe back fallback
This commit is contained in:
@@ -19,7 +19,7 @@ https://git.xin-blog.com/linshenjianlu/ShortX_ToolHub
|
|||||||
- **防回滚**:入口内置 `MIN_TRUSTED_MANIFEST_VERSION`,并记录本地已信任清单版本,拒绝旧版本清单。
|
- **防回滚**:入口内置 `MIN_TRUSTED_MANIFEST_VERSION`,并记录本地已信任清单版本,拒绝旧版本清单。
|
||||||
- **本地可信回退**:网络或远端清单异常时,不盲目覆盖;已验证过的本地模块可继续使用。
|
- **本地可信回退**:网络或远端清单异常时,不盲目覆盖;已验证过的本地模块可继续使用。
|
||||||
- **App 化设置页**:设置主页、按钮管理、按钮编辑等页面使用统一 Shell 与页面栈,支持顶部返回/关闭。
|
- **App 化设置页**:设置主页、按钮管理、按钮编辑等页面使用统一 Shell 与页面栈,支持顶部返回/关闭。
|
||||||
- **系统返回适配**:支持导航键返回与预测返回手势,优先在 ToolHub 页面栈内返回,栈空后关闭面板。
|
- **系统返回适配**:支持导航键返回;悬浮窗内置左右边缘滑动返回,优先在 ToolHub 页面栈内返回,栈空后关闭面板。
|
||||||
- **ShortX 图标选择器**:支持图标点选、搜索、分页、自适应列数,不再依赖手填图标名。
|
- **ShortX 图标选择器**:支持图标点选、搜索、分页、自适应列数,不再依赖手填图标名。
|
||||||
- **颜色选择器**:使用折叠式完整调色板,支持常用色、最近色、RGB、透明度和实时预览;避免重复内联色板。
|
- **颜色选择器**:使用折叠式完整调色板,支持常用色、最近色、RGB、透明度和实时预览;避免重复内联色板。
|
||||||
- **自适应布局**:ToolApp 根据屏幕尺寸调整宽高,按钮管理页底部操作区保持可见。
|
- **自适应布局**:ToolApp 根据屏幕尺寸调整宽高,按钮管理页底部操作区保持可见。
|
||||||
@@ -191,7 +191,8 @@ toolhub-targets-2026-rsa3072
|
|||||||
|
|
||||||
- 设置、按钮管理、按钮编辑统一运行在 ToolApp Shell 内。
|
- 设置、按钮管理、按钮编辑统一运行在 ToolApp Shell 内。
|
||||||
- 顶部栏提供返回与关闭,子页面优先通过页面栈返回。
|
- 顶部栏提供返回与关闭,子页面优先通过页面栈返回。
|
||||||
- 系统返回键 / 手势返回会优先回到上一页;没有上一页时关闭 ToolApp。
|
- 系统返回键会优先回到上一页;没有上一页时关闭 ToolApp。
|
||||||
|
- 悬浮窗无法稳定接入系统级预测性返回动画,因此 ToolHub 内置左右边缘滑动返回作为可用替代。
|
||||||
- 面板尺寸按屏幕自适应,减少小屏溢出与大屏空白。
|
- 面板尺寸按屏幕自适应,减少小屏溢出与大屏空白。
|
||||||
- 按钮管理页底部操作区保持可见,避免被列表内容挤出屏幕。
|
- 按钮管理页底部操作区保持可见,避免被列表内容挤出屏幕。
|
||||||
|
|
||||||
@@ -274,7 +275,7 @@ ToolHub.js.sha256
|
|||||||
**功能改进**
|
**功能改进**
|
||||||
|
|
||||||
- 新增 ToolApp 式设置主页与页面栈,设置、按钮管理、按钮编辑改为更接近 App 的层级导航。
|
- 新增 ToolApp 式设置主页与页面栈,设置、按钮管理、按钮编辑改为更接近 App 的层级导航。
|
||||||
- 支持系统导航返回与预测返回手势;返回优先处理 ToolHub 页面栈,栈空后关闭面板。
|
- 支持系统导航返回;因 ToolHub 是悬浮窗 Overlay,系统级预测性返回动画不稳定,改为内置左右边缘滑动返回。
|
||||||
- ToolApp 尺寸按屏幕自适应,按钮管理页底部操作区保持可见。
|
- ToolApp 尺寸按屏幕自适应,按钮管理页底部操作区保持可见。
|
||||||
- 按钮管理与按钮编辑布局继续轻量化,减少说明文字和视觉负担。
|
- 按钮管理与按钮编辑布局继续轻量化,减少说明文字和视觉负担。
|
||||||
- ShortX 图标选择器风格与设置 UI 对齐。
|
- ShortX 图标选择器风格与设置 UI 对齐。
|
||||||
|
|||||||
@@ -521,14 +521,76 @@ FloatBallAppWM.prototype.closeToolApp = function() {
|
|||||||
} catch (e) { safeLog(this.L, 'e', "closeToolApp fail: " + String(e)); }
|
} catch (e) { safeLog(this.L, 'e', "closeToolApp fail: " + String(e)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FloatBallAppWM.prototype.createToolAppEdgeBackStrip = function(edge) {
|
||||||
|
var self = this;
|
||||||
|
var strip = new android.view.View(context);
|
||||||
|
strip.setBackgroundColor(android.graphics.Color.TRANSPARENT);
|
||||||
|
var downX = 0;
|
||||||
|
var downY = 0;
|
||||||
|
var active = false;
|
||||||
|
var moved = false;
|
||||||
|
strip.setOnTouchListener(new android.view.View.OnTouchListener({
|
||||||
|
onTouch: function(v, event) {
|
||||||
|
try {
|
||||||
|
if (!event) return false;
|
||||||
|
var action = event.getActionMasked();
|
||||||
|
if (action === android.view.MotionEvent.ACTION_DOWN) {
|
||||||
|
downX = event.getRawX();
|
||||||
|
downY = event.getRawY();
|
||||||
|
active = !!(self.state && self.state.toolAppActive);
|
||||||
|
moved = false;
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
if (!active) return false;
|
||||||
|
if (action === android.view.MotionEvent.ACTION_MOVE) {
|
||||||
|
var mx = event.getRawX() - downX;
|
||||||
|
var my = event.getRawY() - downY;
|
||||||
|
var validDir = (edge === 0 && mx > 0) || (edge === 1 && mx < 0);
|
||||||
|
if (validDir && Math.abs(mx) > self.dp(8) && Math.abs(mx) > Math.abs(my)) {
|
||||||
|
moved = true;
|
||||||
|
var p = Math.min(1, Math.abs(mx) / self.dp(120));
|
||||||
|
var panel = self.state ? self.state.toolAppRoot : null;
|
||||||
|
if (panel) {
|
||||||
|
try {
|
||||||
|
panel.setTranslationX((edge === 0 ? 1 : -1) * self.dp(28) * p);
|
||||||
|
panel.setAlpha(1.0 - 0.10 * p);
|
||||||
|
} catch (eAnim) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (action === android.view.MotionEvent.ACTION_UP || action === android.view.MotionEvent.ACTION_CANCEL) {
|
||||||
|
var ux = event.getRawX() - downX;
|
||||||
|
var uy = event.getRawY() - downY;
|
||||||
|
var okDir = (edge === 0 && ux > self.dp(56)) || (edge === 1 && ux < -self.dp(56));
|
||||||
|
var ok = moved && okDir && Math.abs(ux) > Math.abs(uy) * 1.2;
|
||||||
|
try { self.resetPanelPredictiveBackVisual(self.state ? self.state.toolAppRoot : null); } catch (eReset) {}
|
||||||
|
active = false;
|
||||||
|
if (ok) {
|
||||||
|
try { self.popToolAppPage("edge_swipe_back"); } catch (ePop) {}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
try { safeLog(self.L, 'w', "tool app edge back fail: " + String(e)); } catch(eLog) {}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return strip;
|
||||||
|
};
|
||||||
|
|
||||||
FloatBallAppWM.prototype.buildToolAppShell = function(contentView, title, canBack) {
|
FloatBallAppWM.prototype.buildToolAppShell = function(contentView, title, canBack) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var isDark = this.isDarkTheme();
|
var isDark = this.isDarkTheme();
|
||||||
var C = this.ui.colors;
|
var C = this.ui.colors;
|
||||||
var root = new android.widget.LinearLayout(context);
|
var root = new android.widget.FrameLayout(context);
|
||||||
root.setOrientation(android.widget.LinearLayout.VERTICAL);
|
var body = new android.widget.LinearLayout(context);
|
||||||
root.setBackground(this.ui.createRoundDrawable(isDark ? C.bgDark : C.bgLight, this.dp(18)));
|
body.setOrientation(android.widget.LinearLayout.VERTICAL);
|
||||||
try { root.setElevation(this.dp(10)); } catch(eElev) { safeLog(null, 'e', "catch " + String(eElev)); }
|
body.setBackground(this.ui.createRoundDrawable(isDark ? C.bgDark : C.bgLight, this.dp(18)));
|
||||||
|
try { body.setElevation(this.dp(10)); } catch(eElev) { safeLog(null, 'e', "catch " + String(eElev)); }
|
||||||
|
root.addView(body, new android.widget.FrameLayout.LayoutParams(-1, -1));
|
||||||
|
|
||||||
var bar = new android.widget.LinearLayout(context);
|
var bar = new android.widget.LinearLayout(context);
|
||||||
bar.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
bar.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||||
@@ -558,7 +620,7 @@ FloatBallAppWM.prototype.buildToolAppShell = function(contentView, title, canBac
|
|||||||
btnClose.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 18);
|
btnClose.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 18);
|
||||||
btnClose.setPadding(this.dp(8), 0, this.dp(8), 0);
|
btnClose.setPadding(this.dp(8), 0, this.dp(8), 0);
|
||||||
bar.addView(btnClose, new android.widget.LinearLayout.LayoutParams(this.dp(42), this.dp(38)));
|
bar.addView(btnClose, new android.widget.LinearLayout.LayoutParams(this.dp(42), this.dp(38)));
|
||||||
root.addView(bar, new android.widget.LinearLayout.LayoutParams(-1, this.dp(52)));
|
body.addView(bar, new android.widget.LinearLayout.LayoutParams(-1, this.dp(52)));
|
||||||
|
|
||||||
var host = new android.widget.FrameLayout(context);
|
var host = new android.widget.FrameLayout(context);
|
||||||
if (contentView) {
|
if (contentView) {
|
||||||
@@ -566,7 +628,19 @@ FloatBallAppWM.prototype.buildToolAppShell = function(contentView, title, canBac
|
|||||||
try { contentView.setElevation(0); } catch(eEl) { safeLog(null, 'e', "catch " + String(eEl)); }
|
try { contentView.setElevation(0); } catch(eEl) { safeLog(null, 'e', "catch " + String(eEl)); }
|
||||||
host.addView(contentView, new android.widget.FrameLayout.LayoutParams(-1, -1));
|
host.addView(contentView, new android.widget.FrameLayout.LayoutParams(-1, -1));
|
||||||
}
|
}
|
||||||
root.addView(host, new android.widget.LinearLayout.LayoutParams(-1, 0, 1));
|
body.addView(host, new android.widget.LinearLayout.LayoutParams(-1, 0, 1));
|
||||||
|
|
||||||
|
try {
|
||||||
|
var stripW = this.dp(24);
|
||||||
|
var leftStrip = this.createToolAppEdgeBackStrip(0);
|
||||||
|
var leftLp = new android.widget.FrameLayout.LayoutParams(stripW, -1);
|
||||||
|
leftLp.gravity = android.view.Gravity.START | android.view.Gravity.TOP;
|
||||||
|
root.addView(leftStrip, leftLp);
|
||||||
|
var rightStrip = this.createToolAppEdgeBackStrip(1);
|
||||||
|
var rightLp = new android.widget.FrameLayout.LayoutParams(stripW, -1);
|
||||||
|
rightLp.gravity = android.view.Gravity.END | android.view.Gravity.TOP;
|
||||||
|
root.addView(rightStrip, rightLp);
|
||||||
|
} catch (eStrip) { safeLog(this.L, 'w', "add edge back strip fail: " + String(eStrip)); }
|
||||||
|
|
||||||
this.state.toolAppRoot = root;
|
this.state.toolAppRoot = root;
|
||||||
this.state.toolAppContentHost = host;
|
this.state.toolAppContentHost = host;
|
||||||
|
|||||||
@@ -58,8 +58,8 @@
|
|||||||
"size": 239523
|
"size": 239523
|
||||||
},
|
},
|
||||||
"th_15_extra.js": {
|
"th_15_extra.js": {
|
||||||
"sha256": "44d19f0012f4182b9f9831d4f5a747b43d3b726f98e0480e6c79f54eeff70a5e",
|
"sha256": "c39103bc3728fb6b5f0ced8975d064f50d7f6ef091355391f2f18b0d3c1cdb22",
|
||||||
"size": 76125
|
"size": 79219
|
||||||
},
|
},
|
||||||
"th_16_entry.js": {
|
"th_16_entry.js": {
|
||||||
"sha256": "e7c99c3dfbd6aedab05551426955081ae6cae034754f2f557cefa01dc75dc001",
|
"sha256": "e7c99c3dfbd6aedab05551426955081ae6cae034754f2f557cefa01dc75dc001",
|
||||||
@@ -68,5 +68,5 @@
|
|||||||
},
|
},
|
||||||
"keyId": "toolhub-targets-2026-rsa3072",
|
"keyId": "toolhub-targets-2026-rsa3072",
|
||||||
"schema": 2,
|
"schema": 2,
|
||||||
"version": 20260513102801
|
"version": 20260513185115
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
SOgbhiJKZpLnurFbKp6bXjLe4aj/8aAc4Cia6Cmfls8Rvgykwfd9a9yQ8kODvdEPy3UMGKwf26q6zVnx3KxWLBFZ4raJ3qVLmrkPt0zH3r3ECpqsKK45NLVwWio1JKcL6PLddZoyfypidDOM0OPKJSFGctCVCVIW4T2xZieUqkdA/rn9YpW2wm+XF1zDFuKKrTTnjthPJ/8R1iwFQyWdfO8uhXyVdCDebpoPwKh/+ZIdtnBv94OiRukAb8oJty6n/IxhHNswyLxCQR8RPCjhhjiC6ilt7DgjwZ/uZoZioKYstLCevatZ2H1biyh0HjtiahSNf9wkWzkBSlwobJlW4YuIXXf2GNmzc74hOLJcEqiE7VvJulrsW/DFUVcQvIYdAepMJZqCur9wYHjgZAgO+HFVCcScJGe0kMCoyzppDyOXv++daY58LdahRmAYxqJsozhlAUXFAAJFju09t9rdg6l9GIRkl5296C5wpVtT+1o2QGzJsz1dTskKuMj/yRLR
|
Fsvy+vxIvc2+e29Z+Wq+pxms/IVoB04bKhmiDZB5DYq47f5RD4rc12AiiHPFm6tdYY2JQ4Ri/2XAPFW+GGJnhKSLJ9ngw/eSfEKPwlmLqitLTXUMH0qdl68+3BtoDLrBEF9Io1XnmeaLHizEAOM/Ubu5qc+IeDgEbnoMBWI+1eYp/VkeBRxl1TDDhTkb5yiRDCxES8X67FSismFOGQfCFA5T1oSUmX1YdkUkkd29ihUFnP0Jm+L2UIH+etms2LEsaGDXm7JUlGLK145U3pAsjoZzx/00v1ytyNtmE2qgb0NFAcEJqx6fpmKWfF7Ix0IeUTyeCkQXJsKnGsiYe3RxLAL2GGBc3EanIDQJTgsnb5Q96mV37HmHqGk6l/T3hPMpSDkc2AMq/pD2YQTsahW6k22m+/hHCftIBCO/1HkpkBVx+gkrt09OUZPkREuwq+nERSCowgRZLbmSYCjK2Mkl8jn1sXKk017Ew0EjcVzcyk+8rUVnJo7s/Pz4cZgjIp5+
|
||||||
|
|||||||
Reference in New Issue
Block a user