Skip to content

Commit 83336ef

Browse files
committed
add furigana courtesy to jotoba API
1 parent 0587f5b commit 83336ef

19 files changed

+1221
-68
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ scripts/data/*
4848

4949
# ignore ios
5050
ios/
51+
android/
5152

5253
# @generated expo-cli sync-8d4afeec25ea8a192358fae2f8e2fc766bdce4ec
5354
# The following patterns were generated by expo-cli

app.json

+19-5
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,35 @@
1212
"resizeMode": "cover",
1313
"backgroundColor": "#ffffff"
1414
},
15-
"assetBundlePatterns": ["**/*"],
15+
"assetBundlePatterns": [
16+
"**/*"
17+
],
1618
"ios": {
1719
"supportsTablet": true,
1820
"bundleIdentifier": "dev.mmtf.jlpt-practice",
1921
"infoPlist": {
20-
"LSApplicationQueriesSchemes": ["shirabelookup"]
22+
"LSApplicationQueriesSchemes": [
23+
"shirabelookup"
24+
]
2125
}
2226
},
2327
"android": {
2428
"adaptiveIcon": {
2529
"foregroundImage": "./assets/images/adaptive-icon.png",
2630
"backgroundColor": "#ffffff"
2731
},
28-
"package": "dev.mmtf.jlpt-practice"
32+
"package": "dev.mmtf.jlpt_practice"
2933
},
3034
"web": {
3135
"bundler": "metro",
3236
"output": "static",
3337
"favicon": "./assets/images/favicon.png"
3438
},
35-
"plugins": ["expo-router", "expo-build-properties", "expo-font"],
39+
"plugins": [
40+
"expo-router",
41+
"expo-build-properties",
42+
"expo-font"
43+
],
3644
"experiments": {
3745
"typedRoutes": true
3846
},
@@ -44,6 +52,12 @@
4452
"projectId": "dff87a81-66f6-4afb-aed0-ac90289b3417"
4553
}
4654
},
47-
"owner": "mmdf"
55+
"owner": "mmdf",
56+
"runtimeVersion": {
57+
"policy": "appVersion"
58+
},
59+
"updates": {
60+
"url": "https://u.expo.dev/dff87a81-66f6-4afb-aed0-ac90289b3417"
61+
}
4862
}
4963
}

app/(tabs)/question.tsx

+11-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
submitAnswer,
66
} from "@/services/questions";
77
import { settingsStore } from "@/services/store";
8+
import { useIsFocused } from "@react-navigation/native";
89
import { useToastController } from "@tamagui/toast";
910
import { useCallback, useEffect, useState } from "react";
1011
import { AnimatePresence, Heading, Paragraph, View, YStack } from "tamagui";
@@ -21,6 +22,7 @@ const questionSchema = zod.object({
2122
});
2223

