Refactor Toast to global component (#122)

* Refactor Toast to global component, use eventDispatcher to dispatch toast events

* Error handling for TTS
This commit is contained in:
Huang Xin
2025-01-08 14:12:38 +01:00
committed by GitHub
parent 15d8d61841
commit 89b2eba2af
8 changed files with 105 additions and 67 deletions
@@ -18,7 +18,6 @@ import {
handleClick,
handleWheel,
} from '../utils/iframeEventHandlers';
import Toast from '@/components/Toast';
const FoliateViewer: React.FC<{
bookKey: string;
@@ -39,7 +38,7 @@ const FoliateViewer: React.FC<{
return () => clearTimeout(timer);
}, [toastMessage]);
useProgressSync(bookKey, setToastMessage);
useProgressSync(bookKey);
const progressRelocateHandler = (event: Event) => {
const detail = (event as CustomEvent).detail;
@@ -164,9 +163,6 @@ const FoliateViewer: React.FC<{
onClick={(event) => handleTurnPage(event)}
ref={containerRef}
/>
{toastMessage && (
<Toast message={toastMessage} toastClass='toast-top toast-end' alertClass='alert-success' />
)}
</>
);
};
@@ -5,10 +5,10 @@ import { useEffect, Suspense, useRef } from 'react';
import { useEnv } from '@/context/EnvContext';
import { useLibraryStore } from '@/store/libraryStore';
import ReaderContent from './ReaderContent';
import { AboutWindow } from '@/components/AboutWindow';
import { useSettingsStore } from '@/store/settingsStore';
import { AboutWindow } from '@/components/AboutWindow';
import { Toast } from '@/components/Toast';
import ReaderContent from './ReaderContent';
const Reader: React.FC<{ ids?: string }> = ({ ids }) => {
const { envConfig } = useEnv();
@@ -37,6 +37,7 @@ const Reader: React.FC<{ ids?: string }> = ({ ids }) => {
<Suspense>
<ReaderContent ids={ids} settings={settings} />
<AboutWindow />
<Toast />
</Suspense>
</div>
)
@@ -23,7 +23,6 @@ import { useFoliateEvents } from '../../hooks/useFoliateEvents';
import { useNotesSync } from '../../hooks/useNotesSync';
import { getPopupPosition, getPosition, Position, TextSelection } from '@/utils/sel';
import { eventDispatcher } from '@/utils/event';
import Toast from '@/components/Toast';
import AnnotationPopup from './AnnotationPopup';
import WiktionaryPopup from './WiktionaryPopup';
import WikipediaPopup from './WikipediaPopup';
@@ -57,7 +56,6 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const [annotPopupPosition, setAnnotPopupPosition] = useState<Position>();
const [dictPopupPosition, setDictPopupPosition] = useState<Position>();
const [translatorPopupPosition, setTranslatorPopupPosition] = useState<Position>();
const [toastMessage, setToastMessage] = useState('');
const [highlightOptionsVisible, setHighlightOptionsVisible] = useState(false);
const [selectedStyle, setSelectedStyle] = useState<HighlightStyle>(
@@ -196,11 +194,6 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selection, bookKey]);
useEffect(() => {
const timer = setTimeout(() => setToastMessage(''), 2000);
return () => clearTimeout(timer);
}, [toastMessage]);
useEffect(() => {
if (!progress) return;
const { location } = progress;
@@ -225,7 +218,12 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const handleCopy = () => {
if (!selection || !selection.text) return;
setToastMessage(_('Copied to notebook'));
eventDispatcher.dispatch('toast', {
type: 'info',
message: _('Copied to notebook'),
className: 'whitespace-nowrap',
timeout: 2000,
});
const { booknotes: annotations = [] } = config;
if (selection) navigator.clipboard.writeText(selection.text);
@@ -414,8 +412,6 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
onHighlight={handleHighlight}
/>
)}
{toastMessage && <Toast message={toastMessage} alertClass='bg-neutual text-content' />}
</div>
);
};
@@ -7,12 +7,14 @@ import { useReaderStore } from '@/store/readerStore';
import Popup from '@/components/Popup';
import TTSPanel from './TTSPanel';
import TTSIcon from './TTSIcon';
import { useTranslation } from '@/hooks/useTranslation';
const POPUP_WIDTH = 260;
const POPUP_HEIGHT = 80;
const POPUP_PADDING = 10;
const TTSControl = () => {
const _ = useTranslation();
const { getView } = useReaderStore();
const [isPlaying, setIsPlaying] = useState(false);
const [showPanel, setShowPanel] = useState(false);
@@ -44,11 +46,19 @@ const TTSControl = () => {
const view = getView(bookKey);
if (!view) return;
const ttsClient = new WebSpeechClient();
const ttsController = new TTSController(ttsClient, view);
ttsControllerRef.current = ttsController;
ttsControllerRef.current.speak(ssml);
setIsPlaying(true);
try {
const ttsClient = new WebSpeechClient();
const ttsController = new TTSController(ttsClient, view);
ttsControllerRef.current = ttsController;
ttsControllerRef.current.speak(ssml);
setIsPlaying(true);
} catch (error) {
eventDispatcher.dispatch('toast', {
message: _('TTS not supported in this device'),
type: 'error',
});
console.error(error);
}
};
const handleTogglePlay = async () => {
@@ -59,7 +69,7 @@ const TTSControl = () => {
ttsController.pause();
setIsPlaying(false);
} else {
await ttsController.start();
ttsController.start();
setIsPlaying(true);
}
};