feat: jingle when enter app
This commit is contained in:
Binary file not shown.
@@ -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
|
||||||
@@ -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
|
||||||
@@ -3,6 +3,7 @@ import { useNavigation } from '@react-navigation/native'
|
|||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { Image, Platform, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
|
import { Image, Platform, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
|
||||||
import { background, icons } from '../assets'
|
import { background, icons } from '../assets'
|
||||||
|
import EntryJingle from '../components/EntryJingle'
|
||||||
import FullscreenIntroVideo from '../components/FullscreenIntroVideo'
|
import FullscreenIntroVideo from '../components/FullscreenIntroVideo'
|
||||||
import GradientButton from '../components/GradientButton'
|
import GradientButton from '../components/GradientButton'
|
||||||
import { videosRef } from '../config/firebase'
|
import { videosRef } from '../config/firebase'
|
||||||
@@ -21,6 +22,7 @@ export default function LandingPage() {
|
|||||||
const { currentUID } = useUser()
|
const { currentUID } = useUser()
|
||||||
const [videoUrl, setVideoUrl] = useState(null)
|
const [videoUrl, setVideoUrl] = useState(null)
|
||||||
const [selectedLanguage, setSelectedLanguage] = useState(null)
|
const [selectedLanguage, setSelectedLanguage] = useState(null)
|
||||||
|
const [hasLoadedPreferredLanguage, setHasLoadedPreferredLanguage] = useState(false)
|
||||||
const [showFreeCreditsPopup, setShowFreeCreditsPopup] = useState(false)
|
const [showFreeCreditsPopup, setShowFreeCreditsPopup] = useState(false)
|
||||||
const isAuthenticated = !!currentUID
|
const isAuthenticated = !!currentUID
|
||||||
|
|
||||||
@@ -62,6 +64,11 @@ export default function LandingPage() {
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.warn('LandingPage: failed to load language', error)
|
console.warn('LandingPage: failed to load language', error)
|
||||||
})
|
})
|
||||||
|
.finally(() => {
|
||||||
|
if (isMounted) {
|
||||||
|
setHasLoadedPreferredLanguage(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
isMounted = false
|
isMounted = false
|
||||||
@@ -80,6 +87,7 @@ export default function LandingPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<EntryJingle active={hasLoadedPreferredLanguage && !selectedLanguage} />
|
||||||
<Page
|
<Page
|
||||||
shareBtn
|
shareBtn
|
||||||
// connect
|
// connect
|
||||||
|
|||||||
Reference in New Issue
Block a user