"use client"; import { useState } from "react"; import { LinkButton, CircleToggleButton, LightButton } from "@/components/ui/buttons"; import { useAudioPlayer } from "@/hooks/useAudioPlayer"; import { getTTSUrl, TTS_SUPPORTED_LANGUAGES } from "@/lib/bigmodel/tts"; import { useTranslations } from "next-intl"; import localFont from "next/font/local"; import { isNonNegativeInteger, SeededRandom } from "@/utils/random"; import { TSharedPair } from "@/shared/folder-type"; import { PageLayout } from "@/components/ui/PageLayout"; const myFont = localFont({ src: "../../../../public/fonts/NotoNaskhArabic-VariableFont_wght.ttf", }); interface MemorizeProps { textPairs: TSharedPair[]; } const Memorize: React.FC = ({ textPairs }) => { const t = useTranslations("memorize.memorize"); const [reverse, setReverse] = useState(false); const [dictation, setDictation] = useState(false); const [disorder, setDisorder] = useState(false); const [index, setIndex] = useState(0); const [show, setShow] = useState<"question" | "answer">("question"); const { load, play } = useAudioPlayer(); if (textPairs.length === 0) { return (

{t("noTextPairs")}

); } const rng = new SeededRandom(textPairs[0].folderId); const disorderedTextPairs = textPairs.toSorted(() => rng.next() - 0.5); textPairs.sort((a, b) => a.id - b.id); const getTextPairs = () => disorder ? disorderedTextPairs : textPairs; const handleIndexClick = () => { const newIndex = prompt("Input a index number.")?.trim(); if ( newIndex && isNonNegativeInteger(newIndex) && parseInt(newIndex) <= textPairs.length && parseInt(newIndex) > 0 ) { setIndex(parseInt(newIndex) - 1); } }; const handleNext = async () => { if (show === "answer") { const newIndex = (index + 1) % getTextPairs().length; setIndex(newIndex); if (dictation) { const textPair = getTextPairs()[newIndex]; const language = textPair[reverse ? "language2" : "language1"]; const text = textPair[reverse ? "text2" : "text1"]; // 映射语言到 TTS 支持的格式 const languageMap: Record = { "chinese": "Chinese", "english": "English", "japanese": "Japanese", "korean": "Korean", "french": "French", "german": "German", "italian": "Italian", "portuguese": "Portuguese", "spanish": "Spanish", "russian": "Russian", }; const ttsLanguage = languageMap[language?.toLowerCase()] || "Auto"; getTTSUrl(text, ttsLanguage).then((url) => { load(url); play(); }); } } setShow(show === "question" ? "answer" : "question"); }; const handlePrevious = () => { setIndex( (index - 1 + getTextPairs().length) % getTextPairs().length, ); setShow("question"); }; const toggleReverse = () => setReverse(!reverse); const toggleDictation = () => setDictation(!dictation); const toggleDisorder = () => setDisorder(!disorder); const createText = (text: string) => { return (
{text}
); }; const [text1, text2] = reverse ? [getTextPairs()[index].text2, getTextPairs()[index].text1] : [getTextPairs()[index].text1, getTextPairs()[index].text2]; return ( {/* 进度指示器 */}
{index + 1} / {getTextPairs().length}
{/* 文本显示区域 */}
{(() => { if (dictation) { if (show === "question") { return (
?
); } else { return (
{createText(text1)}
{createText(text2)}
); } } else { if (show === "question") { return createText(text1); } else { return (
{createText(text1)}
{createText(text2)}
); } } })()}
{/* 底部按钮 */}
{show === "question" ? t("answer") : t("next")} {t("previous")} {t("reverse")} {t("dictation")} {t("disorder")}
); }; export { Memorize };