From 09f2aa4d07fa5255bd542117d159b21c2786523a Mon Sep 17 00:00:00 2001 From: 7015725 Date: Wed, 13 May 2026 07:31:28 +0800 Subject: [PATCH] feat: adapt ToolApp size to screen --- code/th_15_extra.js | 90 ++++++++++++++++++++----- manifest.json | 6 +- manifest.sig | 2 +- scripts/verify_toolapp_adaptive_size.py | 35 ++++++++++ 4 files changed, 113 insertions(+), 20 deletions(-) create mode 100644 scripts/verify_toolapp_adaptive_size.py diff --git a/code/th_15_extra.js b/code/th_15_extra.js index 051e49f..3b6f0a5 100644 --- a/code/th_15_extra.js +++ b/code/th_15_extra.js @@ -418,9 +418,14 @@ FloatBallAppWM.prototype.addPanel = function(panel, x, y, which) { // } } + var panelLp0 = null; + try { panelLp0 = panel.getLayoutParams(); } catch (ePanelLp) { panelLp0 = null; } + var panelW = (panelLp0 && Number(panelLp0.width) > 0) ? Number(panelLp0.width) : android.view.WindowManager.LayoutParams.WRAP_CONTENT; + var panelH = (panelLp0 && Number(panelLp0.height) > 0) ? Number(panelLp0.height) : android.view.WindowManager.LayoutParams.WRAP_CONTENT; + var lp = new android.view.WindowManager.LayoutParams( - android.view.WindowManager.LayoutParams.WRAP_CONTENT, - android.view.WindowManager.LayoutParams.WRAP_CONTENT, + panelW, + panelH, android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, flags, android.graphics.PixelFormat.TRANSLUCENT @@ -607,6 +612,65 @@ FloatBallAppWM.prototype.setToolAppContent = function(contentView) { return false; }; +FloatBallAppWM.prototype.calculateToolAppLayout = function(shell) { + var sw = Math.max(1, Number(this.state.screen && this.state.screen.w || 0)); + var sh = Math.max(1, Number(this.state.screen && this.state.screen.h || 0)); + if (sw <= 1 || sh <= 1) { + try { var ss = this.getScreenSizePx(); sw = ss.w; sh = ss.h; } catch (eScreen) {} + } + var shortSide = Math.min(sw, sh); + var longSide = Math.max(sw, sh); + var isLandscape = sw > sh; + + var marginX = this.dp(12); + var marginTop = this.dp(14); + var marginBottom = this.dp(14); + var targetW; + var targetH; + + if (shortSide < this.dp(420)) { + // 小屏/分屏:接近全屏,避免内容被裁剪。 + marginX = this.dp(8); + marginTop = this.dp(8); + marginBottom = this.dp(8); + targetW = sw - marginX * 2; + targetH = sh - marginTop - marginBottom; + } else if (shortSide >= this.dp(720)) { + // 平板/大屏:不要铺满,保持卡片阅读宽度。 + marginX = this.dp(28); + marginTop = this.dp(28); + marginBottom = this.dp(28); + targetW = Math.min(this.dp(680), Math.floor(sw * (isLandscape ? 0.56 : 0.72))); + targetH = Math.min(this.dp(780), sh - marginTop - marginBottom); + } else if (isLandscape) { + // 手机横屏:高度优先,宽度适当收窄。 + marginX = this.dp(18); + marginTop = this.dp(12); + marginBottom = this.dp(12); + targetW = Math.min(this.dp(620), Math.floor(sw * 0.68)); + targetH = sh - marginTop - marginBottom; + } else { + // 手机竖屏:左右留少量边距,高度随屏幕增长。 + marginX = this.dp(12); + marginTop = this.dp(18); + marginBottom = this.dp(18); + targetW = Math.min(this.dp(560), sw - marginX * 2); + targetH = Math.min(Math.floor(sh * 0.90), sh - marginTop - marginBottom); + } + + targetW = Math.max(this.dp(300), Math.min(targetW, sw - marginX * 2)); + targetH = Math.max(this.dp(360), Math.min(targetH, sh - marginTop - marginBottom)); + + var x = Math.floor((sw - targetW) / 2); + var y = Math.floor((sh - targetH) / 2); + if (x < marginX) x = marginX; + if (y < marginTop) y = marginTop; + if (x + targetW > sw - marginX) x = Math.max(0, sw - marginX - targetW); + if (y + targetH > sh - marginBottom) y = Math.max(0, sh - marginBottom - targetH); + + return { width: targetW, height: targetH, x: x, y: y, marginX: marginX, marginTop: marginTop, marginBottom: marginBottom, isLandscape: isLandscape, shortSide: shortSide, longSide: longSide }; +}; + FloatBallAppWM.prototype.showToolApp = function(route, resetStack) { if (this.state.closing) return; var r = this.isToolAppRoute(route) ? String(route) : "settings"; @@ -635,27 +699,21 @@ FloatBallAppWM.prototype.showToolApp = function(route, resetStack) { this.updateToolAppShellChrome(this.getToolAppTitle(r), this.state.toolAppNavStack.length > 1); this.setToolAppContent(raw); - var maxW = Math.floor(this.state.screen.w * 0.92); - var maxH = Math.floor(this.state.screen.h * 0.82); - shell.measure( - android.view.View.MeasureSpec.makeMeasureSpec(maxW, android.view.View.MeasureSpec.AT_MOST), - android.view.View.MeasureSpec.makeMeasureSpec(maxH, android.view.View.MeasureSpec.AT_MOST) - ); - var pw = Math.max(this.dp(300), Math.min(maxW, shell.getMeasuredWidth())); - var ph = Math.max(this.dp(380), Math.min(maxH, shell.getMeasuredHeight())); + var layout = this.calculateToolAppLayout(shell); var lp0 = shell.getLayoutParams(); - if (!lp0) lp0 = new android.view.ViewGroup.LayoutParams(pw, ph); - lp0.width = pw; lp0.height = ph; + if (!lp0) lp0 = new android.view.ViewGroup.LayoutParams(layout.width, layout.height); + lp0.width = layout.width; lp0.height = layout.height; shell.setLayoutParams(lp0); if (!this.state.addedViewer || this.state.viewerPanel !== shell) { - var pos = this.getBestPanelPosition(pw, ph, this.state.ballLp.x, this.state.ballLp.y, this.getDockInfo().ballSize); - this.addPanel(shell, pos.x, pos.y, "tool_app"); + this.addPanel(shell, layout.x, layout.y, "tool_app"); } else { try { if (this.state.viewerPanelLp) { - this.state.viewerPanelLp.width = pw; - this.state.viewerPanelLp.height = ph; + this.state.viewerPanelLp.width = layout.width; + this.state.viewerPanelLp.height = layout.height; + this.state.viewerPanelLp.x = layout.x; + this.state.viewerPanelLp.y = layout.y; this.state.wm.updateViewLayout(shell, this.state.viewerPanelLp); } } catch (eUpd) { safeLog(this.L, 'w', "tool_app update layout fail: " + String(eUpd)); } diff --git a/manifest.json b/manifest.json index 47f0c05..04f7b54 100644 --- a/manifest.json +++ b/manifest.json @@ -58,8 +58,8 @@ "size": 237123 }, "th_15_extra.js": { - "sha256": "554092fb880e1f645e8665feac752b7412c3a9b604f960ad73f7fa889c8e39a8", - "size": 73786 + "sha256": "44d19f0012f4182b9f9831d4f5a747b43d3b726f98e0480e6c79f54eeff70a5e", + "size": 76125 }, "th_16_entry.js": { "sha256": "e7c99c3dfbd6aedab05551426955081ae6cae034754f2f557cefa01dc75dc001", @@ -68,5 +68,5 @@ }, "keyId": "toolhub-targets-2026-rsa3072", "schema": 2, - "version": 20260512232713 + "version": 20260512233123 } diff --git a/manifest.sig b/manifest.sig index 4e91f32..c38d9f5 100644 --- a/manifest.sig +++ b/manifest.sig @@ -1 +1 @@ -Y5kHcy+jDtyrB0AAvEgLdWkQr85CJ7UAvOtzDrp93yI2c+PAItrzWjh+inSskBv7UBa7bHIDXGHVPBN9O5qIPn2Zgb01baozxz+KqO4WomLdEKWTOrRhrla2rJAKf7hcrTLnI2WjHWgg2kMikypvm1S45vcwu1u4uVBEFwE9EExrvjmQiHShqWTJ8ejiMbV3AqQFKCA0QpLujPscedW8YFJOpTJarwKIwSTuAGJdLtKh7ixgzB46kcqkxb+bVdi0+kEblY+heYlTxP5p7F75n0X1aIOuRXYnuGf3ODQi+rioTHYRTQGoJ36SNzxgIHS0JyEDgeduJEhaYaYXLz7BaKFFsJ+2SWPyKS0rx+XW+j91Am9C+wCXKNcPa5/r1y1D/hxtEHSK/YEYVX7IYrCNx3xMJVfILzpCB9lFpEiHNjw0qZU/hjXnRzJhstkK7wrMt6kfvmX7feG34a3t8jlDa0H7Kc3BfkO1wn+wT/P/VurdiaEa5xPU6OPUnyb4fdHY +eHDpnB+6LIjkd8UjiiNeI6CUb0vK01Dc+HGNJRLJBbjiRCLMTHYiDulV9qDmMDrNPJy4fKr8Wmdz6Lz0AMkv9cbWEut+Fb7jZJXzwIt967XJsKwyQMdPb/N7wZ5oLvdrDxJXbp833FKlnsNahhcrg92Jw3z5qRgBYJQ5JV4CKPkMAXG6w80Y1d7LUhbJsBUtZwGOA2qMykefFVl1qEO67Ljm0pyeqaFqTKcTmmIn955Ni4f8q/gaaR+mz66WhKy/YUhXIYwXSIsW4eF9kkDe3N2NW77goDNKAn4E1Hg9qsObiWxb452zVwhdR/S8J3nk7vLO6N/FVf0+PxT24W5G+S/BDChTz3fwOsS2DUI2ZkygFn9leF/z8Nmivf2utwkgrZbJ/xkSirvYxZ2KzwRY7VSLM7ESPBBpx52EVK6HlVuZL7v+rlr/Yb+lzXvhgtg9s4btLJH9GGtdJVPGItLEBPYd9fi8J+Xupd6nGDHFVMZqULXoK+3a96FqsQr2pqKB diff --git a/scripts/verify_toolapp_adaptive_size.py b/scripts/verify_toolapp_adaptive_size.py new file mode 100644 index 0000000..aa897d4 --- /dev/null +++ b/scripts/verify_toolapp_adaptive_size.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +import pathlib +import re +import sys + +root = pathlib.Path(__file__).resolve().parents[1] +extra = (root / "code" / "th_15_extra.js").read_text(encoding="utf-8") + +checks = [] + +def check(name, ok): + checks.append((name, bool(ok))) + +check("has calculateToolAppLayout", "FloatBallAppWM.prototype.calculateToolAppLayout" in extra) +check("layout uses screen orientation", "isLandscape" in extra and "shortSide" in extra and "longSide" in extra) +check("layout has tiny screen branch", "shortSide < this.dp(420)" in extra) +check("layout has tablet/large screen branch", "shortSide >= this.dp(720)" in extra) +check("layout applies margins", "marginX" in extra and "marginTop" in extra and "marginBottom" in extra) + +show_match = re.search(r"FloatBallAppWM\.prototype\.showToolApp\s*=\s*function\([^)]*\)\s*\{(?P.*?)\n\};", extra, re.S) +show_body = show_match.group("body") if show_match else "" +check("showToolApp exists", bool(show_match)) +check("showToolApp uses calculateToolAppLayout", "this.calculateToolAppLayout" in show_body) +check("showToolApp applies adaptive width", "layout.width" in show_body and "layout.height" in show_body) +check("showToolApp updates x/y when reusing root", "viewerPanelLp.x = layout.x" in show_body and "viewerPanelLp.y = layout.y" in show_body) +check("showToolApp addPanel uses adaptive x/y", "this.addPanel(shell, layout.x, layout.y" in show_body) +check("showToolApp no fixed 0.92/0.82 sizing", "0.92" not in show_body and "0.82" not in show_body) + +failed = [name for name, ok in checks if not ok] +if failed: + print("ToolApp adaptive-size verification FAILED:") + for name in failed: + print(" - " + name) + sys.exit(1) +print("ToolApp adaptive-size verification OK")