diff --git a/.gitignore b/.gitignore index e43b0f9..20f6c86 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +.python_modules/ diff --git a/nepalingo-web/src/components/Card.tsx b/nepalingo-web/src/components/Card.tsx index 29b01bf..de32c68 100644 --- a/nepalingo-web/src/components/Card.tsx +++ b/nepalingo-web/src/components/Card.tsx @@ -1,7 +1,8 @@ -import React, { useState } from "react"; +import React from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faVolumeHigh } from "@fortawesome/free-solid-svg-icons"; import { useLanguage } from "@/hooks/Langauge"; +import useAudioPlayer from "@/hooks/useAudioPlayer"; interface CardProps { Word: string; @@ -22,25 +23,28 @@ const Card: React.FC = ({ PronounciationUrl, viewType, }) => { - const [audio, setAudio] = useState(null); const { selectedLanguage } = useLanguage(); + const { togglePlayback } = useAudioPlayer(PronounciationUrl); - const handlePronunciation = (event: React.MouseEvent) => { + const handlePronunciation = (event: React.MouseEvent) => { event.stopPropagation(); - if (PronounciationUrl) { - if (audio) { - if (!audio.paused) { - audio.pause(); - audio.currentTime = 0; - } else { - audio.play(); - } - } else { - const newAudio = new Audio(PronounciationUrl); - setAudio(newAudio); - newAudio.play(); - } + togglePlayback(); + }; + + const PronunciationButton = () => { + if (!PronounciationUrl) { + return null; } + + return ( + + ); }; return ( @@ -72,14 +76,7 @@ const Card: React.FC = ({

{Pronunciation}

- {PronounciationUrl && ( - - )} +
{ImageUrl && ( @@ -125,14 +122,7 @@ const Card: React.FC = ({

{Pronunciation}

- {PronounciationUrl && ( - - )} +
{ImageUrl && ( diff --git a/nepalingo-web/src/components/SearchResponseCard.tsx b/nepalingo-web/src/components/SearchResponseCard.tsx index 1277525..357697f 100644 --- a/nepalingo-web/src/components/SearchResponseCard.tsx +++ b/nepalingo-web/src/components/SearchResponseCard.tsx @@ -1,7 +1,18 @@ import { Meaning } from "@/hooks/useDictionary"; import React from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faVolumeHigh } from "@fortawesome/free-solid-svg-icons"; +import useAudioPlayer from "@/hooks/useAudioPlayer"; const SearchResponseCard = ({ meaning }: { meaning: Meaning }) => { + const { togglePlayback } = useAudioPlayer(meaning.audio?.uri); + + const handlePronunciation = (event: React.MouseEvent) => { + event.stopPropagation(); + + togglePlayback(); + }; + return (
{

)}
- {meaning.audio && ( - + {meaning.audio?.uri && ( + )}
diff --git a/nepalingo-web/src/hooks/useAudioPlayer.ts b/nepalingo-web/src/hooks/useAudioPlayer.ts new file mode 100644 index 0000000..66ee7e2 --- /dev/null +++ b/nepalingo-web/src/hooks/useAudioPlayer.ts @@ -0,0 +1,69 @@ +import { useCallback, useEffect, useState } from "react"; + +const resetAudio = (audio: HTMLAudioElement | null) => { + if (!audio) { + return; + } + + audio.pause(); + audio.currentTime = 0; +}; + +const useAudioPlayer = (audioUrl?: string) => { + const [audio, setAudio] = useState(null); + + const clearAudio = useCallback(() => { + setAudio((currentAudio) => { + if (currentAudio) { + resetAudio(currentAudio); + } + + return null; + }); + }, []); + + useEffect(() => { + return () => { + resetAudio(audio); + }; + }, [audio]); + + useEffect(() => { + clearAudio(); + }, [audioUrl, clearAudio]); + + const togglePlayback = useCallback(() => { + if (!audioUrl) { + return; + } + + setAudio((currentAudio) => { + if (currentAudio) { + if (!currentAudio.paused) { + resetAudio(currentAudio); + return null; + } + + currentAudio.currentTime = 0; + const playPromise = currentAudio.play(); + if (playPromise) { + void playPromise.catch(() => undefined); + } + + return currentAudio; + } + + const newAudio = new Audio(audioUrl); + const playPromise = newAudio.play(); + if (playPromise) { + void playPromise.catch(() => undefined); + } + + return newAudio; + }); + }, [audioUrl]); + + return { togglePlayback }; +}; + +export default useAudioPlayer;