b39a7b800795
RecoveryWordDisplay: replace navigator.share (no-op without @capacitor/share) with a true file download via base64 data URL on native (caught by MainActivity.setDownloadListener and written to public Downloads via MediaStore); button label always reads 'download as .txt'
- time
- 2026-05-07 02:53 UTC · 5 months ago
- machine
- koh2
- parent
- 4bb8cb4b18bc
↓ peach-browser-b39a7b80.tar.gzatlas at this save
files changed1 file
src/popup/views/RecoveryWordDisplay.tsx+14 −23src/popup/views/RecoveryWordDisplay.tsx+14 −23
@@ -127,7 +127,7 @@127127 class="peach-recovery-download-btn"128128 onClick={() => void saveRecoveryWords(words())}129129 >130- {isNativePlatform() ? "share recovery words" : "download as .txt"}130+ download as .txt131131 </button>132132 </div>133133 @@ -192,7 +192,7 @@192192 );193193 }194194 195-async function saveRecoveryWords(words: string[]): Promise<void> {195+function saveRecoveryWords(words: string[]): void {196196 const numbered = words.map((w, i) => `${String(i + 1).padStart(2, " ")}. ${w}`).join("\n");197197 const body =198198 "PEACH RECOVERY WORDS\n" +@@ -201,30 +201,21 @@201201 "Store this file somewhere only you can access.\n\n" +202202 numbered + "\n";203203 204- // Capacitor WebView doesn't fire <a download> — without a DownloadListener205- // the click is a no-op. Use Web Share when available (covers Android +206- // iOS Capacitor and modern desktop Safari), and fall back to <a download>207- // for Chromium/Firefox on desktop where Share is unavailable or noisy.208- if (isNativePlatform() && typeof navigator !== "undefined" && typeof navigator.share === "function") {209- try {210- await navigator.share({211- title: "Peach recovery words",212- text: body,213- });214- return;215- } catch (e) {216- // User cancelled or share failed — silently fall through to download.217- if (e instanceof Error && /abort/i.test(e.message)) return;218- }219- }220-221- const blob = new Blob([body], { type: "text/plain" });222- const url = URL.createObjectURL(blob);223204 const a = document.createElement("a");224- a.href = url;225205 a.download = "peach-recovery-words.txt";206+ if (isNativePlatform()) {207+ // Capacitor WebView: blob: URLs are opaque to native, but data: URLs go208+ // through MainActivity.setDownloadListener which writes them to public209+ // Downloads via MediaStore. Encode as base64 to keep the data URL210+ // intact through the WebView's URL plumbing.211+ const b64 = btoa(unescape(encodeURIComponent(body)));212+ a.href = `data:text/plain;base64,${b64}`;213+ } else {214+ const blob = new Blob([body], { type: "text/plain" });215+ a.href = URL.createObjectURL(blob);216+ setTimeout(() => URL.revokeObjectURL(a.href), 1000);217+ }226218 document.body.appendChild(a);227219 a.click();228220 a.remove();229- URL.revokeObjectURL(url);230221 }\ No newline at end of file