(({
exampleTranslation,
showResult
}) => {
- const [isPlayingAnswer, setIsPlayingAnswer] = useState(false)
- const [isPlayingExample, setIsPlayingExample] = useState(false)
-
- // TTS 播放邏輯
- const handleToggleTTS = useCallback((text: string, type: 'answer' | 'example', lang?: string) => {
- const isCurrentlyPlaying = type === 'answer' ? isPlayingAnswer : isPlayingExample
- const setPlaying = type === 'answer' ? setIsPlayingAnswer : setIsPlayingExample
- const stopOther = type === 'answer' ? setIsPlayingExample : setIsPlayingAnswer
-
- if (isCurrentlyPlaying) {
- speechSynthesis.cancel()
- setPlaying(false)
- return
- }
-
- // 停止另一個播放
- stopOther(false)
- speechSynthesis.cancel()
-
- const utterance = new SpeechSynthesisUtterance(text)
- utterance.lang = lang || 'en-US'
- utterance.rate = 0.8
-
- utterance.onstart = () => setPlaying(true)
- utterance.onend = () => setPlaying(false)
- utterance.onerror = () => setPlaying(false)
-
- speechSynthesis.speak(utterance)
- }, [isPlayingAnswer, isPlayingExample])
if (!showResult) return null
return (
@@ -80,8 +51,6 @@ export const TestResultDisplay = memo(({
{pronunciation && {pronunciation}}
handleToggleTTS(text, 'answer', lang)}
size="sm"
title="播放答案"
/>
@@ -93,8 +62,6 @@ export const TestResultDisplay = memo(({
{example}
handleToggleTTS(text, 'example', lang)}
size="sm"
title="播放例句"
/>
diff --git a/frontend/hooks/shared/useTTSPlayer.ts b/frontend/hooks/shared/useTTSPlayer.ts
deleted file mode 100644
index 96bd650..0000000
--- a/frontend/hooks/shared/useTTSPlayer.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-import { useState } from 'react'
-import { useToast } from '@/components/shared/Toast'
-
-interface UseTTSPlayerReturn {
- isPlayingWord: boolean
- isPlayingExample: boolean
- toggleWordTTS: (text: string, lang?: string) => void
- toggleExampleTTS: (text: string, lang?: string) => void
- stopAllTTS: () => void
-}
-
-export const useTTSPlayer = (): UseTTSPlayerReturn => {
- const toast = useToast()
- const [isPlayingWord, setIsPlayingWord] = useState(false)
- const [isPlayingExample, setIsPlayingExample] = useState(false)
-
- // 檢查瀏覽器支援
- const checkTTSSupport = (): boolean => {
- if (!('speechSynthesis' in window)) {
- toast.error('您的瀏覽器不支援語音播放')
- return false
- }
- return true
- }
-
- // 停止所有語音播放
- const stopAllTTS = () => {
- speechSynthesis.cancel()
- setIsPlayingWord(false)
- setIsPlayingExample(false)
- }
-
- // 創建語音播放實例
- const createUtterance = (text: string, lang: string = 'en-US', rate: number = 0.8) => {
- const utterance = new SpeechSynthesisUtterance(text)
- utterance.lang = lang
- utterance.rate = rate
- utterance.pitch = 1.0
- utterance.volume = 1.0
- return utterance
- }
-
- // 詞彙發音播放
- const toggleWordTTS = (text: string, lang: string = 'en-US') => {
- if (!checkTTSSupport()) return
-
- // 如果正在播放詞彙,則停止
- if (isPlayingWord) {
- stopAllTTS()
- return
- }
-
- // 停止所有播放並開始新播放
- stopAllTTS()
- setIsPlayingWord(true)
-
- const utterance = createUtterance(text, lang, 0.8) // 詞彙播放稍慢
-
- utterance.onend = () => setIsPlayingWord(false)
- utterance.onerror = () => {
- setIsPlayingWord(false)
- toast.error('語音播放失敗')
- }
-
- speechSynthesis.speak(utterance)
- }
-
- // 例句發音播放
- const toggleExampleTTS = (text: string, lang: string = 'en-US') => {
- if (!checkTTSSupport()) return
-
- // 如果正在播放例句,則停止
- if (isPlayingExample) {
- stopAllTTS()
- return
- }
-
- // 停止所有播放並開始新播放
- stopAllTTS()
- setIsPlayingExample(true)
-
- const utterance = createUtterance(text, lang, 0.9) // 例句播放正常語速
-
- utterance.onend = () => setIsPlayingExample(false)
- utterance.onerror = () => {
- setIsPlayingExample(false)
- toast.error('語音播放失敗')
- }
-
- speechSynthesis.speak(utterance)
- }
-
- return {
- isPlayingWord,
- isPlayingExample,
- toggleWordTTS,
- toggleExampleTTS,
- stopAllTTS
- }
-}
\ No newline at end of file