1febc9d6daf1
RecoveryWordDisplay: route save through navigator.share on native (Capacitor WebView ignores <a download>); button label flips to 'share recovery words' on mobile; desktop keeps <a download> fallback
- time
- 2026-05-07 02:27 UTC · 5 months ago
- machine
- koh2
- parent
- 2ce7d020ae13
↓ peach-browser-1febc9d6.tar.gzatlas at this save
files changed1 file
src/popup/views/RecoveryWordDisplay.tsx+22 −3src/popup/views/RecoveryWordDisplay.tsx+22 −3
@@ -2,6 +2,7 @@22 import { sendMessage } from "../App";33 import { PeachWordmark } from "../components/PeachMark";44 import { RecoveryRuneBackground } from "../components/RecoveryRuneBackground";5+import { isNativePlatform } from "../../shared/native";56 67 interface RecoveryWordDisplayViewProps {78 onDone: () => void;@@ -124,9 +125,9 @@124125 <button125126 type="button"126127 class="peach-recovery-download-btn"127- onClick={() => downloadRecoveryWords(words())}128+ onClick={() => void saveRecoveryWords(words())}128129 >129- download as .txt130+ {isNativePlatform() ? "share recovery words" : "download as .txt"}130131 </button>131132 </div>132133 @@ -191,7 +192,7 @@191192 );192193 }193194 194-function downloadRecoveryWords(words: string[]): void {195+async function saveRecoveryWords(words: string[]): Promise<void> {195196 const numbered = words.map((w, i) => `${String(i + 1).padStart(2, " ")}. ${w}`).join("\n");196197 const body =197198 "PEACH RECOVERY WORDS\n" +@@ -199,6 +200,24 @@199200 "Anyone with these 12 words can recover your vault.\n" +200201 "Store this file somewhere only you can access.\n\n" +201202 numbered + "\n";203+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+202221 const blob = new Blob([body], { type: "text/plain" });203222 const url = URL.createObjectURL(blob);204223 const a = document.createElement("a");