Adding guesses stats in KanjiList using AsyncStorage

master
Arthur VALIN 2 years ago
parent 16ca071780
commit 3464d7daf6

Binary file not shown.

@ -11,6 +11,6 @@
"\\redux\\reducers",
"\\redux\\thunks"
],
"SelectedNode": "\\assets",
"SelectedNode": "\\components\\KanjiPlaygroundList.tsx",
"PreviewInSolutionExplorer": false
}

Binary file not shown.

@ -7,5 +7,6 @@ export const learnihonColors = {
"dark_2": "#1C1C1C",
"dark_3": "#0D0D0D",
"wrong": "#AA3D3D",
"correct": "#3DAA3D"
"correct": "#3DAA3D",
"warning": "#FAD63C"
}

@ -5,6 +5,7 @@ import { useSelector } from 'react-redux';
import { learnihonColors } from '../assets/colors';
import { Kanji } from '../model/kanji';
import { KanjiListByGrade } from '../model/kanjiListByGrades';
import { storeGuess } from '../storage/storage';
import GradeChipList from './GradeChipList';
import KanjiAnswerField from './KanjiAnswerField';
@ -68,7 +69,9 @@ const KanjiCard = () => {
}, [kanji]);
const computeAnswer = () => {
setAnswerTextColor(isAnswerRight() ? learnihonColors.correct : learnihonColors.wrong);
var isCorrect = isAnswerRight();
setAnswerTextColor(isCorrect ? learnihonColors.correct : learnihonColors.wrong);
storeGuess(kanji?.character!, isCorrect);
setHasAnswered(true);
}
const computeNext = () => {

@ -1,8 +1,10 @@
import { useNavigation } from '@react-navigation/native';
import React from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { StyleSheet, Text, TouchableOpacity, useColorScheme } from 'react-native';
import { learnihonColors } from '../assets/colors';
import { Kanji } from '../model/kanji';
import { calcCorrectGuessesRatio, getColorByRatio, KanjiGuess } from '../model/kanjiGuess';
import { retrieveGuess } from '../storage/storage';
interface kanjiListCellProps {
kanji: Kanji;
@ -13,11 +15,34 @@ const KanjiListCell = React.memo((props: kanjiListCellProps) => {
const cellStyle = useColorScheme() == 'light' ? cellStyle_light : cellStyle_dark;
const navigator = useNavigation();
const [guessColor, setGuessColor] = useState(cellStyle.text.color);
const [ratio, setRatio] = useState(-1);
var ratioStyle = StyleSheet.create({
text:
{
color: guessColor,
textAlign: "right",
fontWeight: "bold",
position: "absolute",
right: 15
}
});
const memoizedValues = useMemo(async () => {
const guess = await retrieveGuess(props.kanji.character);
const ratio = guess ? await calcCorrectGuessesRatio(guess) : -1;
setRatio(ratio);
}, []);
useEffect(() => {
setGuessColor(getColorByRatio(ratio));
}, [ratio]);
return (
<TouchableOpacity onPress={() => navigator.navigate("Detail", {"kanji": props.kanji})} style={cellStyle.item}>
<Text style={cellStyle.kanji}>{props.kanji.character}</Text>
<Text style={cellStyle.text}>{props.kanji.meaning}</Text>
{ratio!=-1 && (<Text style={ratioStyle.text}>{ratio}%</Text>)}
</TouchableOpacity>
);
});
@ -34,7 +59,6 @@ const cellStyle_light = StyleSheet.create({
},
text: {
color: "black",
width: "90%"
},
kanji: {
fontWeight: "bold",
@ -56,14 +80,13 @@ const cellStyle_dark = StyleSheet.create({
},
text: {
color: "white",
width: "90%"
},
kanji: {
fontWeight: "bold",
color: "white",
fontSize: "20em",
width: "10%"
width: "10%",
},
})
export default KanjiListCell;

@ -0,0 +1,14 @@
import { learnihonColors } from "../assets/colors";
export type KanjiGuess = {
totalGuesses: number,
totalCorrectGuesses: number
}
export const calcCorrectGuessesRatio = (guess: KanjiGuess): number => {
return (guess.totalCorrectGuesses / guess.totalGuesses) * 100;
}
export const getColorByRatio = (ratio: number): string => {
return ratio <= 33 ? learnihonColors.wrong : ratio <= 66 ? learnihonColors.warning : learnihonColors.correct;
}

54
package-lock.json generated

@ -9,6 +9,7 @@
"version": "1.0.0",
"dependencies": {
"@benjeau/react-native-draw": "^0.8.3",
"@react-native-async-storage/async-storage": "~1.17.3",
"@react-native-community/slider": "4.2.4",
"@react-navigation/bottom-tabs": "^6.5.4",
"@react-navigation/native": "^6.1.3",
@ -3778,6 +3779,17 @@
"node": ">=10"
}
},
"node_modules/@react-native-async-storage/async-storage": {
"version": "1.17.11",
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.17.11.tgz",
"integrity": "sha512-bzs45n5HNcDq6mxXnSsOHysZWn1SbbebNxldBXCQs8dSvF8Aor9KCdpm+TpnnGweK3R6diqsT8lFhX77VX0NFw==",
"dependencies": {
"merge-options": "^3.0.4"
},
"peerDependencies": {
"react-native": "^0.0.0-0 || 0.60 - 0.71 || 1000.0.0"
}
},
"node_modules/@react-native-community/cli": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-9.2.1.tgz",
@ -12133,6 +12145,25 @@
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
"license": "MIT"
},
"node_modules/merge-options": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
"dependencies": {
"is-plain-obj": "^2.1.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/merge-options/node_modules/is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
"engines": {
"node": ">=8"
}
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@ -21521,6 +21552,14 @@
}
}
},
"@react-native-async-storage/async-storage": {
"version": "1.17.11",
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.17.11.tgz",
"integrity": "sha512-bzs45n5HNcDq6mxXnSsOHysZWn1SbbebNxldBXCQs8dSvF8Aor9KCdpm+TpnnGweK3R6diqsT8lFhX77VX0NFw==",
"requires": {
"merge-options": "^3.0.4"
}
},
"@react-native-community/cli": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-9.2.1.tgz",
@ -27536,6 +27575,21 @@
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
},
"merge-options": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
"requires": {
"is-plain-obj": "^2.1.0"
},
"dependencies": {
"is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="
}
}
},
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",

