fix: mobile nostr signer detection, mobile TTS auto-unlock, button loaders
- Nostr signer: poll for window.nostr up to 3s on mobile (Amber injects late). Both login() and handleSignerLogin() now wait before failing. - Mobile TTS: install global one-time click/touch/keydown handler to auto-unlock AudioContext when fight pages mount. Previously only triggered by explicit sound toggle, so mobile TTS silently failed. - Add loading spinners to "I BUILD BOTS" and "I FIGHT MYSELF" buttons. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
4897335686
commit
dd3cbdae7f
@@ -11,7 +11,7 @@ import {
|
||||
fanfareRound,
|
||||
sfxCrowdCheer, sfxApplause, sfxDrumRoll,
|
||||
announceFinishHim, announceFlawlessVictory, announceDeepIntro,
|
||||
setMusicIntensity, stopAllAudio, ensureAudioContext, setMasterMute,
|
||||
setMusicIntensity, stopAllAudio, ensureAudioContext, installAutoUnlock, setMasterMute,
|
||||
} from '../game/audio'
|
||||
|
||||
const route = useRoute()
|
||||
@@ -444,6 +444,9 @@ watch(liveFightData, async (val) => {
|
||||
|
||||
// --- Mount / Unmount ---
|
||||
onMounted(async () => {
|
||||
// Auto-unlock AudioContext on first user interaction (critical for mobile TTS)
|
||||
if (liveSoundOn.value) installAutoUnlock()
|
||||
|
||||
let status = await loadFight()
|
||||
|
||||
// If fetch failed (offline), try IndexedDB cache
|
||||
|
||||
@@ -10,7 +10,7 @@ import WalletConnect from '../components/WalletConnect.vue'
|
||||
import { authFetch } from '../lib/nostr-auth'
|
||||
|
||||
const router = useRouter()
|
||||
const { pubkey, bot, profilePicUrl, isLoggedIn, hasExtension, hasStoredKey, isLoading, login, generateLogin, loginWithNsec, registerBot, registerHuman, getStoredNsec, logout } = useNostr()
|
||||
const { pubkey, bot, profilePicUrl, isLoggedIn, hasExtension, hasStoredKey, isLoading, login, waitForSigner, generateLogin, loginWithNsec, registerBot, registerHuman, getStoredNsec, logout } = useNostr()
|
||||
const showNsecBackup = ref(false)
|
||||
const generatedNsec = ref('')
|
||||
const nsecInput = ref('')
|
||||
@@ -185,10 +185,16 @@ async function handleLogin() {
|
||||
}
|
||||
}
|
||||
|
||||
function handleSignerLogin() {
|
||||
async function handleSignerLogin() {
|
||||
if (!window.nostr) {
|
||||
error.value = 'No Nostr signer detected. Install a NIP-07 extension (Nos2x, Alby) or use Amber on Android.'
|
||||
return
|
||||
// Mobile signers inject late — wait briefly
|
||||
error.value = 'Looking for signer...'
|
||||
const found = await waitForSigner(3000)
|
||||
if (!found) {
|
||||
error.value = 'No Nostr signer detected. Install a NIP-07 extension (Nos2x, Alby) or use Amber on Android.'
|
||||
return
|
||||
}
|
||||
error.value = ''
|
||||
}
|
||||
handleLogin()
|
||||
}
|
||||
@@ -295,14 +301,21 @@ async function confirmName() {
|
||||
step.value = 'bot-setup'
|
||||
}
|
||||
|
||||
function chooseBot() {
|
||||
const isChoosingMode = ref(false)
|
||||
async function chooseBot() {
|
||||
isChoosingMode.value = true
|
||||
isHumanMode.value = false
|
||||
await new Promise(r => setTimeout(r, 0)) // Let spinner render
|
||||
step.value = 'pick-character'
|
||||
isChoosingMode.value = false
|
||||
}
|
||||
|
||||
function chooseHuman() {
|
||||
async function chooseHuman() {
|
||||
isChoosingMode.value = true
|
||||
isHumanMode.value = true
|
||||
await new Promise(r => setTimeout(r, 0))
|
||||
step.value = 'pick-human-avatar'
|
||||
isChoosingMode.value = false
|
||||
}
|
||||
|
||||
const humanAvatarList = [
|
||||
@@ -640,10 +653,13 @@ function handleSignOut() {
|
||||
<div class="space-y-4">
|
||||
<button
|
||||
class="w-full py-5 px-4 bg-neon-cyan/5 border-2 border-neon-cyan/40 text-left
|
||||
hover:bg-neon-cyan/10 hover:border-neon-cyan/70 transition-all group"
|
||||
hover:bg-neon-cyan/10 hover:border-neon-cyan/70 transition-all group
|
||||
disabled:opacity-50 disabled:cursor-wait"
|
||||
:disabled="isChoosingMode"
|
||||
@click="chooseBot"
|
||||
>
|
||||
<span class="font-display font-black text-lg tracking-wider text-neon-cyan block mb-1">
|
||||
<span class="font-display font-black text-lg tracking-wider text-neon-cyan block mb-1 flex items-center gap-2">
|
||||
<span v-if="isChoosingMode && !isHumanMode" class="w-4 h-4 border-2 border-neon-cyan/30 border-t-neon-cyan rounded-full animate-spin" />
|
||||
I BUILD BOTS
|
||||
</span>
|
||||
<span class="font-mono text-[10px] text-text-muted leading-relaxed block">
|
||||
@@ -654,10 +670,13 @@ function handleSignOut() {
|
||||
|
||||
<button
|
||||
class="w-full py-5 px-4 bg-neon-pink/5 border-2 border-neon-pink/40 text-left
|
||||
hover:bg-neon-pink/10 hover:border-neon-pink/70 transition-all group"
|
||||
hover:bg-neon-pink/10 hover:border-neon-pink/70 transition-all group
|
||||
disabled:opacity-50 disabled:cursor-wait"
|
||||
:disabled="isChoosingMode"
|
||||
@click="chooseHuman"
|
||||
>
|
||||
<span class="font-display font-black text-lg tracking-wider text-neon-pink block mb-1">
|
||||
<span class="font-display font-black text-lg tracking-wider text-neon-pink block mb-1 flex items-center gap-2">
|
||||
<span v-if="isChoosingMode && isHumanMode" class="w-4 h-4 border-2 border-neon-pink/30 border-t-neon-pink rounded-full animate-spin" />
|
||||
I FIGHT MYSELF
|
||||
</span>
|
||||
<span class="font-mono text-[10px] text-text-muted leading-relaxed block">
|
||||
|
||||
Reference in New Issue
Block a user