fix(game): own export chooser modal; PNG option outside in-app webviews only
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 59s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m26s

Telegram's native showPopup delivers its callback with no user
activation, so navigator.share (TG iOS) and clipboard writes (TG
Android GCG copy) silently fail from it — the chooser is now always the
app's own modal, keeping the button click's gesture alive for the
delivery APIs.

The data:URL preview modal is dropped: the Android TG/VK long-press
menu mangles data: URLs (dead download, black-screen open, base64
clipboard garbage), so a binary PNG has no working client-side route in
those webviews at all. The image option is withheld there until the
server-rendered signed-URL delivery (Telegram downloadFile /
VKWebAppDownloadFile) lands; the plain web and mobile browsers keep it.

On-device findings by the owner on the test contour (TG iOS, TG
Android, VK Android).
This commit is contained in:
Ilia Denisov
2026-07-02 17:16:05 +02:00
parent a0eacf3011
commit 946420db93
9 changed files with 95 additions and 202 deletions
+9 -7
View File
@@ -322,8 +322,9 @@ Finished games are archived in a dictionary-independent form and exportable in
**two formats behind one 📤 button** — the GCG file and a rendered **PNG image** of
the final position; the export is offered **only once a game is finished**, and
never for an honest-AI practice game (a live game's export would leak the move
journal; an AI game is throwaway). The format chooser is native where the platform
has one (Telegram's popup), the app's own modal elsewhere.
journal; an AI game is throwaway). The format chooser is always the app's **own
modal** — deliberately not Telegram's native popup, whose callback runs without
user activation and silently breaks the share/clipboard delivery it leads to.
The **image** is rendered on the client (Canvas 2D, always the light theme): the
final board with classic coordinate axes A..O / 1..15 on the left — premium squares
@@ -342,11 +343,12 @@ dead space.
Delivery per format: the **GCG** file is Web-Shared where the platform supports it;
on an Android in-app client (Telegram / VK), which has neither Web Share nor a
working file download, it copies the GCG text to the clipboard (with a confirming
toast); otherwise it downloads the file. The **PNG** shares or downloads the same
way where possible, but a binary image has no clipboard-text fallback — those
in-app webviews (and the desktop VK iframe) get a **preview modal** instead: the
image with a long-press / right-click save hint and a copy-image button where the
clipboard-image API exists. Statistics (durable accounts only):
toast); otherwise it downloads the file. The **PNG** is Web-Shared or downloaded the
same way, but a binary image has no clipboard-text fallback at all — so the image
option is currently **withheld inside the in-app webviews** (Telegram / VK) and
offered on the plain web and mobile browsers only; it returns there with the
server-rendered signed-URL delivery (Telegram `downloadFile` /
`VKWebAppDownloadFile`). Statistics (durable accounts only):
wins, losses, draws, max points in a game, and max points for a single move (the
best play, which already includes every word it formed plus the all-tiles bonus). It
also shows the player's **move count** (their plays — passes and exchanges do not