feat: jingle when enter app

This commit is contained in:
2026-08-11 14:27:40 +02:00
parent 0165e8b44d
commit afc48375ae
4 changed files with 105 additions and 0 deletions
Binary file not shown.
+37
View File
@@ -0,0 +1,37 @@
import { useEffect, useRef } from 'react'
import { useAudioPlayer } from 'expo-audio'
const entryJingle = require('../assets/audio/musicland-entry.wav')
const EntryJingle = ({ active }) => {
const player = useAudioPlayer(entryJingle)
const hasStartedRef = useRef(false)
useEffect(() => {
player.loop = false
player.volume = 0.32
if (!active) {
player.pause()
return undefined
}
if (!hasStartedRef.current) {
hasStartedRef.current = true
player
.seekTo(0)
.then(() => player.play())
.catch((error) => {
console.warn("EntryJingle: impossible de lancer le son d'entrée", error)
})
}
return () => {
player.pause()
}
}, [active, player])
return null
}
export default EntryJingle
+60
View File
@@ -0,0 +1,60 @@
import { Asset } from 'expo-asset'
import { useEffect } from 'react'
const entryJingle = require('../assets/audio/musicland-entry.wav')
const EntryJingle = ({ active }) => {
useEffect(() => {
if (!active) {
return undefined
}
const audio = new Audio(Asset.fromModule(entryJingle).uri)
let isDisposed = false
let isWaitingForInteraction = false
audio.loop = false
audio.preload = 'auto'
audio.volume = 0.32
const removeInteractionListeners = () => {
document.removeEventListener('pointerdown', handleFirstInteraction)
document.removeEventListener('keydown', handleFirstInteraction)
isWaitingForInteraction = false
}
const play = () => {
audio
.play()
.then(removeInteractionListeners)
.catch(() => {
if (isDisposed || isWaitingForInteraction) {
return
}
isWaitingForInteraction = true
document.addEventListener('pointerdown', handleFirstInteraction, { once: true })
document.addEventListener('keydown', handleFirstInteraction, { once: true })
})
}
function handleFirstInteraction() {
if (!isDisposed) {
play()
}
}
play()
return () => {
isDisposed = true
removeInteractionListeners()
audio.pause()
audio.removeAttribute('src')
audio.load()
}
}, [active])
return null
}
export default EntryJingle
+8
View File
@@ -3,6 +3,7 @@ import { useNavigation } from '@react-navigation/native'
import { useCallback, useEffect, useState } from 'react'
import { Image, Platform, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import { background, icons } from '../assets'
import EntryJingle from '../components/EntryJingle'
import FullscreenIntroVideo from '../components/FullscreenIntroVideo'
import GradientButton from '../components/GradientButton'
import { videosRef } from '../config/firebase'
@@ -21,6 +22,7 @@ export default function LandingPage() {
const { currentUID } = useUser()
const [videoUrl, setVideoUrl] = useState(null)
const [selectedLanguage, setSelectedLanguage] = useState(null)
const [hasLoadedPreferredLanguage, setHasLoadedPreferredLanguage] = useState(false)
const [showFreeCreditsPopup, setShowFreeCreditsPopup] = useState(false)
const isAuthenticated = !!currentUID
@@ -62,6 +64,11 @@ export default function LandingPage() {
.catch((error) => {
console.warn('LandingPage: failed to load language', error)
})
.finally(() => {
if (isMounted) {
setHasLoadedPreferredLanguage(true)
}
})
return () => {
isMounted = false
@@ -80,6 +87,7 @@ export default function LandingPage() {
return (
<>
<EntryJingle active={hasLoadedPreferredLanguage && !selectedLanguage} />
<Page
shareBtn
// connect