diff --git a/code/th_01_base.js b/code/th_01_base.js index 145d314..40e9cc4 100644 --- a/code/th_01_base.js +++ b/code/th_01_base.js @@ -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; diff --git a/code/th_15_extra.js b/code/th_15_extra.js index 8bf9c26..e79626a 100644 --- a/code/th_15_extra.js +++ b/code/th_15_extra.js @@ -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; diff --git a/manifest.json b/manifest.json index 00c9464..acf7da0 100644 --- a/manifest.json +++ b/manifest.json @@ -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 } diff --git a/manifest.sig b/manifest.sig index 5c01b82..96d65eb 100644 --- a/manifest.sig +++ b/manifest.sig @@ -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