fix: add ToolApp edge swipe back fallback

This commit is contained in:
7015725
2026-05-14 02:51:46 +08:00
parent 96bbb77127
commit 1d31638073
4 changed files with 88 additions and 13 deletions

View File

@@ -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 对齐。

View File

@@ -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;

View File

@@ -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
} }

View File

@@ -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+