diff --git a/.vs/LEARNIHON/FileContentIndex/18ab66a5-4a11-4328-bc91-cd3376b0ec91.vsidx b/.vs/LEARNIHON/FileContentIndex/18ab66a5-4a11-4328-bc91-cd3376b0ec91.vsidx
new file mode 100644
index 0000000..049725d
Binary files /dev/null and b/.vs/LEARNIHON/FileContentIndex/18ab66a5-4a11-4328-bc91-cd3376b0ec91.vsidx differ
diff --git a/.vs/LEARNIHON/FileContentIndex/258f16dc-1fae-46bb-a37e-067ba22b8aa6.vsidx b/.vs/LEARNIHON/FileContentIndex/435d2972-bbd4-45e0-8354-cf69c2c152c7.vsidx
similarity index 53%
rename from .vs/LEARNIHON/FileContentIndex/258f16dc-1fae-46bb-a37e-067ba22b8aa6.vsidx
rename to .vs/LEARNIHON/FileContentIndex/435d2972-bbd4-45e0-8354-cf69c2c152c7.vsidx
index 44a42bc..5150a6d 100644
Binary files a/.vs/LEARNIHON/FileContentIndex/258f16dc-1fae-46bb-a37e-067ba22b8aa6.vsidx and b/.vs/LEARNIHON/FileContentIndex/435d2972-bbd4-45e0-8354-cf69c2c152c7.vsidx differ
diff --git a/.vs/LEARNIHON/FileContentIndex/a731465e-eb3c-499c-8b0d-31f641e360d5.vsidx b/.vs/LEARNIHON/FileContentIndex/a731465e-eb3c-499c-8b0d-31f641e360d5.vsidx
new file mode 100644
index 0000000..4954627
Binary files /dev/null and b/.vs/LEARNIHON/FileContentIndex/a731465e-eb3c-499c-8b0d-31f641e360d5.vsidx differ
diff --git a/.vs/LEARNIHON/FileContentIndex/a7dd2f40-abf0-45ad-9ffc-b68af86427ae.vsidx b/.vs/LEARNIHON/FileContentIndex/a7dd2f40-abf0-45ad-9ffc-b68af86427ae.vsidx
deleted file mode 100644
index 07329bf..0000000
Binary files a/.vs/LEARNIHON/FileContentIndex/a7dd2f40-abf0-45ad-9ffc-b68af86427ae.vsidx and /dev/null differ
diff --git a/.vs/LEARNIHON/FileContentIndex/d5ec9cbe-63e1-4a04-aad4-7e43aeb6e545.vsidx b/.vs/LEARNIHON/FileContentIndex/d5ec9cbe-63e1-4a04-aad4-7e43aeb6e545.vsidx
deleted file mode 100644
index 911a013..0000000
Binary files a/.vs/LEARNIHON/FileContentIndex/d5ec9cbe-63e1-4a04-aad4-7e43aeb6e545.vsidx and /dev/null differ
diff --git a/.vs/LEARNIHON/v17/.wsuo b/.vs/LEARNIHON/v17/.wsuo
index 9781c68..2f2f413 100644
Binary files a/.vs/LEARNIHON/v17/.wsuo and b/.vs/LEARNIHON/v17/.wsuo differ
diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json
index db14d0e..1048f14 100644
--- a/.vs/VSWorkspaceState.json
+++ b/.vs/VSWorkspaceState.json
@@ -1,7 +1,13 @@
{
"ExpandedNodes": [
- ""
+ "",
+ "\\assets",
+ "\\components",
+ "\\model",
+ "\\navigation",
+ "\\pages",
+ "\\redux"
],
- "SelectedNode": "\\C:\\Users\\Siph9\\Source\\Repos\\LEARNIHON",
+ "SelectedNode": "\\components\\KanjiListCell.tsx",
"PreviewInSolutionExplorer": false
}
\ No newline at end of file
diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite
index fe38e26..feede14 100644
Binary files a/.vs/slnx.sqlite and b/.vs/slnx.sqlite differ
diff --git a/assets/answerAnimation.ts b/assets/answerAnimation.ts
index b6189f9..a1dc765 100644
--- a/assets/answerAnimation.ts
+++ b/assets/answerAnimation.ts
@@ -23,7 +23,7 @@ export const animatedStyles = {
{
translateY: animation.interpolate({
inputRange: [0, 1],
- outputRange: [0, -Dimensions.get('window').height / 1.9]
+ outputRange: [0, -Dimensions.get('window').height / 2]
}),
},
],
diff --git a/components/DetailExamples.tsx b/components/DetailExamples.tsx
new file mode 100644
index 0000000..a923f99
--- /dev/null
+++ b/components/DetailExamples.tsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import { FlatList, StyleSheet, Text, useColorScheme, View } from 'react-native';
+
+
+
+interface detailExamplesProps {
+ data: { japanese: string, english: string }[]
+}
+
+const DetailExamples = (props: detailExamplesProps) => {
+
+ const detailExamplesStyle = useColorScheme() == 'light' ? detailExamplesStyle_light : detailExamplesStyle_dark;
+
+ return (
+
+ item.japanese + item.english}
+ renderItem={
+ ({ item }) =>
+ true}>
+ {item.japanese}
+ {item.english}
+
+ }>
+
+
+ );
+};
+
+const detailExamplesStyle_light = StyleSheet.create({
+ container: {
+ width: '100%',
+ paddingBottom: 50,
+ },
+ cellContainer: {
+ flex: 1,
+ flexDirection: "row"
+ },
+ textJapanese: {
+ width: "50%"
+ },
+ textEnglish: {
+ textAlign: "right",
+ width: "50%"
+ }
+})
+
+const detailExamplesStyle_dark = StyleSheet.create({
+ container: {
+ width: '100%',
+ paddingBottom: 50,
+ },
+ cellContainer: {
+ flex: 1,
+ flexDirection: "row"
+ },
+ textJapanese: {
+ width: "50%",
+ color: "white"
+ },
+ textEnglish: {
+ textAlign: "right",
+ width: "50%",
+ color: "white"
+ }
+})
+
+export default DetailExamples;
\ No newline at end of file
diff --git a/components/DetailRadical.tsx b/components/DetailRadical.tsx
new file mode 100644
index 0000000..dd2aa3b
--- /dev/null
+++ b/components/DetailRadical.tsx
@@ -0,0 +1,73 @@
+import React from 'react';
+import { StyleSheet, Text, useColorScheme, View } from 'react-native';
+import { SvgXml } from 'react-native-svg';
+import { useDispatch, useSelector } from 'react-redux';
+
+
+
+interface detailRadicalProps {
+ character: string,
+ icon: string
+}
+
+const DetailRadical = (props: detailRadicalProps) => {
+
+ const detailRadicalStyle = useColorScheme() == 'light' ? detailRadicalStyle_light : detailRadicalStyle_dark;
+ return (
+
+ {props.character}
+
+
+ );
+};
+
+const detailRadicalStyle_light = StyleSheet.create({
+ container: {
+ height: 30,
+ width: 30,
+ },
+ svg: {
+ color: "#FF5C5C"
+ },
+ radicalIcon: {
+ position: "absolute"
+ },
+ radicalText: {
+ fontWeight: "bold",
+ textAlign: "center",
+ width: 30,
+ height: 30,
+ fontSize: 25
+ },
+})
+
+const detailRadicalStyle_dark = StyleSheet.create({
+ container: {
+ height: 30,
+ width: 30,
+ },
+ svg: {
+ color: "#FF5C5C"
+ },
+ radicalIcon: {
+ position: "absolute"
+ },
+ radicalText: {
+ fontWeight: "bold",
+ textAlign: "center",
+ width: 30,
+ height: 30,
+ fontSize: 25,
+ color: "white"
+ },
+})
+
+export default DetailRadical;
\ No newline at end of file
diff --git a/components/KanjiCard.tsx b/components/KanjiCard.tsx
index 7b8addd..9987701 100644
--- a/components/KanjiCard.tsx
+++ b/components/KanjiCard.tsx
@@ -26,13 +26,13 @@ const KanjiCard = (props: KanjiProps) => {
const fetchData = async () => {
await fetch(`https://kanjialive-api.p.rapidapi.com/api/public/kanji/${props.kanji}`, options)
- .then(async response => {
+ .then(async response => {
const data = await response.json()
setData(data);
const xml = await (await fetch(data.kanji.video.poster)).text();
setImgXml(xml);
})
- .catch(err => console.log(err));
+ .catch(err => console.log(err));
}
useEffect(() => {
@@ -44,7 +44,7 @@ const KanjiCard = (props: KanjiProps) => {
return (
-
+
{loading ? Loading... : {res.kanji.onyomi.katakana}}
{!loading && (
@@ -54,11 +54,11 @@ const KanjiCard = (props: KanjiProps) => {
width="200"
height="200"
/>
- )}
- {loading ? : {res.kanji.meaning.english}}
-
-
-
+ )}
+ {loading ? : {res.kanji.meaning.english}}
+
+
+
);
};
diff --git a/components/KanjiList.tsx b/components/KanjiList.tsx
index 0bb146e..57961c5 100644
--- a/components/KanjiList.tsx
+++ b/components/KanjiList.tsx
@@ -34,7 +34,7 @@ const KanjiList = () => {
renderSectionHeader={({ section }) => (
{section.title}
)}
- keyExtractor={item => `basicListEntry-${item}`}
+ keyExtractor={item => `basicListEntry-${item.character}`}
>
diff --git a/components/KanjiListCell.tsx b/components/KanjiListCell.tsx
index 8087c82..bde0e8b 100644
--- a/components/KanjiListCell.tsx
+++ b/components/KanjiListCell.tsx
@@ -14,7 +14,7 @@ const KanjiListCell = (props: kanjiListCellProps) => {
const navigator = useNavigation();
return (
- navigator.push("Detail", {"kanji": props.kanji})} style={cellStyle.item}>
+ navigator.navigate("Detail", {"kanji": props.kanji})} style={cellStyle.item}>
{props.kanji.character}
{props.kanji.meaning}
diff --git a/components/KanjiPlaygroundList.tsx b/components/KanjiPlaygroundList.tsx
index eb35f3e..b88a16b 100644
--- a/components/KanjiPlaygroundList.tsx
+++ b/components/KanjiPlaygroundList.tsx
@@ -32,7 +32,7 @@ const KanjiPlaygroundList = (props: kanjiPlaygroundListProps) => {
)
}
- keyExtractor={item => `basicListEntry-${item}`}>
+ keyExtractor={item => `basicListEntry-${item.character}`}>
);
diff --git a/model/kanji.ts b/model/kanji.ts
index 2fccf50..b5d2b91 100644
--- a/model/kanji.ts
+++ b/model/kanji.ts
@@ -2,11 +2,34 @@ export class Kanji {
private _character: string;
private _meaning: string;
private _image: string;
+ private _animation: string;
+ private _strokes: number;
+ private _onyomi: string;
+ private _kunyomi: string;
+ private _radical: {
+ character: string,
+ position: string
+ }
+ private _examples: {
+ japanese: string,
+ english: string
+ }[]
- constructor(character: string, meaning: string, image: string) {
+ constructor(character: string, meaning: string, image: string,
+ animation: string, strokes: number, onyomi: string,
+ kunyomi: string,
+ radical: { character: string, position: string },
+ examples: { japanese: string, english: string }[]
+ ) {
this._character = character;
this._meaning = meaning;
this._image = image;
+ this._animation = animation;
+ this._strokes = strokes;
+ this._onyomi = onyomi;
+ this._kunyomi = kunyomi;
+ this._radical = radical;
+ this._examples = examples;
}
get character(): string {
@@ -21,11 +44,41 @@ export class Kanji {
return this._image;
}
+ get animation(): string {
+ return this._animation;
+ }
+
+ get strokes(): number {
+ return this._strokes;
+ }
+
+ get onyomi(): string {
+ return this._onyomi;
+ }
+
+ get kunyomi(): string {
+ return this._kunyomi;
+ }
+
+ get radical(): { character: string, position: string } {
+ return this._radical;
+ }
+
+ get examples(): { japanese: string, english: string }[] {
+ return this._examples;
+ }
+
toObject() {
return {
character: this._character,
meaning: this._meaning,
- image: this._image
+ image: this._image,
+ animation: this._animation,
+ strokes: this._strokes,
+ onyomi: this._onyomi,
+ kunyomi: this.kunyomi,
+ radical: this._radical,
+ examples: this._examples
};
}
@@ -34,14 +87,31 @@ export class Kanji {
export class KanjiMapper {
static ApiJsonToKanji(json: any): Kanji {
- console.log(typeof json)
- return new Kanji(json.kanji.character, json.kanji.meaning.english, json.kanji.video.poster);
+ var radical: { character: string, position: string } = {
+ character: json.radical.character,
+ position: json.radical.position.icon
+ };
+
+ var examples: { japanese: string, english: string }[] = [];
+
+ json.examples.forEach(
+ (entry) => {
+ examples.push({
+ japanese: entry.japanese,
+ english: entry.meaning.english
+ })
+ }
+ )
+
+ return new Kanji(json.kanji.character, json.kanji.meaning.english, json.kanji.video.poster,
+ json.kanji.video.mp4, json.kanji.strokes.count, json.kanji.onyomi.katakana, json.kanji.kunyomi.hiragana,
+ radical, examples);
}
// @ts-ignore
static SerializedObjectToKanji(obj): Kanji | null {
if (!obj) return null;
- return new Kanji(obj.character, obj.meaning, obj.image);
+ return new Kanji(obj.character, obj.meaning, obj.image, obj.animation, obj.strokes, obj.onyomi, obj.kunyomi, obj.radical, obj.examples);
}
}
diff --git a/navigation/Stack.tsx b/navigation/Stack.tsx
index 92680eb..d3eeb69 100644
--- a/navigation/Stack.tsx
+++ b/navigation/Stack.tsx
@@ -9,10 +9,10 @@ export default function KanjiStackNavigator() {
const Stack = createStackNavigator();
return (
-
-
+
)
@@ -20,6 +20,6 @@ export default function KanjiStackNavigator() {
const stackOptions: StackNavigationOptions = {
- headerShown: false,
+ headerShown: false,
presentation: "modal"
-};
\ No newline at end of file
+};
diff --git a/package-lock.json b/package-lock.json
index 92ad49b..3bf5f75 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -26,6 +26,7 @@
"react-native-feather": "^1.1.2",
"react-native-gesture-handler": "^2.8.0",
"react-native-svg": "13.4.0",
+ "react-native-video": "^5.2.1",
"react-native-web": "~0.18.9",
"react-redux": "^8.0.5",
"redux": "^4.2.1",
@@ -36,6 +37,7 @@
"@types/react": "~18.0.14",
"@types/react-native": "~0.70.6",
"@types/react-native-canvas": "^0.1.9",
+ "@types/react-native-video": "^5.0.14",
"typescript": "^4.6.3"
}
},
@@ -4706,6 +4708,16 @@
"@types/react-native": "*"
}
},
+ "node_modules/@types/react-native-video": {
+ "version": "5.0.14",
+ "resolved": "https://registry.npmjs.org/@types/react-native-video/-/react-native-video-5.0.14.tgz",
+ "integrity": "sha512-KdcyY4HY/Q1l6f5qQA337BNVN+GsdZy836j9CXbWHZ008VVNzSlnJypJQPsnUgI0EPBw/uG/lyJk6cg9Jj1syg==",
+ "dev": true,
+ "dependencies": {
+ "@types/react": "*",
+ "@types/react-native": "*"
+ }
+ },
"node_modules/@types/responselike": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
@@ -7706,6 +7718,16 @@
"node": ">= 0.6"
}
},
+ "node_modules/deprecated-react-native-prop-types": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz",
+ "integrity": "sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==",
+ "dependencies": {
+ "@react-native/normalize-color": "*",
+ "invariant": "*",
+ "prop-types": "*"
+ }
+ },
"node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
@@ -7871,6 +7893,11 @@
"integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
"license": "ISC"
},
+ "node_modules/eme-encryption-scheme-polyfill": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/eme-encryption-scheme-polyfill/-/eme-encryption-scheme-polyfill-2.1.1.tgz",
+ "integrity": "sha512-njD17wcUrbqCj0ArpLu5zWXtaiupHb/2fIUQGdInf83GlI+Q6mmqaPGLdrke4savKAu15J/z1Tg/ivDgl14g0g=="
+ },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -11745,6 +11772,11 @@
"integrity": "sha512-VHdsIWwXNO1l+fqwNdYZ/dDGnaN60RLuOIgMnwL+2kE3woPvxpOpeusjfaMZbTFaQFwGnTTzFbVHqQrDqf1FnQ==",
"license": "MIT"
},
+ "node_modules/keymirror": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/keymirror/-/keymirror-0.1.1.tgz",
+ "integrity": "sha512-vIkZAFWoDijgQT/Nvl2AHCMmnegN2ehgTPYuyy2hWQkQSntI0S7ESYqdLkoSe1HyEBFHHkCgSIvVdSEiWwKvCg=="
+ },
"node_modules/keyv": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
@@ -14969,6 +15001,17 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
+ "node_modules/react-native-video": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-5.2.1.tgz",
+ "integrity": "sha512-aJlr9MeTuQ0LpZ4n+EC9RvhoKeiPbLtI2Rxy8u7zo/wzGevbRpWHSBj9xZ5YDBXnAVXzuqyNIkGhdw7bfdIBZw==",
+ "dependencies": {
+ "deprecated-react-native-prop-types": "^2.2.0",
+ "keymirror": "^0.1.1",
+ "prop-types": "^15.7.2",
+ "shaka-player": "^2.5.9"
+ }
+ },
"node_modules/react-native-web": {
"version": "0.18.11",
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.11.tgz",
@@ -15905,6 +15948,15 @@
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
"license": "ISC"
},
+ "node_modules/shaka-player": {
+ "version": "2.5.23",
+ "resolved": "https://registry.npmjs.org/shaka-player/-/shaka-player-2.5.23.tgz",
+ "integrity": "sha512-3MC9k0OXJGw8AZ4n/ZNCZS2yDxx+3as5KgH6Tx4Q5TRboTBBCu6dYPI5vp1DxKeyU12MBN1Zcbs7AKzXv2EnCg==",
+ "deprecated": "Shaka Player < v3.2 is no longer supported.",
+ "dependencies": {
+ "eme-encryption-scheme-polyfill": "^2.0.1"
+ }
+ },
"node_modules/shallow-clone": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
@@ -22192,6 +22244,16 @@
"@types/react-native": "*"
}
},
+ "@types/react-native-video": {
+ "version": "5.0.14",
+ "resolved": "https://registry.npmjs.org/@types/react-native-video/-/react-native-video-5.0.14.tgz",
+ "integrity": "sha512-KdcyY4HY/Q1l6f5qQA337BNVN+GsdZy836j9CXbWHZ008VVNzSlnJypJQPsnUgI0EPBw/uG/lyJk6cg9Jj1syg==",
+ "dev": true,
+ "requires": {
+ "@types/react": "*",
+ "@types/react-native": "*"
+ }
+ },
"@types/responselike": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
@@ -24272,6 +24334,16 @@
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="
},
+ "deprecated-react-native-prop-types": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz",
+ "integrity": "sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==",
+ "requires": {
+ "@react-native/normalize-color": "*",
+ "invariant": "*",
+ "prop-types": "*"
+ }
+ },
"destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
@@ -24393,6 +24465,11 @@
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
"integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA=="
},
+ "eme-encryption-scheme-polyfill": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/eme-encryption-scheme-polyfill/-/eme-encryption-scheme-polyfill-2.1.1.tgz",
+ "integrity": "sha512-njD17wcUrbqCj0ArpLu5zWXtaiupHb/2fIUQGdInf83GlI+Q6mmqaPGLdrke4savKAu15J/z1Tg/ivDgl14g0g=="
+ },
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -27196,6 +27273,11 @@
"resolved": "https://registry.npmjs.org/keychain/-/keychain-1.3.0.tgz",
"integrity": "sha512-VHdsIWwXNO1l+fqwNdYZ/dDGnaN60RLuOIgMnwL+2kE3woPvxpOpeusjfaMZbTFaQFwGnTTzFbVHqQrDqf1FnQ=="
},
+ "keymirror": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/keymirror/-/keymirror-0.1.1.tgz",
+ "integrity": "sha512-vIkZAFWoDijgQT/Nvl2AHCMmnegN2ehgTPYuyy2hWQkQSntI0S7ESYqdLkoSe1HyEBFHHkCgSIvVdSEiWwKvCg=="
+ },
"keyv": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
@@ -29423,6 +29505,17 @@
}
}
},
+ "react-native-video": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-5.2.1.tgz",
+ "integrity": "sha512-aJlr9MeTuQ0LpZ4n+EC9RvhoKeiPbLtI2Rxy8u7zo/wzGevbRpWHSBj9xZ5YDBXnAVXzuqyNIkGhdw7bfdIBZw==",
+ "requires": {
+ "deprecated-react-native-prop-types": "^2.2.0",
+ "keymirror": "^0.1.1",
+ "prop-types": "^15.7.2",
+ "shaka-player": "^2.5.9"
+ }
+ },
"react-native-web": {
"version": "0.18.11",
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.11.tgz",
@@ -30068,6 +30161,14 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
},
+ "shaka-player": {
+ "version": "2.5.23",
+ "resolved": "https://registry.npmjs.org/shaka-player/-/shaka-player-2.5.23.tgz",
+ "integrity": "sha512-3MC9k0OXJGw8AZ4n/ZNCZS2yDxx+3as5KgH6Tx4Q5TRboTBBCu6dYPI5vp1DxKeyU12MBN1Zcbs7AKzXv2EnCg==",
+ "requires": {
+ "eme-encryption-scheme-polyfill": "^2.0.1"
+ }
+ },
"shallow-clone": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
diff --git a/package.json b/package.json
index 15990c8..872b317 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"react-native-feather": "^1.1.2",
"react-native-gesture-handler": "^2.8.0",
"react-native-svg": "13.4.0",
+ "react-native-video": "^5.2.1",
"react-native-web": "~0.18.9",
"react-redux": "^8.0.5",
"redux": "^4.2.1",
@@ -37,6 +38,7 @@
"@types/react": "~18.0.14",
"@types/react-native": "~0.70.6",
"@types/react-native-canvas": "^0.1.9",
+ "@types/react-native-video": "^5.0.14",
"typescript": "^4.6.3"
},
"private": true
diff --git a/pages/Detail.tsx b/pages/Detail.tsx
index 48c5a18..676040d 100644
--- a/pages/Detail.tsx
+++ b/pages/Detail.tsx
@@ -1,28 +1,287 @@
-import React from 'react';
-import { Text, View, StyleSheet, useColorScheme } from 'react-native';
+import React, { useEffect, useState } from 'react';
+import { Text, View, StyleSheet, useColorScheme, FlatList, ScrollView } from 'react-native';
import KanjiListCell from '../components/KanjiListCell';
-import { Kanji } from '../model/kanji';
-
+import { Kanji, KanjiMapper } from '../model/kanji';
+import Video from 'react-native-video';
+import { SvgXml } from 'react-native-svg';
+import KanjiPlaygroundList from '../components/KanjiPlaygroundList';
+import DetailExamples from '../components/DetailExamples';
+import DetailRadical from '../components/DetailRadical';
const Detail = ({route}) => {
- const kanji = route.params.kanji;
+ const kanji_temp = route.params.kanji;
const detailStyle = useColorScheme() == 'light' ? detailStyle_light : detailStyle_dark;
+ const [imgXml, setImgXml] = useState('');
+ const [iconXml, setIconXml] = useState('');
+
+ const fetchXml = async () => {
+ const xml = await (await fetch(kanji.image)).text();
+ const iconxml = await (await fetch(kanji.radical.position)).text();
+ setImgXml(xml);
+ setIconXml(iconxml);
+ }
+
+ useEffect(() => {
+ fetchXml();
+ }, []);
+
+ const kanji = KanjiMapper.ApiJsonToKanji({
+ "kanji": {
+ "character": "所",
+ "meaning": {
+ "english": "place"
+ },
+ "strokes": {
+ "count": 8,
+ "timings": [
+ 0,
+ 1.465,
+ 2.598,
+ 3.465,
+ 4.332,
+ 5.332,
+ 6.265,
+ 7.198,
+ 8.533333
+ ],
+ "images": [
+ "https://media.kanjialive.com/kanji_strokes/(ba)sho_1.svg",
+ "https://media.kanjialive.com/kanji_strokes/(ba)sho_2.svg",
+ "https://media.kanjialive.com/kanji_strokes/(ba)sho_3.svg",
+ "https://media.kanjialive.com/kanji_strokes/(ba)sho_4.svg",
+ "https://media.kanjialive.com/kanji_strokes/(ba)sho_5.svg",
+ "https://media.kanjialive.com/kanji_strokes/(ba)sho_6.svg",
+ "https://media.kanjialive.com/kanji_strokes/(ba)sho_7.svg",
+ "https://media.kanjialive.com/kanji_strokes/(ba)sho_8.svg"
+ ]
+ },
+ "onyomi": {
+ "romaji": "sho",
+ "katakana": "ショ"
+ },
+ "kunyomi": {
+ "romaji": "tokoro",
+ "hiragana": "ところ"
+ },
+ "video": {
+ "poster": "https://media.kanjialive.com/kanji_strokes/(ba)sho_8.svg",
+ "mp4": "https://media.kanjialive.com/kanji_animations/kanji_mp4/(ba)sho_00.mp4",
+ "webm": "https://media.kanjialive.com/kanji_animations/kanji_webm/(ba)sho_00.webm"
+ }
+ },
+ "radical": {
+ "character": "⼧",
+ "strokes": 4,
+ "image": "https://media.kanjialive.com/radical_character/todare.svg",
+ "position": {
+ "hiragana": "たれ",
+ "romaji": "tare",
+ "icon": "https://media.kanjialive.com/rad_positions/tare.svg"
+ },
+ "name": {
+ "hiragana": "とだれ",
+ "romaji": "todare"
+ },
+ "meaning": {
+ "english": "door"
+ },
+ "animation": [
+ "https://media.kanjialive.com/rad_frames/todare0.svg",
+ "https://media.kanjialive.com/rad_frames/todare1.svg",
+ "https://media.kanjialive.com/rad_frames/todare2.svg"
+ ]
+ },
+ "references": {
+ "grade": 3,
+ "kodansha": "568",
+ "classic_nelson": "1821"
+ },
+ "examples": [
+ {
+ "japanese": "場所(ばしょ)",
+ "meaning": {
+ "english": "place"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_a.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_a.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_a.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_a.mp3"
+ }
+ },
+ {
+ "japanese": "住所(じゅうしょ)",
+ "meaning": {
+ "english": "address"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_b.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_b.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_b.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_b.mp3"
+ }
+ },
+ {
+ "japanese": "近所(きんじょ)",
+ "meaning": {
+ "english": "neighborhood"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_c.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_c.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_c.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_c.mp3"
+ }
+ },
+ {
+ "japanese": "役所(やくしょ)",
+ "meaning": {
+ "english": "public office"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_d.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_d.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_d.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_d.mp3"
+ }
+ },
+ {
+ "japanese": "名所(めいしょ)",
+ "meaning": {
+ "english": "famous place"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_e.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_e.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_e.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_e.mp3"
+ }
+ },
+ {
+ "japanese": "研究所(けんきゅうじょ)",
+ "meaning": {
+ "english": "research institute"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_f.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_f.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_f.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_f.mp3"
+ }
+ },
+ {
+ "japanese": "停留所(ていりゅうじょ)",
+ "meaning": {
+ "english": "bus stop"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_g.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_g.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_g.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_g.mp3"
+ }
+ },
+ {
+ "japanese": "所有する(しょゆうする)",
+ "meaning": {
+ "english": "possess"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_h.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_h.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_h.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_h.mp3"
+ }
+ },
+ {
+ "japanese": "所(ところ)",
+ "meaning": {
+ "english": "place"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_i.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_i.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_i.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_i.mp3"
+ }
+ },
+ {
+ "japanese": "台所(だいどころ)",
+ "meaning": {
+ "english": "kitchen"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_j.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_j.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_j.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_j.mp3"
+ }
+ },
+ {
+ "japanese": "居所(いどころ)",
+ "meaning": {
+ "english": "whereabouts"
+ },
+ "audio": {
+ "opus": "https://media.kanjialive.com/examples_audio/audio-opus/(ba)sho_06_k.opus",
+ "aac": "https://media.kanjialive.com/examples_audio/audio-aac/(ba)sho_06_k.aac",
+ "ogg": "https://media.kanjialive.com/examples_audio/audio-ogg/(ba)sho_06_k.ogg",
+ "mp3": "https://media.kanjialive.com/examples_audio/audio-mp3/(ba)sho_06_k.mp3"
+ }
+ }
+ ]
+ })
return (
-
+ {kanji.onyomi}
+ {kanji.kunyomi}
+
+ {kanji.strokes + " strokes"}
+ {kanji.meaning}
+
+ Radical
+
+
+ Examples
+
);
};
+
const detailStyle_light = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
- backgroundColor: "#e4e4e4"
+ backgroundColor: "#e4e4e4",
+ },
+ svg: {
+ color: "black"
+ },
+ title: {
+ fontWeight: "bold",
+ fontSize: 20,
+ },
+ text: {
+ color: "black"
+ },
+ tinyText: {
+ fontSize: 10,
+ color: "black"
+ },
+ meaningText: {
+ fontSize: 50,
+ color: "#FF5C5C",
+ fontWeight: "900",
+
}
})
@@ -32,8 +291,29 @@ const detailStyle_dark = StyleSheet.create({
flex: 1,
justifyContent: 'center',
alignItems: 'center',
- backgroundColor: '#3c3c3c',
+ backgroundColor: "#1c1c1c",
+ },
+ svg: {
+ color: "white"
+ },
+ title: {
+ fontWeight: "bold",
+ fontSize: 20,
+ color: "white"
},
+ text: {
+ color: "white"
+ },
+ tinyText: {
+ fontSize: 10,
+ color: "white"
+ },
+ meaningText: {
+ fontSize: 50,
+ color: "#FF5C5C",
+ fontWeight: "900",
+
+ }
});
export default Detail;
\ No newline at end of file