From 0cc6439619f2df30e40854279e5fc05e1b391035 Mon Sep 17 00:00:00 2001 From: 7015725 Date: Sat, 23 May 2026 06:08:24 +0800 Subject: [PATCH] Add edge swipe dismiss for popup overlays --- code/th_14_panels.js | 105 ++++++++++++++++++++++++++++++++++++++++++- manifest.json | 6 +-- manifest.sig | 2 +- 3 files changed, 108 insertions(+), 5 deletions(-) diff --git a/code/th_14_panels.js b/code/th_14_panels.js index 4f3e141..b4ac4ac 100644 --- a/code/th_14_panels.js +++ b/code/th_14_panels.js @@ -4624,8 +4624,111 @@ FloatBallAppWM.prototype.showPopupOverlay = function(opts) { root.setBackgroundColor(self.withAlpha(isDark ? 0xFF000000 : 0xFFFFFFFF, isDark ? 0.58 : 0.42)); root.setClickable(true); try { root.setFocusable(true); root.setFocusableInTouchMode(true); } catch(eRootFocus) {} + try { + root.setOnKeyListener(new android.view.View.OnKeyListener({ + onKey: function(v, keyCode, event) { + try { + if (keyCode === android.view.KeyEvent.KEYCODE_BACK && event && event.getAction && event.getAction() === android.view.KeyEvent.ACTION_UP) { + closePopup(); + return true; + } + } catch(eKey) {} + return false; + } + })); + } catch(eRootKey) {} - var card = new android.widget.LinearLayout(context); + var popupBackDownX = 0; + var popupBackDownY = 0; + var popupBackEdge = -1; + var popupBackEligible = false; + var popupBackActive = false; + var popupBackMoved = false; + var card = new JavaAdapter(android.widget.LinearLayout, { + onInterceptTouchEvent: function(ev) { + try { + if (!ev) return false; + var action = ev.getActionMasked(); + if (action === android.view.MotionEvent.ACTION_DOWN) { + popupBackDownX = ev.getX(); + popupBackDownY = ev.getY(); + popupBackEdge = -1; + popupBackEligible = false; + popupBackActive = false; + popupBackMoved = false; + var edgeW = self.dp(56); + var cw = 0; + try { cw = this.getWidth(); } catch(eW) { cw = 0; } + if (popupBackDownX <= edgeW) { popupBackEdge = 0; popupBackEligible = true; } + else if (cw > 0 && popupBackDownX >= cw - edgeW) { popupBackEdge = 1; popupBackEligible = true; } + return false; + } + if (action === android.view.MotionEvent.ACTION_MOVE) { + if (!popupBackEligible) return false; + var dx = ev.getX() - popupBackDownX; + var dy = ev.getY() - popupBackDownY; + var adx = Math.abs(dx); + var ady = Math.abs(dy); + var validDir = (popupBackEdge === 0 && dx > 0) || (popupBackEdge === 1 && dx < 0); + var slop = Math.max(self.dp(8), self.dp(Number(self.config.CLICK_SLOP_DP || 6))); + if (validDir && adx > slop && adx > ady * 0.9) { + popupBackActive = true; + popupBackMoved = true; + try { this.animate().cancel(); } catch(eCancel) {} + try { this.setTranslationX(dx); } catch(eTx) {} + return true; + } + } + } catch(eIntercept) { try { safeLog(self.L, 'w', 'popup back intercept fail: ' + String(eIntercept)); } catch(eLog) {} } + return false; + }, + onTouchEvent: function(ev) { + try { + if (!ev || !popupBackActive) return false; + var action = ev.getActionMasked(); + if (action === android.view.MotionEvent.ACTION_MOVE) { + var mx = ev.getX() - popupBackDownX; + var my = ev.getY() - popupBackDownY; + var validDir2 = (popupBackEdge === 0 && mx > 0) || (popupBackEdge === 1 && mx < 0); + if (validDir2 && Math.abs(mx) > Math.abs(my) * 0.9) { + popupBackMoved = true; + var maxMove = Math.floor(panelWidth * 0.62); + var tx = mx; + if (tx > maxMove) tx = maxMove; + if (tx < -maxMove) tx = -maxMove; + this.setTranslationX(tx); + } + return true; + } + if (action === android.view.MotionEvent.ACTION_UP || action === android.view.MotionEvent.ACTION_CANCEL) { + var ux = ev.getX() - popupBackDownX; + var uy = ev.getY() - popupBackDownY; + var okDir = (popupBackEdge === 0 && ux > self.dp(72)) || (popupBackEdge === 1 && ux < -self.dp(72)); + var ok = action === android.view.MotionEvent.ACTION_UP && popupBackMoved && okDir && Math.abs(ux) > Math.abs(uy) * 0.9; + var dir = popupBackEdge === 1 ? -1 : 1; + popupBackActive = false; + popupBackEligible = false; + popupBackMoved = false; + popupBackEdge = -1; + if (ok) { + this.animate().translationX(dir * panelWidth).alpha(0.96).setDuration(150).withEndAction(new java.lang.Runnable({ run: function() { closePopup(); } })).start(); + } else { + this.animate().translationX(0).alpha(1).setDuration(160).start(); + } + return true; + } + return true; + } catch(eTouch) { + popupBackActive = false; + popupBackEligible = false; + popupBackMoved = false; + popupBackEdge = -1; + try { this.setTranslationX(0); this.setAlpha(1); } catch(eReset) {} + try { safeLog(self.L, 'w', 'popup back touch fail: ' + String(eTouch)); } catch(eLog2) {} + } + return false; + } + }, context); card.setOrientation(android.widget.LinearLayout.VERTICAL); var cardLp = new android.widget.FrameLayout.LayoutParams(panelWidth, panelHeight); cardLp.gravity = android.view.Gravity.CENTER; diff --git a/manifest.json b/manifest.json index dfb3084..cc72fff 100644 --- a/manifest.json +++ b/manifest.json @@ -62,8 +62,8 @@ "size": 23906 }, "th_14_panels.js": { - "sha256": "fcbab7b835c4f020c258d8ddd81675e486572bc140dc6db4aa3bee3f9c2aa27d", - "size": 268044 + "sha256": "9ecfbb5f367802cb3b9f3cbcfbb473e75656207cd03ad61cd25bb43d080c8c41", + "size": 272423 }, "th_14_schema_editor.js": { "sha256": "5669d0b5a16f770bed24eedee24203df57f7cbc7910c840931e533adac1ef146", @@ -80,5 +80,5 @@ }, "keyId": "toolhub-targets-2026-rsa3072", "schema": 2, - "version": 20260522220033 + "version": 20260522220817 } diff --git a/manifest.sig b/manifest.sig index 889027c..58afad0 100644 --- a/manifest.sig +++ b/manifest.sig @@ -1 +1 @@ -C96vTXwZOxNzf6dPnp6DLtQzgY1xdVSe+JAObGu78cZqXO4BNCooFVfLGN4/WaTICx6e6mJ/dtmRVnPtJVc39+EDSaDWUg1ELtD4pPW4u5a5r8qU0J7mCxpUvLcTowG0txvheU4Cu5FQqPdHuBgNiyS1J5pNu0WAHapVBhyR7PXgOA8gnzzSaYZyawO/tf6uG20nVS3cFnlcw+ImvmY0tdLUTnfoaRJZBZMDAy5P36oLZCb3NSoqKPSrNj2cWr6i0x+h5D1jdDxRDjBGpK/fRsJAh4CdZTch8pEQsHVlGakb5hLmGARF0WR3RMHOCVeJNj2LXza1ktx2apjfUPJj84neHBgTCj0BcfwrZ0VY52cwE7n5aJn9xdXMaOiPzlioF7fcN9gmMS6ib0+N9qpW2sqfSSXmiWVEuUvNS0f11w39WfzPI5UNE+rt5bwplIWCuiLPWu65wAewm5Fz+y49ysqYuhPJwUEfJ8HLn+wRJnFcaOdWGod2U3DSVLliwi5Y +YhHLAiZPsJLqf7OEX6ttGyJW25rDDxh+lv066wwRbJMIVsvbpX5m0NKmXTwTJhHYrwc2G3Fsile9hvTe6UXXEQU8FurBxA55g3U9WQadSsXVBi2I3E41IiES5IiFxpp1BHDXr4X3mOv1tvNmAfiPdVZ9NU/YD8+gGHdcGUK/OT5DWpfFduTOAdkC9garVWdfHPCxHlxwCS7TYoeKxkGdi8gQdR/pWHfRp6F9pZ103HyuRyTWCZVeU+1Nh/VGOb5a+HGPGQmHOcEb/Gqh4+w9AuGH++VhpH50fMJJdh5CZVObuTlfsEnili+F0QmHhMeKhzpnPnP2gj15ahAm0ThK6rOgDxdyeJ1DzptbkhjYAckoTMLcDEKulJ24fiugkPIvL1vx/OR6mqM8/JJKIA/4aFe+Km1SRLNj7c9m6VOYGQypA6PD2qwDdreMm2AZzyhcIEQdUIbH0k8lFUPFrVVRBAYgJf7R/SkTeLvHgeczPGsjX1nadPavl+4RsrLpLeVi