parent
f1a4952a2a
commit
0cccc65a3e
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,13 +1,15 @@
|
|||||||
{
|
{
|
||||||
"ExpandedNodes": [
|
"ExpandedNodes": [
|
||||||
"",
|
"",
|
||||||
"\\assets",
|
|
||||||
"\\components",
|
"\\components",
|
||||||
"\\model",
|
"\\model",
|
||||||
"\\navigation",
|
"\\navigation",
|
||||||
"\\pages",
|
"\\pages",
|
||||||
"\\redux"
|
"\\redux",
|
||||||
|
"\\redux\\actions",
|
||||||
|
"\\redux\\reducers",
|
||||||
|
"\\redux\\thunks"
|
||||||
],
|
],
|
||||||
"SelectedNode": "\\components\\KanjiListCell.tsx",
|
"SelectedNode": "\\components\\KanjiListSearchPanel.tsx",
|
||||||
"PreviewInSolutionExplorer": false
|
"PreviewInSolutionExplorer": false
|
||||||
}
|
}
|
Binary file not shown.
@ -0,0 +1,78 @@
|
|||||||
|
import { useNavigation } from '@react-navigation/native';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Text, View, StyleSheet, TouchableOpacity, useColorScheme, Animated } from 'react-native';
|
||||||
|
import { Check } from "react-native-feather";
|
||||||
|
|
||||||
|
interface gradeChipProps {
|
||||||
|
grade: number;
|
||||||
|
onSelect: (item: string, isSelected: Boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GradeChip = (props: gradeChipProps) => {
|
||||||
|
|
||||||
|
const [chipStyle, setChipStyle] = useState(style);
|
||||||
|
|
||||||
|
const [isSelected, setIsSelected] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setChipStyle(isSelected ? styleSELECTED : style);
|
||||||
|
}, [isSelected]);
|
||||||
|
|
||||||
|
const select = () => {
|
||||||
|
props.onSelect("Grade "+props.grade, isSelected);
|
||||||
|
setIsSelected(!isSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity style={chipStyle.chip} onPress={() => { select() }}>
|
||||||
|
<Text style={chipStyle.text}>Grade {props.grade}</Text>
|
||||||
|
{isSelected && (<Check style={chipStyle.icon} />)}
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const style = StyleSheet.create({
|
||||||
|
chip: {
|
||||||
|
backgroundColor: "#FF5C5C",
|
||||||
|
borderRadius: 10,
|
||||||
|
margin: 5,
|
||||||
|
justifyContent: "center",
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
color: "white",
|
||||||
|
margin: 5
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
color: "white",
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "18em",
|
||||||
|
padding: 5
|
||||||
|
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const styleSELECTED = StyleSheet.create({
|
||||||
|
chip: {
|
||||||
|
backgroundColor: "#FF5C5C",
|
||||||
|
borderRadius: 10,
|
||||||
|
margin: 5,
|
||||||
|
justifyContent: "center",
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
color: "white",
|
||||||
|
margin: 5
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
color: "white",
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "18em",
|
||||||
|
padding: 5
|
||||||
|
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default GradeChip;
|
@ -0,0 +1,50 @@
|
|||||||
|
import { useNavigation } from "@react-navigation/native";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { FlatList, TextInput, StyleSheet, View } from "react-native";
|
||||||
|
import GradeChip from './GradeChip';
|
||||||
|
|
||||||
|
interface kanjiListSeachPanelProps {
|
||||||
|
onSelect: (item: string, isSelected: Boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const KanjiListSearchPanel = (props: kanjiListSeachPanelProps) => {
|
||||||
|
|
||||||
|
const navigator = useNavigation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={panelStyle.container}>
|
||||||
|
<TextInput style={panelStyle.input} />
|
||||||
|
<FlatList
|
||||||
|
data={[1, 2, 3, 4, 5, 6]}
|
||||||
|
renderItem={(item) => <GradeChip grade={item.item} onSelect={props.onSelect} />}
|
||||||
|
horizontal={true}
|
||||||
|
showsHorizontalScrollIndicator={false}
|
||||||
|
|
||||||
|
>
|
||||||
|
</FlatList>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const panelStyle = StyleSheet.create({
|
||||||
|
input: {
|
||||||
|
height: 40,
|
||||||
|
margin: 12,
|
||||||
|
borderWidth: 1,
|
||||||
|
padding: 10,
|
||||||
|
width: 200,
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderRadius: 20,
|
||||||
|
borderColor: "black",
|
||||||
|
width: "80%"
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
height: "20%"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export default KanjiListSearchPanel;
|
@ -0,0 +1,21 @@
|
|||||||
|
import { Kanji } from "./kanji"
|
||||||
|
|
||||||
|
export type KanjiListByGrade = {
|
||||||
|
"Grade 1": Kanji[],
|
||||||
|
"Grade 2": Kanji[],
|
||||||
|
"Grade 3": Kanji[],
|
||||||
|
"Grade 4": Kanji[],
|
||||||
|
"Grade 5": Kanji[],
|
||||||
|
"Grade 6": Kanji[],
|
||||||
|
}[]
|
||||||
|
|
||||||
|
export const initKanjiListByGrade = (): KanjiListByGrade => {
|
||||||
|
return {
|
||||||
|
"Grade 1": [],
|
||||||
|
"Grade 2": [],
|
||||||
|
"Grade 3": [],
|
||||||
|
"Grade 4": [],
|
||||||
|
"Grade 5": [],
|
||||||
|
"Grade 6": [],
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
import { Kanji } from "./kanji";
|
||||||
|
|
||||||
|
export class KanjiMapper {
|
||||||
|
|
||||||
|
static ApiJsonToKanji(json: any): Kanji {
|
||||||
|
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, obj.animation, obj.strokes, obj.onyomi, obj.kunyomi, obj.radical, obj.examples);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
export type kanjiSearchParams = {
|
||||||
|
input: string
|
||||||
|
grades: string[]
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
import { NavigationContainer, useNavigation } from "@react-navigation/native";
|
||||||
|
import { createStackNavigator, StackNavigationOptions } from "@react-navigation/stack";
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { View, StyleSheet, Text } from "react-native";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { fetchKanjis } from "../redux/thunks/fetchKanjis";
|
||||||
|
import TabBar from "./TabBar";
|
||||||
|
|
||||||
|
|
||||||
|
const stackOptions: StackNavigationOptions = {
|
||||||
|
headerShown: false,
|
||||||
|
presentation: "modal"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InitStack = () => {
|
||||||
|
|
||||||
|
const Stack = createStackNavigator();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavigationContainer>
|
||||||
|
|
||||||
|
<Stack.Navigator initialRouteName="Startup"
|
||||||
|
screenOptions={stackOptions}
|
||||||
|
>
|
||||||
|
<Stack.Screen name="Startup" component={Startup} />
|
||||||
|
<Stack.Screen name="Main"
|
||||||
|
component={TabBar}
|
||||||
|
options={{ animationEnabled: false }} />
|
||||||
|
|
||||||
|
|
||||||
|
</Stack.Navigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Startup() {
|
||||||
|
|
||||||
|
const navigator = useNavigation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const init = async () => {
|
||||||
|
|
||||||
|
await dispatch(await fetchKanjis());
|
||||||
|
//await new Promise(resolve => setTimeout(resolve, 5000));
|
||||||
|
navigator.navigate("Main");
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
init()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={splashscreenStyle.container}>
|
||||||
|
<Text style={splashscreenStyle.title}>LEARNIHON</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const splashscreenStyle = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
position: "absolute",
|
||||||
|
backgroundColor: '#FF5C5C',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: 'white',
|
||||||
|
textAlign: 'center',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
fontSize: 50,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
import { Kanji } from '../../model/kanji';
|
|
||||||
import { FETCH_KANJIS } from '../constants';
|
|
||||||
|
|
||||||
export const fetchKanjis = (kanjis: Kanji[]) => {
|
|
||||||
return {
|
|
||||||
type: FETCH_KANJIS,
|
|
||||||
payload: kanjis,
|
|
||||||
};
|
|
||||||
}
|
|
@ -0,0 +1,10 @@
|
|||||||
|
import { Kanji } from '../../model/kanji';
|
||||||
|
import { SET_KANJIS } from '../constants';
|
||||||
|
import { KanjiListByGrade } from '../../model/kanjiListByGrades';
|
||||||
|
|
||||||
|
export const setKanjis = (kanjis: kanjiListByGrade) => {
|
||||||
|
return {
|
||||||
|
type: SET_KANJIS,
|
||||||
|
payload: kanjis,
|
||||||
|
};
|
||||||
|
}
|
@ -1,2 +1,2 @@
|
|||||||
export const FETCH_KANJIS = 'FETCH_KANJIS';
|
|
||||||
export const SET_SELECTED_KANJI = 'SET_SELECTED_KANJI';
|
export const SET_SELECTED_KANJI = 'SET_SELECTED_KANJI';
|
||||||
|
export const SET_KANJIS = 'SET_KANJIS';
|
@ -0,0 +1,40 @@
|
|||||||
|
import { initKanjiListByGrade, KanjiListByGrade } from '../../model/kanjiListByGrades';
|
||||||
|
import { KanjiMapper } from '../../model/kanjiMapper';
|
||||||
|
import { setKanjis } from '../actions/setKanjis';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
export const fetchKanjis = async () => {
|
||||||
|
|
||||||
|
const kanjis: KanjiListByGrade = initKanjiListByGrade();
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'X-RapidAPI-Key': '19516a9900mshce10de76f99976bp10f192jsn8c8d82222baa',
|
||||||
|
'X-RapidAPI-Host': 'kanjialive-api.p.rapidapi.com'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchData = async (grade: string) => {
|
||||||
|
return fetch(`https://kanjialive-api.p.rapidapi.com/api/public/search/advanced/?grade=${grade}`, options)
|
||||||
|
}
|
||||||
|
return async dispatch => {
|
||||||
|
const fetchAll = async () => {
|
||||||
|
for (let i = 1; i <= 6; i++) {
|
||||||
|
await fetchData(i.toString()).then(async (response) => {
|
||||||
|
const data = await response.json();
|
||||||
|
data.forEach(async (it: object) => {
|
||||||
|
await fetch(`https://kanjialive-api.p.rapidapi.com/api/public/kanji/${it.kanji.character}`, options)
|
||||||
|
.then(async detail => {
|
||||||
|
const detail_data = await detail.json();
|
||||||
|
kanjis['Grade ' + i].push(KanjiMapper.ApiJsonToKanji(detail_data));
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fetchAll().then(_ => dispatch(setKanjis(kanjis)))
|
||||||
|
.catch((err) => console.log("ERR : " + err));
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in new issue