@ -32,7 +32,8 @@
"react-native-web": "~0.18.9",
"react-redux": "^8.0.5",
"redux": "^4.2.1",
"rn-perfect-sketch-canvas": "^0.3.0"
"rn-perfect-sketch-canvas": "^0.3.0",
"@react-native-async-storage/async-storage": "~1.17.3"
},
"devDependencies": {
"@babel/core": "^7.12.9",

@ -0,0 +1,43 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { KanjiGuess } from '../model/kanjiGuess'
export const retrieveGuess = async (kanji: string) => {
try {
const value = await AsyncStorage.getItem(kanji);
if (value === null) {
return null;
}
const guess: KanjiGuess = await JSON.parse(value!)
return guess;
} catch (error) {
console.log(error)
return null;
}
};
export const storeGuess = async (kanji: string, wasRight: boolean) => {
const guess = await retrieveGuess(kanji)
if (guess === null) {
try {
await AsyncStorage.setItem(
kanji,
JSON.stringify({ totalGuesses: 1, totalCorrectGuesses: wasRight ? 1 : 0 }),
);
} catch (error) {
console.log(error)
}
} else {
try {
await AsyncStorage.setItem(
kanji,
JSON.stringify({
totalGuesses: guess.totalGuesses + 1,
totalCorrectGuesses: wasRight ? guess.totalCorrectGuesses + 1 : guess.totalCorrectGuesses
}),
);
} catch (error) {
console.log(error)
}
}
};
Loading…
Cancel
Save