2324
function QuestionManager() {
25+
const focus = useIsFocused();
2426
const [solvedId, setSolvedId] = useState(0);
2527
const [answer, setAnswer] = useState<null | number>(null);
2628
const [questionBase, setQuestion] = useState<QuestionWithAnswers | null>(
@@ -71,10 +73,16 @@ function QuestionManager() {
7173
[setQuestion]
7274
);
7375

76+
const [scheduledUpdate, setScheduledUpdate] = useState(false);
7477
useEffect(() => {
75-
setAnswer(null);
76-
fetchQuestion();
78+
setScheduledUpdate(true);
7779
}, [categoryFilter, levelFilter]);
80+
useEffect(() => {
81+
if (focus && scheduledUpdate) {
82+
setAnswer(null);
83+
fetchQuestion();
84+
}
85+
}, [focus, scheduledUpdate]);
7886

7987
const handleAnswerBase = async (answerId: number) => {
8088
if (answer !== null) {
@@ -117,7 +125,7 @@ function QuestionManager() {
117125
/>
118126
</View>
119127
)}
120-
{!questionBase && !loading && (
128+
{!questionBase && !loading && !scheduledUpdate && (
121129
<YStack
122130
f={1}
123131
enterStyle={{ opacity: 0 }}

app/(tabs)/settings.tsx

+36-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,16 @@ import {
88
} from "@/services/questions";
99
import { answersTodayStore, settingsStore } from "@/services/store";
1010
import React, { useEffect } from "react";
11-
import { H5, Heading, Label, ScrollView, XStack, YStack } from "tamagui";
11+
import {
12+
H5,
13+
Heading,
14+
Label,
15+
ScrollView,
16+
Separator,
17+
Switch,
18+
XStack,
19+
YStack,
20+
} from "tamagui";
1221
import { MultipleSelectBox } from "../../components/SelectBox";
1322

1423
const levelItems: { name: Question["level"] }[] = [
@@ -83,6 +92,7 @@ const CategoryFilter = () => {
8392
const SettingsTab: React.FC = () => {
8493
const numberOfAnswersToday = answersTodayStore((s) => s.data.val);
8594
const [answers, setAnswers] = React.useState<QuestionAnswer[]>([]);
95+
8696
useEffect(() => {
8797
getAnswersToday().then((answers) => {
8898
answersTodayStore.getState().update((state) => {
@@ -97,9 +107,11 @@ const SettingsTab: React.FC = () => {
97107
null
98108
);
99109

100-
const { categoryFilter, questionLevelFilter: levelFilter } = settingsStore(
101-
(state) => state.data
102-
);
110+
const {
111+
categoryFilter,
112+
questionLevelFilter: levelFilter,
113+
furiEnabled,
114+
} = settingsStore((state) => state.data);
103115

104116
useEffect(() => {
105117
getQuestionSeenStats({
@@ -114,6 +126,26 @@ const SettingsTab: React.FC = () => {
114126
<ScrollView>
115127
<YStack padding="$8" gap="$4">
116128
<Heading>Settings</Heading>
129+
<H5>Helpers</H5>
130+
<XStack width={200} alignItems="center" gap="$4">
131+
<Label paddingRight="$0" justifyContent="flex-end">
132+
Enable furigana
133+
{"\n"}
134+
<Label size="$1">*experimental</Label>
135+
</Label>
136+
<Separator minHeight={20} vertical />
137+
<Switch
138+
checked={furiEnabled}
139+
onCheckedChange={(s) =>
140+
settingsStore
141+
.getState()
142+
.update((state) => (state.furiEnabled = s))
143+
}
144+
>
145+
<Switch.Thumb animation="fast" />
146+
</Switch>
147+
</XStack>
148+
117149
<YStack gap="$2">
118150
<H5>Question Filters</H5>
119151
<CategoryFilter />

app/_layout.tsx

+39-28
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ import * as SplashScreen from "expo-splash-screen";
1010
import { useEffect } from "react";
1111

1212
import { tamaguiConfig } from "@/constants/tamagui";
13+
import { JotobaFuriganaService } from "@/services/ext/jotoba";
14+
import { FuriganaContext } from "@/services/furigana";
1315
import {
1416
Toast,
1517
ToastProvider,
1618
ToastViewport,
1719
useToastState,
1820
} from "@tamagui/toast";
21+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
1922
import { useColorScheme } from "react-native";
2023
import { useSafeAreaInsets } from "react-native-safe-area-context";
2124
import { TamaguiProvider, YStack } from "tamagui";
@@ -26,6 +29,8 @@ export {
2629
ErrorBoundary,
2730
} from "expo-router";
2831

32+
const qc = new QueryClient();
33+
2934
export const unstable_settings = {
3035
// Ensure that reloading on `/modal` keeps a back button present.
3136
initialRouteName: "(tabs)/question",
@@ -94,33 +99,39 @@ function RootLayoutNav() {
9499
const { top } = useSafeAreaInsets();
95100

96101
return (
97-
<TamaguiProvider
98-
config={tamaguiConfig}
99-
defaultTheme={colorScheme || "light"}
100-
>
101-
<ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
102-
<ToastProvider burntOptions={{ from: "top" }}>
103-
<ToastViewport position="absolute" left={0} right={0} top={top} />
104-
<CurrentToast />
105-
<MigrationProvider>
106-
<Stack>
107-
<Stack.Screen
108-
name="(tabs)"
109-
options={{ headerShown: false, title: "Home" }}
110-
/>
111-
<Stack.Screen
112-
name="grammar/[id]"
113-
options={{ title: "Grammar" }}
114-
/>
115-
<Stack.Screen
116-
name="grammar/list"
117-
options={{ title: "Grammar List" }}
118-
/>
119-
<Stack.Screen name="review" options={{ title: "Review" }} />
120-
</Stack>
121-
</MigrationProvider>
122-
</ToastProvider>
123-
</ThemeProvider>
124-
</TamaguiProvider>
102+
<FuriganaContext.Provider value={{ service: new JotobaFuriganaService() }}>
103+
<QueryClientProvider client={qc}>
104+
<TamaguiProvider
105+
config={tamaguiConfig}
106+
defaultTheme={colorScheme || "light"}
107+
>
108+
<ThemeProvider
109+
value={colorScheme === "dark" ? DarkTheme : DefaultTheme}
110+
>
111+
<ToastProvider burntOptions={{ from: "top" }}>
112+
<ToastViewport position="absolute" left={0} right={0} top={top} />
113+
<CurrentToast />
114+
<MigrationProvider>
115+
<Stack>
116+
<Stack.Screen
117+
name="(tabs)"
118+
options={{ headerShown: false, title: "Home" }}
119+
/>
120+
<Stack.Screen
121+
name="grammar/[id]"
122+
options={{ title: "Grammar" }}
123+
/>
124+
<Stack.Screen
125+
name="grammar/list"
126+
options={{ title: "Grammar List" }}
127+
/>
128+
<Stack.Screen name="review" options={{ title: "Review" }} />
129+
</Stack>
130+
</MigrationProvider>
131+
</ToastProvider>
132+
</ThemeProvider>
133+
</TamaguiProvider>
134+
</QueryClientProvider>
135+
</FuriganaContext.Provider>
125136
);
126137
}

components/AnswerButton.tsx

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { settingsStore } from "@/services/store";
12
import { Button, ThemeName } from "tamagui";
3+
import { JapaneseText } from "./JapaneseText";
24

35
export const AnswerButton = ({
46
answerText,
@@ -22,6 +24,8 @@ export const AnswerButton = ({
2224
theme = "blue";
2325
}
2426
}
27+
28+
const furiEnabled = settingsStore((s) => s.data.furiEnabled);
2529
return (
2630
<Button
2731
animation="superfastTransform"
@@ -31,10 +35,17 @@ export const AnswerButton = ({
3135
theme={theme}
3236
size={"$5"}
3337
noTextWrap={false}
34-
textProps={{ adjustsFontSizeToFit: true }}
3538
onPress={onPress}
3639
>
37-
{answerText}
40+
{furiEnabled ? (
41+
<JapaneseText
42+
textProps={{ adjustsFontSizeToFit: true }}
43+
size="$5"
44+
text={answerText}
45+
/>
46+
) : (
47+
answerText
48+
)}
3849
</Button>
3950
);
4051
};

0 commit comments

Comments
 (0)