diff --git a/src/components/Settings/TTSSettings.tsx b/src/components/Settings/TTSSettings.tsx index e26788b9..1dc5c7bc 100644 --- a/src/components/Settings/TTSSettings.tsx +++ b/src/components/Settings/TTSSettings.tsx @@ -1,7 +1,9 @@ -import React from 'react' +import React, { useState } from 'react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faGauge } from '@fortawesome/free-solid-svg-icons' +import { faGauge, faPlay, faPause } from '@fortawesome/free-solid-svg-icons' import { UserSettings } from '../../services/settingsService' +import { useTextToSpeech } from '../../hooks/useTextToSpeech' +import { detect } from 'tinyld' interface TTSSettingsProps { settings: UserSettings @@ -9,9 +11,15 @@ interface TTSSettingsProps { } const SPEED_OPTIONS = [0.8, 1, 1.2, 1.4, 1.6, 1.8, 2, 2.1, 2.4, 2.8, 3] +const EXAMPLE_TEXT = "Welcome to Boris. Text-to-speech brings your highlights and articles to life. Adjust the playback speed and language settings to your preference." const TTSSettings: React.FC = ({ settings, onUpdate }) => { const currentSpeed = settings.ttsDefaultSpeed || 2.1 + const [isTestSpeaking, setIsTestSpeaking] = useState(false) + + const { supported, speaking, paused, speak, pause, resume, stop } = useTextToSpeech({ + defaultRate: currentSpeed + }) const handleCycleSpeed = () => { const currentIndex = SPEED_OPTIONS.indexOf(currentSpeed) @@ -19,6 +27,46 @@ const TTSSettings: React.FC = ({ settings, onUpdate }) => { onUpdate({ ttsDefaultSpeed: SPEED_OPTIONS[nextIndex] }) } + const handleTestPlayPause = () => { + if (!isTestSpeaking && !speaking) { + let langOverride: string | undefined + + // Determine language based on settings + const mode = settings?.ttsLanguageMode + if (mode === 'system' || settings?.ttsUseSystemLanguage) { + langOverride = navigator?.language?.split('-')[0] + } else { + try { + const detected = detect(EXAMPLE_TEXT) + if (typeof detected === 'string' && detected.length >= 2) { + langOverride = detected.slice(0, 2) + } + } catch (err) { + console.debug('[tts][detect] failed', err) + } + } + + setIsTestSpeaking(true) + speak(EXAMPLE_TEXT, langOverride) + } else if (paused) { + resume() + } else { + pause() + } + } + + const handleStopTest = () => { + stop() + setIsTestSpeaking(false) + } + + // Stop test speaking when settings change + React.useEffect(() => { + if (isTestSpeaking && !speaking) { + setIsTestSpeaking(false) + } + }, [speaking, isTestSpeaking]) + return (

Text-to-Speech

@@ -51,6 +99,37 @@ const TTSSettings: React.FC = ({ settings, onUpdate }) => {
+ + {supported && ( +
+ +
+ {EXAMPLE_TEXT} +
+
+ + {isTestSpeaking && ( + + )} +
+
+ )} ) }