fix(ui): copy GCG to clipboard on Android in-app WebViews
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 57s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m16s
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 57s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m16s
On-device diagnostics from Android Telegram and VK confirmed both expose no navigator.share AND no navigator.canShare, so the export fell to a Blob <a download> that those WebViews silently ignore — nothing happened. pickGcgDelivery is now a 3-way decision: Web Share where available (iOS), a clipboard copy in an Android in-app WebView (Telegram/VK: no share, dead download), else a desktop Blob download. shareOrDownloadGcg reports the outcome so the game shows a "GCG copied" toast; the copy is VKWebAppCopyText inside VK (which also covers the desktop VK iframe, where navigator.clipboard is blocked) and navigator.clipboard otherwise. Unit tests cover the 3-way choice and the copy/failed outcomes; new i18n key game.gcgCopied (en+ru); docs ARCHITECTURE/FUNCTIONAL(+ru)/UI_DESIGN/TESTING.
This commit is contained in:
+18
-1
@@ -21,6 +21,7 @@
|
||||
import { alphabetLetters, hasAlphabet } from '../lib/alphabet';
|
||||
import { hintsLeft } from '../lib/hints';
|
||||
import { shareOrDownloadGcg } from '../lib/share';
|
||||
import { insideVK, vkCopyText } from '../lib/vk';
|
||||
import { getCachedGame, setCachedGame, setCachedDraft, type CachedGame } from '../lib/gamecache';
|
||||
import { patchLobbyGame } from '../lib/lobbycache';
|
||||
import { applyGameOver, applyMoveDelta, applyOpponentJoined, type DeltaResult } from '../lib/gamedelta';
|
||||
@@ -837,12 +838,28 @@
|
||||
|
||||
async function exportGcg() {
|
||||
try {
|
||||
await shareOrDownloadGcg(await gateway.exportGcg(id));
|
||||
const gcg = await gateway.exportGcg(id);
|
||||
const outcome = await shareOrDownloadGcg(gcg, insideTelegram() || insideVK(), copyGcgText);
|
||||
if (outcome === 'copied') showToast(t('game.gcgCopied'), 'info');
|
||||
else if (outcome === 'failed') showToast(t('error.generic'), 'error');
|
||||
} catch (e) {
|
||||
handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
// The GCG export copies to the clipboard in an Android in-app WebView (no Web Share, a dead
|
||||
// <a download>): VKWebAppCopyText inside VK — which also works in the desktop VK iframe, where
|
||||
// navigator.clipboard is blocked — and navigator.clipboard elsewhere.
|
||||
async function copyGcgText(text: string): Promise<boolean> {
|
||||
if (insideVK()) return vkCopyText(text);
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// --- move history: open by tapping the score bar, close by tapping or swiping up the board ---
|
||||
// The boardwrap surface drives two gestures, selected by `historyOpen`:
|
||||
// - open: the slid board is inert (CSS pointer-events), so the whole board reads as a
|
||||
|
||||
Reference in New Issue
Block a user