fix(export): per-platform polish from the on-device review
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 14s
CI / ui (pull_request) Successful in 1m4s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m41s

- TG iOS: the OS share sheet with the fetched file (WKWebView has
  navigator.share — the долгоживущий debug-overlay Share path proves
  it). The chooser stays the app modal on this one platform: a native
  popup callback cannot supply the user activation the sheet needs.
  TG Android/desktop keep the native popup + downloadFile (verified
  perfect, untouched).
- VK mobile: the PNG now rides VKWebAppDownloadFile like the GCG — the
  owner-verified path that lands in VK's native share flow; the
  ShowImages viewer is dropped (its preview offered save only, no
  share).
- VK desktop iframe: both formats are plain anchor downloads (it is an
  ordinary browser; the viewer/bridge path made no sense there).
This commit is contained in:
Ilia Denisov
2026-07-02 23:05:35 +02:00
parent a9376c20a2
commit 8db18f2a2a
8 changed files with 142 additions and 83 deletions
+15 -12
View File
@@ -323,8 +323,10 @@ Finished games are archived in a dictionary-independent form and exportable in
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 Telegram's **native popup**
inside Telegram (safe there: the whole Telegram chain is bridge calls, which need no
user activation) and the app's own modal elsewhere (VK has no native chooser).
on Telegram Android/desktop (safe there: that chain is all bridge calls, which need
no user activation) and the app's own modal elsewhere — on Telegram iOS the delivery
is the OS share sheet, which a native-popup callback cannot open, and VK has no
native chooser.
The **image** is rendered on the server (the internal render sidecar runs the same
drawing module the web client tests; always the light theme): the final board with
@@ -341,16 +343,17 @@ finish date in the device locale. The scoresheet typography is fixed; a long gam
stretches the board (never below its minimum) so the image carries no dead space.
Delivery is **one signed, short-lived link for both formats on every platform**,
handed to the most native affordance: Telegram's download dialog (both TG
platforms; sharing onwards from Telegram's own file preview); on VK the image opens
in **VK's native photo viewer** (on screen at once — saving/sharing are the
viewer's own controls) and the GCG goes through VK's download; a **mobile browser
gets the OS share sheet** with the file (nothing lands in Downloads first); a
desktop browser downloads the file. The link needs no login to fetch (the
platforms' downloaders carry none) and is valid for minutes. The single exception
is a legacy Telegram client without the download dialog (pre-Bot API 8.0): there
the GCG falls back to the old clipboard copy (with the confirming toast) and the
image option is not offered. Statistics (durable accounts only):
handed to the best affordance each platform has (each branch verified on-device):
Telegram Android/desktop use Telegram's download dialog (whose own preview shares
onwards); **Telegram iOS opens the OS share sheet** with the fetched file; on VK
both formats go through VK's download into its native share/preview flow (the
desktop VK iframe, an ordinary browser, downloads them); a **mobile browser gets
the OS share sheet** (nothing lands in Downloads first); a desktop browser
downloads the file. The link needs no login to fetch (the platforms' downloaders
carry none) and is valid for minutes. The single exception is a legacy Telegram
client without the download dialog (pre-Bot API 8.0): there the GCG falls back to
the old clipboard copy (with the confirming toast) and the image option is not
offered. 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