fix: prefer ToolApp surface back gesture
This commit is contained in:
@@ -105,6 +105,7 @@ var ConfigValidator = {
|
||||
ENABLE_TOOLAPP_INNER_BACK_STRIPS: { type: "bool", default: false },
|
||||
ENABLE_TOOLAPP_SCREEN_BACK_STRIPS: { type: "bool", default: true },
|
||||
TOOLAPP_BACK_COMMIT_DISTANCE_DP: { type: "int", min: 1, max: 480, default: 36 },
|
||||
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: 96 },
|
||||
|
||||
// 功能开关
|
||||
@@ -742,6 +743,7 @@ var ConfigManager = {
|
||||
ENABLE_TOOLAPP_INNER_BACK_STRIPS: false,
|
||||
ENABLE_TOOLAPP_SCREEN_BACK_STRIPS: true,
|
||||
TOOLAPP_BACK_COMMIT_DISTANCE_DP: 36,
|
||||
TOOLAPP_BACK_SURFACE_SLOP_DP: 24,
|
||||
TOOLAPP_BACK_PROGRESS_DISTANCE_DP: 96,
|
||||
ENABLE_BOUNCE: true,
|
||||
BOUNCE_TIMES: 2,
|
||||
@@ -854,13 +856,14 @@ var ConfigManager = {
|
||||
{ key: "CLICK_SLOP_DP", name: "点击位移阈值(dp)", type: "int", min: 1, max: 40, step: 1 },
|
||||
{ key: "TOOLAPP_BACK_GESTURE_MODE", name: "设置页滑动返回模式", type: "single_choice", options: [
|
||||
{ label: "全表面横滑", value: "surface" },
|
||||
{ label: "仅左右边缘", value: "edge" },
|
||||
{ label: "仅面板内部左右边缘", value: "edge" },
|
||||
{ label: "关闭", value: "off" }
|
||||
]},
|
||||
{ key: "TOOLAPP_BACK_EDGE_WIDTH_DP", name: "边缘模式起手宽度", type: "int", min: 1, max: 120, step: 1 },
|
||||
{ key: "ENABLE_TOOLAPP_INNER_BACK_STRIPS", name: "启用旧版页面覆盖热区(不推荐)", type: "bool" },
|
||||
{ key: "ENABLE_TOOLAPP_SCREEN_BACK_STRIPS", name: "启用屏幕空白区返回", type: "bool" },
|
||||
{ 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: "ENABLE_LONG_PRESS", name: "启用长按", type: "bool" },
|
||||
{ key: "LONG_PRESS_MS", name: "长按判定(ms)", type: "int", min: 200, max: 2000, step: 10 },
|
||||
@@ -899,7 +902,7 @@ var ConfigManager = {
|
||||
var needReset = false;
|
||||
if (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_GESTURE_MODE") < 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("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_SURFACE_SLOP_DP") < 0 || sStr.indexOf("TOOLAPP_BACK_PROGRESS_DISTANCE_DP") < 0 || sStr.indexOf("LONG_PRESS_TRIGGERED_MOVE_SLOP_DP") < 0) {
|
||||
needReset = true;
|
||||
}
|
||||
|
||||
@@ -935,6 +938,7 @@ var ConfigManager = {
|
||||
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_SURFACE_SLOP_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"])) {
|
||||
needReset = true;
|
||||
|
||||
@@ -1312,22 +1312,52 @@ FloatBallAppWM.prototype.getToolAppBackGestureMode = function() {
|
||||
var mode = "surface";
|
||||
try { mode = String(this.config.TOOLAPP_BACK_GESTURE_MODE || "surface"); } catch(e) { mode = "surface"; }
|
||||
if (mode !== "edge" && mode !== "surface" && mode !== "off") mode = "surface";
|
||||
// 全面屏手势下物理极致边缘容易被系统抢走;旧配置若停留在 edge,运行期优先回退到 surface。
|
||||
// edge 分支仍保留为 ToolApp 面板内部边缘模式;只有显式把 TOOLAPP_BACK_FORCE_SURFACE 设为 false 时才启用。
|
||||
if (mode === "edge") {
|
||||
var forceSurface = true;
|
||||
try { if (this.config.TOOLAPP_BACK_FORCE_SURFACE === false || String(this.config.TOOLAPP_BACK_FORCE_SURFACE) === "false") forceSurface = false; } catch(eForce) {}
|
||||
if (forceSurface) {
|
||||
try { this.config.TOOLAPP_BACK_GESTURE_MODE = "surface"; } catch(eMig) {}
|
||||
mode = "surface";
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
};
|
||||
|
||||
FloatBallAppWM.prototype.isToolAppBackInteractiveView = function(v) {
|
||||
FloatBallAppWM.prototype.getToolAppBackSurfaceSlopPx = function(commitDistancePx) {
|
||||
var slopDp = 24;
|
||||
try { slopDp = Number(this.config.TOOLAPP_BACK_SURFACE_SLOP_DP || 24); } catch(e) { slopDp = 24; }
|
||||
if (isNaN(slopDp)) slopDp = 24;
|
||||
if (slopDp < 8) slopDp = 8;
|
||||
if (slopDp > 96) slopDp = 96;
|
||||
var px = this.dp(slopDp);
|
||||
try {
|
||||
var c = Number(commitDistancePx || 0);
|
||||
if (!isNaN(c) && c > 0) px = Math.min(px, c);
|
||||
} catch(e2) {}
|
||||
return px;
|
||||
};
|
||||
|
||||
FloatBallAppWM.prototype.isToolAppBackInteractiveView = function(v, dx, dy) {
|
||||
try {
|
||||
if (!v) return false;
|
||||
try { if (v instanceof android.widget.SeekBar) return true; } catch(eSeek) {}
|
||||
try { if (v instanceof android.widget.CompoundButton) return true; } catch(eComp) {}
|
||||
try { if (v instanceof android.widget.Switch) return true; } catch(eSw) {}
|
||||
var adx = Math.abs(Number(dx || 0));
|
||||
var ady = Math.abs(Number(dy || 0));
|
||||
var strongHorizontal = adx > 0 && adx >= ady;
|
||||
try { if (v instanceof android.widget.SeekBar) return strongHorizontal; } catch(eSeek) {}
|
||||
try { if (v instanceof android.widget.CompoundButton) return strongHorizontal; } catch(eComp) {}
|
||||
try { if (v instanceof android.widget.Switch) return strongHorizontal; } catch(eSw) {}
|
||||
try { if (v instanceof android.widget.EditText) return true; } catch(eEdit) {}
|
||||
try { if (v instanceof android.widget.HorizontalScrollView) return true; } catch(eHsv) {}
|
||||
// 普通 Button / 卡片 / 垂直列表 item 不在 DOWN 阶段屏蔽返回;强横滑由 root 在 MOVE 阶段接管。
|
||||
// 垂直 ListView/RecyclerView 也不作为 blocker,保证列表上下滑正常且强横滑可返回。
|
||||
// 不把所有 clickable/longClickable 都当成阻断项:ToolHub 大量卡片/容器为了 ripple 都会 setClickable(true),
|
||||
// 若在 surface 横滑模式下阻断它们,几乎整页都会 rootBackBlocked=true,导致滑动返回一直触发不了。
|
||||
// DOWN 已经放行给子控件,只有超过横滑阈值后才拦截;这里只保留 SeekBar/Switch/EditText/HorizontalScrollView 等强交互控件。
|
||||
try {
|
||||
if (v instanceof android.widget.HorizontalScrollView) {
|
||||
var dir = Number(dx || 0) > 0 ? -1 : 1;
|
||||
try { if (v.canScrollHorizontally && v.canScrollHorizontally(dir)) return true; } catch(eCan) {}
|
||||
return false;
|
||||
}
|
||||
} catch(eHsv) {}
|
||||
// 普通 Button / 卡片 / 垂直列表 item 不作为 blocker;点击和上下滑继续交给子控件,强横滑由 root 接管。
|
||||
// 只有 SeekBar/Switch/EditText/可继续横向滚动的 HorizontalScrollView 在 MOVE 阶段按 dx/dy 细粒度阻断。
|
||||
/* try { if (v.isClickable && v.isClickable()) return true; } catch(eClick) {} */
|
||||
/* try { if (v.isLongClickable && v.isLongClickable()) return true; } catch(eLong) {} */
|
||||
} catch(e) {}
|
||||
@@ -1358,11 +1388,11 @@ FloatBallAppWM.prototype.findToolAppTouchedChild = function(v, rawX, rawY) {
|
||||
return null;
|
||||
};
|
||||
|
||||
FloatBallAppWM.prototype.isToolAppBackBlockedAt = function(root, rawX, rawY) {
|
||||
FloatBallAppWM.prototype.isToolAppBackBlockedAt = function(root, rawX, rawY, dx, dy) {
|
||||
try {
|
||||
var v = this.findToolAppTouchedChild(root, rawX, rawY);
|
||||
while (v && v !== root) {
|
||||
if (this.isToolAppBackInteractiveView && this.isToolAppBackInteractiveView(v)) return true;
|
||||
if (this.isToolAppBackInteractiveView && this.isToolAppBackInteractiveView(v, dx, dy)) return true;
|
||||
try { v = v.getParent ? v.getParent() : null; } catch(eParent) { v = null; }
|
||||
}
|
||||
} catch(e) {}
|
||||
@@ -1417,13 +1447,13 @@ FloatBallAppWM.prototype.buildToolAppShell = function(contentView, title, canBac
|
||||
else if (rw > 0 && rootDownX >= rw - edgeW) { rootEdge = 1; rootBackEligible = true; }
|
||||
} else {
|
||||
rootBackEligible = true;
|
||||
rootBackBlocked = !!(self.isToolAppBackBlockedAt && self.isToolAppBackBlockedAt(this, rootDownRawX, rootDownRawY));
|
||||
rootBackBlocked = false;
|
||||
}
|
||||
// DOWN 必须放行给子控件,surface 模式也不抢按钮/列表/Switch/SeekBar 原始点击。
|
||||
return false;
|
||||
}
|
||||
if (action === android.view.MotionEvent.ACTION_MOVE) {
|
||||
if (!rootBackEligible || rootBackBlocked || rootBackMode === "off") return false;
|
||||
if (!rootBackEligible || rootBackMode === "off") return false;
|
||||
if (!(self.hasToolAppBackTarget && self.hasToolAppBackTarget())) return false;
|
||||
var dx = ev.getX() - rootDownX;
|
||||
var dy = ev.getY() - rootDownY;
|
||||
@@ -1439,7 +1469,14 @@ FloatBallAppWM.prototype.buildToolAppShell = function(contentView, title, canBac
|
||||
}
|
||||
var shouldIntercept = false;
|
||||
if (rootBackMode === "surface") {
|
||||
shouldIntercept = validDir && adx > self.dp(48) && adx > ady * 1.2;
|
||||
var commitDp0 = Number(self.config.TOOLAPP_BACK_COMMIT_DISTANCE_DP || 36);
|
||||
if (isNaN(commitDp0)) commitDp0 = 36;
|
||||
if (commitDp0 < 1) commitDp0 = 1;
|
||||
if (commitDp0 > 480) commitDp0 = 480;
|
||||
var surfaceSlop = self.getToolAppBackSurfaceSlopPx ? self.getToolAppBackSurfaceSlopPx(self.dp(commitDp0)) : Math.min(self.dp(24), self.dp(commitDp0));
|
||||
var blockedNow = !!(self.isToolAppBackBlockedAt && self.isToolAppBackBlockedAt(this, rootDownRawX, rootDownRawY, dx, dy));
|
||||
rootBackBlocked = blockedNow;
|
||||
shouldIntercept = (!blockedNow) && validDir && adx > surfaceSlop && adx > ady * 1.08;
|
||||
} else {
|
||||
var slopDp = Number(self.config.CLICK_SLOP_DP || 6);
|
||||
if (isNaN(slopDp)) slopDp = 6;
|
||||
@@ -1482,7 +1519,7 @@ FloatBallAppWM.prototype.buildToolAppShell = function(contentView, title, canBac
|
||||
var mx = ev.getX() - rootDownX;
|
||||
var my = ev.getY() - rootDownY;
|
||||
var validDir2 = (rootEdge === 0 && mx > 0) || (rootEdge === 1 && mx < 0);
|
||||
var dominance = rootBackMode === "surface" ? 1.2 : 0.75;
|
||||
var dominance = rootBackMode === "surface" ? 1.08 : 0.75;
|
||||
if (validDir2 && Math.abs(mx) > Math.abs(my) * dominance) {
|
||||
var triggerDp = Number(self.config.TOOLAPP_BACK_PROGRESS_DISTANCE_DP || 96);
|
||||
if (isNaN(triggerDp)) triggerDp = 96;
|
||||
@@ -1503,7 +1540,7 @@ FloatBallAppWM.prototype.buildToolAppShell = function(contentView, title, canBac
|
||||
if (commitDp > 480) commitDp = 480;
|
||||
var completeDistance = self.dp(commitDp);
|
||||
var okDir = (rootEdge === 0 && ux > completeDistance) || (rootEdge === 1 && ux < -completeDistance);
|
||||
var ratio = rootBackMode === "surface" ? 1.2 : 0.75;
|
||||
var ratio = rootBackMode === "surface" ? 1.08 : 0.75;
|
||||
var ok = (action === android.view.MotionEvent.ACTION_UP) && rootBackMoved && okDir && Math.abs(ux) > Math.abs(uy) * ratio;
|
||||
var edgeDone = rootEdge;
|
||||
rootBackActive = false;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"alg": "SHA256withRSA",
|
||||
"files": {
|
||||
"th_01_base.js": {
|
||||
"sha256": "c186450c6a64cf51fdf6cc93e45624793596ce9f566d1b18c3e70905459fd618",
|
||||
"size": 57722
|
||||
"sha256": "12c6645e42cb7dd21da495545e69f64d11c9d6b510aabf0d169edf883b57c4ff",
|
||||
"size": 58140
|
||||
},
|
||||
"th_02_core.js": {
|
||||
"sha256": "3c5c498d200e961d48fc9ca3f885475e770ecb32b83ec6a89d23df3f88aed1c9",
|
||||
@@ -58,8 +58,8 @@
|
||||
"size": 304993
|
||||
},
|
||||
"th_15_extra.js": {
|
||||
"sha256": "380272c10e117c2ad09216709d3f7bd3a54ab97b3fa6ce5594ab5fdd252aa48e",
|
||||
"size": 129287
|
||||
"sha256": "8ef8f3b48c324426f9f6926e7e4fbee8cea6f15b6e465c1dad6982bbb00c3af3",
|
||||
"size": 130833
|
||||
},
|
||||
"th_16_entry.js": {
|
||||
"sha256": "6c59d9891cd010647f84c3db93f1cf95c7bbfb758470ea21044bf72eb8ff73d1",
|
||||
@@ -68,5 +68,5 @@
|
||||
},
|
||||
"keyId": "toolhub-targets-2026-rsa3072",
|
||||
"schema": 2,
|
||||
"version": 20260522043019
|
||||
"version": 20260522044045
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
n3ojvi067byhyd0l6vNsePByOJ/dN9Hoa16nhD/9nuU3f0pnNTKjGDS+iHDlO9V2MOsRPRjTlzYR0inJJZaMh2sSjzCmcAOapxqkm2XwItOrtYjgk3yNBO7AwcXH5sYDUXGZ2Tsx95z7dS3sLNyavVUSAKyO3ygzTSQL7EgfWu3LumIiATrHPHL71jvbJRfG1tVUilWF3VYZMyULOJievgCApeX6h4xRgh0eCdgtbn6bDlH4E1gHbapQ+beYKDD2GL1H9msuwyzehxUM4QZVrtOwXHVlCHL4x9Kidm35wMp4H21XCr7UD6N2oRvUsXoEtI6Ugj8dN2Ilvbz0/GO4Nf/v522xbFsPZBj06kD2qiGGJ6ztT3KkfVBv53GRBhN+v/aGimO8ww/YtnUn6njTcF36Mnh98CvE/9BXENU98TYA0zWNOop5WxlyHXOf6rQ3ivMYnsbKzvOX5LrX8uExJawjpUvsoY7ahUJ+h6TDPcyB6Fl3644MKq5ukXgVm1jI
|
||||
d31WnUYPRd99BgqOnWKrh+xaCDIjlON13cKvM9s+T4xno3g11qoenoFo9rBI4Mcu63R783cIYS9PtfZ8ii1hlaB2DMNqebzGXFTi+9u/Yd56D5pV84Jd/SjL1yN6hTwXT9t/bHrS3E9npyyFVLVeponFagKHecgk/3yEe5GSmLAp1QX0o7ecca2L0rO534rMHa4Ml/dkrsGCwPAfWzuru/xpO8KV0zvQ4leSU7YT+ZxgU4o8L+scvXKDEp3wnaldqqy6ekIhk75m4qmVAPw4dsp+b5CtEcWNfgy6SgvkXz+PawvHOmWz67TQa5G4jCDP7EWynHFcF26U8xuO1x4x4bpNLdzImis/Dg14/HavNID0Yc72+3uJEGHL6RyCyGhic8+mG/25vSkB+brfy8qZK5K8stqZLIC1wJ/0IL0ppkx2LoDTyuwfk+vshzJDmiLBaJCgOuiR24ya3sFeDFD0OWLxbgQiXg1MoYNb1FP69h+i0f2ziea9zja2qEQ8aN81
|
||||
|
||||
Reference in New Issue
Block a user