1
- import {
2
- YStack ,
3
- XStack ,
4
- AnimatePresence ,
5
- View ,
6
- ScrollView ,
7
- Button ,
8
- } from "tamagui" ;
1
+ import { AnimatePresence , View } from "tamagui" ;
9
2
import { useCallback , useEffect , useState } from "react" ;
10
3
import {
11
4
getRandomQuestion ,
12
5
QuestionWithAnswers ,
13
6
submitAnswer ,
14
- } from "../.. /services/questions" ;
7
+ } from "@ /services/questions" ;
15
8
import { useToastController } from "@tamagui/toast" ;
16
9
import * as zod from "zod" ;
17
- import { AnswerButton } from "../../components/AnswerButton" ;
18
- import { QuestionContent } from "../../components/QuestionContent" ;
19
- import {
20
- BookOpen ,
21
- JapaneseYen ,
22
- Search ,
23
- SearchCheck ,
24
- SearchCode ,
25
- SearchX ,
26
- } from "@tamagui/lucide-icons" ;
27
- import { Linking } from "react-native" ;
28
- import * as WebBrowser from "expo-web-browser" ;
29
- import { SearchBar } from "react-native-screens" ;
10
+ import { QuestionView } from "@/components/QuestionView" ;
30
11
31
12
const questionSchema = zod . object ( {
32
13
id : zod . number ( ) ,
@@ -37,12 +18,10 @@ const questionSchema = zod.object({
37
18
correctAnswer : zod . number ( ) . lte ( 3 ) . gte ( 0 ) ,
38
19
} ) ;
39
20
40
- export default function TabOneScreen ( ) {
21
+ function QuestionManager ( ) {
41
22
const [ answer , setAnswer ] = useState < null | number > ( null ) ;
42
-
43
23
const [ question , setQuestion ] = useState < QuestionWithAnswers | null > ( null ) ;
44
24
const [ loading , setLoading ] = useState ( false ) ;
45
-
46
25
const toast = useToastController ( ) ;
47
26
48
27
const fetchQuestion = useCallback (
@@ -72,10 +51,12 @@ export default function TabOneScreen() {
72
51
setLoading ( false ) ;
73
52
}
74
53
} ,
75
- [ setQuestion ]
54
+ [ setQuestion ] ,
76
55
) ;
77
56
78
57
useEffect ( ( ) => {
58
+ if ( question ) return ;
59
+ setAnswer ( null ) ;
79
60
fetchQuestion ( ) ;
80
61
} , [ ] ) ;
81
62
@@ -91,100 +72,30 @@ export default function TabOneScreen() {
91
72
setAnswer ( answerId ) ;
92
73
} ;
93
74
94
- const [ layout , setLayout ] = useState ( {
95
- questionY : 0 ,
96
- containerY : 0 ,
97
- paragraphHeight : 0 ,
98
- } ) ;
99
-
100
75
return (
101
- < YStack
102
- onLayout = { ( e ) => {
103
- const y = e . nativeEvent . layout . y ;
104
- setLayout ( ( l ) => ( { ...l , containerY : y } ) ) ;
105
- } }
106
- height = "100%"
107
- paddingHorizontal = "$8"
108
- alignItems = "center"
109
- justifyContent = "flex-end"
110
- gap = "$4"
111
- >
112
- < AnimatePresence >
113
- < View
114
- overflow = "visible"
115
- width = "100%"
116
- animation = "fast"
117
- key = { question ?. question . toString ( ) }
118
- exitStyle = { { transform : [ { translateX : 200 } ] , opacity : 0 } }
119
- enterStyle = { { transform : [ { translateX : - 200 } ] , opacity : 0 } }
120
- onLayout = { ( e ) => {
121
- const y = e . nativeEvent . layout . y ;
122
- setLayout ( ( l ) => ( { ...l , questionY : y } ) ) ;
123
- } }
124
- transform = { [ { translateX : 0 } ] }
125
- >
126
- < ScrollView
127
- bottom = { 0 }
128
- left = { 0 }
129
- right = { 0 }
130
- position = "absolute"
131
- width = "100%"
132
- onContentSizeChange = { ( _ , h ) => {
133
- setLayout ( ( l ) => ( { ...l , paragraphHeight : h } ) ) ;
134
- } }
135
- contentContainerStyle = { { flexGrow : 1 } }
136
- height = { layout . questionY - layout . containerY }
137
- scrollEnabled = { layout . paragraphHeight > layout . questionY }
138
- >
139
- < QuestionContent question = { question } />
140
- </ ScrollView >
141
- </ View >
142
- </ AnimatePresence >
143
- < XStack gap = "$2" flexWrap = "wrap" >
144
- { question ?. answers . map ( ( answerText , idx ) => (
145
- < AnswerButton
146
- key = { idx }
147
- answerText = { answerText }
148
- isCorrect = { idx === question ! . correctAnswer }
149
- selected = { answer === null ? answer : idx === answer }
150
- onPress = { ( ) => handleAnswer ( idx ) }
151
- />
152
- ) ) }
153
- </ XStack >
154
- < XStack
155
- justifyContent = "space-between"
156
- width = "100%"
157
- marginTop = "$-2"
158
- gap = "$2"
159
- pointerEvents = { answer !== null ? "auto" : "none" }
160
- opacity = { answer !== null ? 1 : 0 }
161
- animation = "medium"
162
- theme = "alt2"
76
+ < AnimatePresence >
77
+ < View
78
+ position = "absolute"
79
+ top = { 0 }
80
+ left = { 0 }
81
+ right = { 0 }
82
+ bottom = { 0 }
83
+ animation = "fast"
84
+ key = { question ?. question . toString ( ) }
85
+ exitStyle = { { transform : [ { translateX : 200 } ] , opacity : 0 } }
86
+ enterStyle = { { transform : [ { translateX : - 200 } ] , opacity : 0 } }
87
+ transform = { [ { translateX : 0 } ] }
163
88
>
164
- < Button
165
- circular
166
- icon = { BookOpen }
167
- onPress = { ( ) => {
168
- WebBrowser . openBrowserAsync (
169
- `https://jisho.org/search/${ encodeURIComponent (
170
- ( question ?. question || "" ) + ( question ?. answers . join ( " " ) || "" )
171
- ) } `
172
- ) ;
173
- } }
174
- />
175
- < Button
176
- circular
177
- icon = { Search }
178
- onPress = { ( ) => {
179
- WebBrowser . openBrowserAsync (
180
- `https://www.google.com/search?q=${ encodeURIComponent (
181
- ( question ?. answers [ question . correctAnswer ] || "" ) + " 文法"
182
- ) } `
183
- ) ;
184
- } }
89
+ < QuestionView
90
+ question = { question }
91
+ answer = { answer }
92
+ handleAnswer = { handleAnswer }
185
93
/>
186
- </ XStack >
187
- < View marginBottom = "40%" />
188
- </ YStack >
94
+ </ View >
95
+ </ AnimatePresence >
189
96
) ;
190
97
}
98
+
99
+ export default function TabOneScreen ( ) {
100
+ return < QuestionManager /> ;
101
+ }
0 commit comments