From 5b19ba2c2feccfdb6cea19e3756142e152f40f1d Mon Sep 17 00:00:00 2001 From: 3252a8 <3252a8@proton.me> Date: Mon, 1 Jun 2026 20:29:54 +0300 Subject: [PATCH] fix: keep deeplink gateway open during app prompt --- backend/bot/app/web/templates/open_app_gateway.html | 8 ++++++-- frontend/src/webapp/screens/AppLaunchScreen.svelte | 8 ++++---- tests/test_webapp_route_contract.py | 4 ++++ tests/test_webapp_telegram_logout.py | 3 +++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/backend/bot/app/web/templates/open_app_gateway.html b/backend/bot/app/web/templates/open_app_gateway.html index 5bc02c9..287e051 100644 --- a/backend/bot/app/web/templates/open_app_gateway.html +++ b/backend/bot/app/web/templates/open_app_gateway.html @@ -109,6 +109,8 @@ let attempted = false; let pageLeft = false; let state = "opening"; + let closeAttemptTimer = null; + const CLOSE_ATTEMPT_DELAY_MS = 2500; function hasControlChars(value) { return Array.from(String(value || "")).some((char) => { @@ -167,7 +169,10 @@ function markDone() { if (state === "done" || isUnsafe) return; render("done"); - window.setTimeout(tryCloseWindow, 120); + if (closeAttemptTimer) window.clearTimeout(closeAttemptTimer); + closeAttemptTimer = window.setTimeout(() => { + if (pageLeft || document.hidden) tryCloseWindow(); + }, CLOSE_ATTEMPT_DELAY_MS); } function notePageLeft() { @@ -201,7 +206,6 @@ render("done"); }); window.addEventListener("pagehide", notePageLeft); - window.addEventListener("blur", notePageLeft); document.addEventListener("visibilitychange", () => { if (!attempted) return; if (document.hidden) { diff --git a/frontend/src/webapp/screens/AppLaunchScreen.svelte b/frontend/src/webapp/screens/AppLaunchScreen.svelte index d996fb7..ea7c286 100644 --- a/frontend/src/webapp/screens/AppLaunchScreen.svelte +++ b/frontend/src/webapp/screens/AppLaunchScreen.svelte @@ -6,7 +6,7 @@ const AUTO_OPEN_DELAY_MS = 80; const MANUAL_STATE_DELAY_MS = 1600; const DONE_STATE_DELAY_MS = 900; - const CLOSE_ATTEMPT_DELAY_MS = 120; + const CLOSE_ATTEMPT_DELAY_MS = 2500; export let brand = {}; export let appLaunchTarget = ""; @@ -54,7 +54,6 @@ autoOpenTimer = window.setTimeout(openTarget, AUTO_OPEN_DELAY_MS); window.addEventListener("pagehide", notePageLeft); - window.addEventListener("blur", notePageLeft); document.addEventListener("visibilitychange", handleVisibilityChange); return () => { @@ -63,7 +62,6 @@ clearTimer(doneStateTimer); clearTimer(closeAttemptTimer); window.removeEventListener("pagehide", notePageLeft); - window.removeEventListener("blur", notePageLeft); document.removeEventListener("visibilitychange", handleVisibilityChange); }; }); @@ -91,7 +89,9 @@ if (!attempted || state === "done" || !activeTarget) return; state = "done"; clearTimer(closeAttemptTimer); - closeAttemptTimer = window.setTimeout(tryCloseWindow, CLOSE_ATTEMPT_DELAY_MS); + closeAttemptTimer = window.setTimeout(() => { + if (pageLeft || document.hidden) tryCloseWindow(); + }, CLOSE_ATTEMPT_DELAY_MS); } function notePageLeft() { diff --git a/tests/test_webapp_route_contract.py b/tests/test_webapp_route_contract.py index e201b8a..80418fd 100644 --- a/tests/test_webapp_route_contract.py +++ b/tests/test_webapp_route_contract.py @@ -296,6 +296,10 @@ class WebAppRouteContractTests(unittest.TestCase): self.assertIn("URLSearchParams", response.text) self.assertIn("Settings added", response.text) self.assertIn("window.close()", response.text) + self.assertNotIn('window.addEventListener("blur", notePageLeft)', response.text) + self.assertNotIn("window.setTimeout(tryCloseWindow, 120)", response.text) + self.assertIn("const CLOSE_ATTEMPT_DELAY_MS = 2500", response.text) + self.assertIn("if (pageLeft || document.hidden) tryCloseWindow();", response.text) self.assertIn(r"/^(?:javascript|data|vbscript|https?):/i", response.text) def test_app_deeplink_gateway_uses_i18n_template(self): diff --git a/tests/test_webapp_telegram_logout.py b/tests/test_webapp_telegram_logout.py index aa19b63..db70249 100644 --- a/tests/test_webapp_telegram_logout.py +++ b/tests/test_webapp_telegram_logout.py @@ -44,6 +44,9 @@ def test_open_app_route_uses_fallback_screen_without_auth_flow(): assert "AppLaunchScreen" in app_source assert 'mode = isAppLaunchRoute ? "appLaunch"' in app_source assert "window.close()" in screen_source + assert 'window.addEventListener("blur", notePageLeft)' not in screen_source + assert "CLOSE_ATTEMPT_DELAY_MS = 2500" in screen_source + assert "if (pageLeft || document.hidden) tryCloseWindow();" in screen_source launch_guard_pos = app_source.index("if (isAppLaunchRoute) return;") boot_pos = app_source.index("boot();", launch_guard_pos)