Skip to content

Commit

Permalink
Update srs quiz display and fetching algo
Browse files Browse the repository at this point in the history
  • Loading branch information
hockyy committed Jul 4, 2024
1 parent 44edfb5 commit 9210549
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 126 deletions.
49 changes: 24 additions & 25 deletions main/handler/learning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class SRSDatabase {
static db: Level;

static async setup(lang: string) {
if (this.srsData.get(lang)) return;
if (this.srsData.has(lang)) return;
for (const key of Object.keys(SkillConstant)) {
this.learningTrees.set(
getPair(lang, SkillConstant[key]),
Expand All @@ -207,36 +207,26 @@ class SRSDatabase {
}
}

static storeOrUpdate(lang: string, ch: string, srsData: SRSData) {
static storeOrUpdateToDB(lang: string, ch: string, srsData: SRSData) {
this.db.put(`srs/${lang}/${ch}`, srsData.toJSON()).then(r => console.log(r));
}

static insertNew(lang: string, character: string) {
static storeOrUpdate(lang: string, character: string, srsData?: SRSData) {
if (!this.srsData.has(lang)) {
console.warn(`ERROR: srsData ${lang} not initted`)
return;
}

if (this.srsData.get(lang).has(character)) {
if (!srsData && this.srsData.get(lang).has(character)) {
return;
}
const newSrs = new SRSData(character, lang);
this.storeOrUpdate(lang, character, newSrs);
this.srsData.get(lang).set(character, newSrs);
}

static updateLearningTrees(lang: string, character: string, skillName: SkillConstant, newLevel: number) {
const ptrToSRSData = this.srsData.get(lang).get(character);
if (!ptrToSRSData) return;

this.learningTrees.get(getPair(lang, skillName)).erase(ptrToSRSData);

ptrToSRSData.skills.get(skillName).level = newLevel;
ptrToSRSData.skills.get(skillName).lastUpdated = now();
ptrToSRSData.lastUpdated = now();

this.learningTrees.get(getPair(lang, skillName)).insert(ptrToSRSData);
this.storeOrUpdate(lang, character, ptrToSRSData);
if(!srsData) srsData = new SRSData(character, lang);
this.storeOrUpdateToDB(lang, character, srsData);
this.srsData.get(lang).set(character, srsData);
for(const key of Object.keys(SkillConstant)) {
this.learningTrees.get(getPair(lang, SkillConstant[key])).insert(srsData);
}
}

static classicKeyGen(srsData: SRSData, skillType: SkillConstant) {
Expand All @@ -252,19 +242,17 @@ class SRSDatabase {

sm2Algorithm(skill, grade);

this.learningTrees.get(getPair(lang, skillType)).insert(ptrToSRSData);
this.storeOrUpdate(lang, character, ptrToSRSData);
}

static getQuestion(lang: string, skillType: SkillConstant, optionNumber: number = 3) {
const learningTree = this.learningTrees.get(getPair(lang, skillType));
const treeSize = learningTree.container.size();
console.log(treeSize)
if (treeSize < 1) return null; // Not enough characters to generate a question

const nextCharacter = learningTree.findByOrder(0); // Get the closest character to be learned
// Ensure optionNumber does not exceed the available distinct characters
optionNumber = Math.min(optionNumber, treeSize - 1);

let selectedIndices: number[] = []
if (optionNumber > 100) {

Expand Down Expand Up @@ -347,7 +335,7 @@ class Learning {
await this.db.put(key, JSON.stringify(parsedValue));
}
if (parsedValue.level) for (const ch of strippedKey) {
SRSDatabase.insertNew(lang, ch);
SRSDatabase.storeOrUpdate(lang, ch);
}
learningState[strippedKey] = parsedValue;
}
Expand Down Expand Up @@ -415,14 +403,25 @@ class Learning {
}
});

ipcMain.handle('getOneQuestion', async (_event, lang, skillType) => {
ipcMain.handle('learn-getOneQuestion', async (_event, lang, skillType) => {
try {
return SRSDatabase.getQuestion(lang, skillType);
} catch (error) {
console.error('Error getting one question:', error);
return null;
}
});

ipcMain.handle('learn-updateOneCharacter', async (_event, skillType, lang, character, isCorrect) => {
try {
const grade = isCorrect ? 5 : 2; // SM2 grading: 5 for correct, 2 for incorrect
SRSDatabase.updateSkillLevel(lang, character, skillType, grade);
return true;
} catch (error) {
console.error('Error updating one character:', error);
return false;
}
});
}
}

Expand Down
5 changes: 3 additions & 2 deletions renderer/components/Meaning/QuizDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {useEffect, useRef, useState} from "react";
import HanziWriter from "hanzi-writer";

import {AwesomeButton} from "react-awesome-button";
const QuizDisplay = ({character, mode = 'plain'}) => {
const QuizDisplay = ({character, mode = 'plain', onAnswer}) => {
const writingRef = useRef(null);
const [hanziWriter, setHanziWriter] = useState(null);
const [changer, setChanger] = useState(0);
Expand Down Expand Up @@ -31,6 +31,7 @@ const QuizDisplay = ({character, mode = 'plain'}) => {
showHintAfterMisses: mode === 'plain' ? 3 : false,
onComplete: () => {
console.log('Quiz complete')
onAnswer(true);
},
}).then(r => console.log(r)).catch(error => {
console.log(error)
Expand All @@ -44,7 +45,7 @@ const QuizDisplay = ({character, mode = 'plain'}) => {
console.log(e);
}
}
}, [character, mode, hanziWriter, changer]);
}, [character, mode, hanziWriter, changer, onAnswer]);

return (
<div
Expand Down
43 changes: 0 additions & 43 deletions renderer/hooks/useSRS.tsx

This file was deleted.

112 changes: 56 additions & 56 deletions renderer/pages/srs.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import React, {useCallback, useEffect, useState} from "react";
import {ipcRenderer} from 'electron';
import {ipcRenderer} from "electron";
import QuizDisplay from "../components/Meaning/QuizDisplay";
import {videoConstants} from "../utils/constants";
import {AwesomeButton} from "react-awesome-button";
import 'react-awesome-button/dist/styles.css';
import "react-awesome-button/dist/styles.css";
import Head from "next/head";
import useMeaning from "../hooks/useMeaning";
import useLearningKeyBind from "../hooks/useLearningKeyBind";
Expand All @@ -13,8 +11,14 @@ import {LearningSidebar} from "../components/VideoPlayer/LearningSidebar";
import {defaultLearningStyling} from "../utils/CJKStyling";
import {useStoreData} from "../hooks/useStoreData";

const SRS = () => {
// Define the types
enum SkillConstant {
Writing,
Conveyance,
Translation,
}

const SRS = () => {
const {
meaning,
setMeaning,
Expand All @@ -25,37 +29,42 @@ const SRS = () => {
lang
} = useMiteiruTokenizer();
const [showSidebar, setShowSidebar] = useState(0);
useLearningKeyBind(setMeaning, setShowSidebar, undo)
useLearningKeyBind(setMeaning, setShowSidebar, undo);

const [mode, setMode] = useState("help");
const [questionData, setQuestionData] = useState<{
question: string;
options: string[]
} | null>(null);
const [primaryStyling, setPrimaryStyling] = useStoreData(
"user.styling.learning",
defaultLearningStyling
);

const [currentCharacter, setCurrentCharacter] = useState('学');
const [mode, setMode] = useState('help');
const [hanziProgress, setHanziProgress] = useState(null);
const [primaryStyling, setPrimaryStyling] = useStoreData('user.styling.learning', defaultLearningStyling);
const fetchQuestion = useCallback(async () => {
const question = await ipcRenderer.invoke("learn-getOneQuestion", lang, SkillConstant.Writing, 0);
console.log(question)
setQuestionData(question);
}, [lang]);

useEffect(() => {
if (currentCharacter) {
const fetchProgress = async () => {
const progress = {currentCharacter: null};
setHanziProgress(progress[currentCharacter] || {
level: {reading: 0, meaning: 0, writing: 0},
timeCreated: Date.now(),
timeUpdated: {reading: Date.now(), meaning: Date.now(), writing: Date.now()}
});
};
fetchProgress();
}
}, [currentCharacter]);
fetchQuestion().then(r => console.log("OK"));
}, [fetchQuestion]);

const handleStartPractice = useCallback(async (char) => {
setCurrentCharacter(char);
await ipcRenderer.invoke('updateSRSContent', char, 'chinese', {
level: {reading: 0, meaning: 0, writing: 0},
timeCreated: Date.now(),
timeUpdated: {reading: Date.now(), meaning: Date.now(), writing: Date.now()}
});
}, []);
const handleAnswer = async (isCorrect: boolean) => {
if (questionData) {
await ipcRenderer.invoke(
"learn-updateOneCharacter",
SkillConstant.Writing,
lang,
questionData.question,
isCorrect
);
fetchQuestion(); // Fetch the next question
}
};

const handleModeChange = useCallback((newMode) => {
const handleModeChange = useCallback((newMode: string) => {
setMode(newMode);
}, []);

Expand All @@ -66,22 +75,9 @@ const SRS = () => {
</Head>
<div
className="flex flex-col items-center justify-center bg-blue-50 text-black min-h-screen p-6">

<MeaningBox lang={lang} meaning={meaning} setMeaning={setMeaning}
tokenizeMiteiru={tokenizeMiteiru}/>
<h1 className="text-3xl font-bold mb-6">Hanzi/Kanji Practice</h1>
<div className="mb-4">
<input
type="text"
placeholder="Enter character"
className="border p-2 rounded-md"
onChange={(e) => setCurrentCharacter(e.target.value)}
/>
<AwesomeButton type="primary" onPress={() => handleStartPractice(currentCharacter)}
className="ml-4">
Start Practice
</AwesomeButton>
</div>
<div className="mb-4 flex items-center gap-4">
<label className="flex items-center gap-2">
Mode:
Expand All @@ -92,18 +88,22 @@ const SRS = () => {
</select>
</label>
</div>
<div className="w-full flex justify-center">
<QuizDisplay character={currentCharacter} mode={mode}/>
</div>
<div className="mt-6 p-4 border rounded-lg bg-white shadow-md">
<h2 className="text-2xl font-bold mb-4">Progress for {currentCharacter}</h2>
<p>Reading Level: {hanziProgress ? hanziProgress.level.reading : 0}</p>
<p>Meaning Level: {hanziProgress ? hanziProgress.level.meaning : 0}</p>
<p>Writing Level: {hanziProgress ? hanziProgress.level.writing : 0}</p>
</div>
<LearningSidebar showSidebar={showSidebar} setShowSidebar={setShowSidebar}
primaryStyling={primaryStyling}
setPrimaryStyling={setPrimaryStyling} lang={lang}/>
{questionData && (
<div className="w-full flex justify-center">
<QuizDisplay
character={questionData.question}
onAnswer={handleAnswer}
mode={mode}
/>
</div>
)}
<LearningSidebar
showSidebar={showSidebar}
setShowSidebar={setShowSidebar}
primaryStyling={primaryStyling}
setPrimaryStyling={setPrimaryStyling}
lang={lang}
/>
</div>
</React.Fragment>
);
Expand Down

0 comments on commit 9210549

Please sign in to comment.