1- import { StatusBar } from 'expo-status-bar' ;
2- import { StyleSheet , Text , View } from 'react-native' ;
1+ import "expo-dev-client" ;
2+ import { useEffect , useState } from "react" ;
3+ import {
4+ FlatList ,
5+ StyleSheet ,
6+ Text ,
7+ View ,
8+ } from "react-native" ;
9+ import * as SplashScreen from "expo-splash-screen" ;
10+ import { GestureHandlerRootView } from "react-native-gesture-handler" ;
11+
12+ import Button from "./components/button" ;
13+ import color from "./constants/colors" ;
14+ import Task from "./ui/task" ;
15+ import CreateTask from "./ui/createTask" ;
16+ import NoTasks from "./ui/NoTasks" ;
17+
18+ // Anyone knows how to cut down on these imports?
19+ // Oh wait, it's just me here, alone...
20+
21+ import { ExpoDevMenuItem , registerDevMenuItems } from "expo-dev-menu" ;
22+ import AsyncStorage , { useAsyncStorage } from "@react-native-async-storage/async-storage" ;
23+ import { useAsyncStorageDevTools } from "@dev-plugins/async-storage" ;
24+
25+ // SplashScreen.preventAutoHideAsync();
26+
27+ SplashScreen . setOptions ( {
28+ fade : true ,
29+ duration : 250 ,
30+ } ) ;
31+
32+ export type TaskItem = {
33+ title : string ;
34+ completed : boolean ;
35+ subTasks ?: {
36+ title : string ;
37+ completed : boolean ;
38+ } [ ]
39+ }
340
441export default function App ( ) {
5- return (
6- < View style = { styles . container } >
7- < Text > Open up App.tsx to start working on your app!</ Text >
8- < StatusBar style = "auto" />
9- </ View >
10- ) ;
42+ useAsyncStorageDevTools ( { errorHandler : ( e ) => { console . log ( "[App.js] -> Error:" , e ) } } ) ;
43+
44+ const { getItem, removeItem, setItem } = useAsyncStorage ( "tasks" ) ;
45+
46+ const [ tasks , setTasks ] = useState < TaskItem [ ] | undefined > ( undefined ) ;
47+ const [ taskToEdit , setTaskToEdit ] = useState < number | undefined > ( ) ;
48+ const [ creationModalVisible , setCreationModalVisible ] = useState ( false ) ;
49+
50+ async function fetchTasks ( ) {
51+ await getItem ( ) . then ( ( e ) => {
52+ if ( e !== null ) {
53+ setTasks ( JSON . parse ( e ) ) ;
54+ }
55+ } ) . catch ( ( err ) => console . log ( "[App.tsx] -> Something went wrong: " , err ) )
56+ }
57+
58+ async function saveTasks ( ) {
59+ await setItem ( JSON . stringify ( tasks ) ) . then ( ( v ) => console . log ( "[App.tsx] -> Saved successfully: " , tasks ) )
60+ }
61+
62+ function createTask ( t : TaskItem ) {
63+ setTasks ( ( ) => tasks ? [ ...tasks , t ] : [ t ] ) ;
64+ }
65+
66+ function updateTask ( id : number , replacement : TaskItem ) {
67+ setTasks ( prevTasks => prevTasks ?. map ( ( prev , idx ) => id === idx ? replacement : prev ) )
68+ }
69+
70+ function deleteTask ( id : number ) {
71+ setTasks ( prevTasks => prevTasks ?. filter ( ( _ , idx ) => id !== idx ) ) ;
72+ }
73+
74+ useEffect ( ( ) => {
75+ fetchTasks ( ) ;
76+ } , [ ] )
77+
78+ useEffect ( ( ) => {
79+ const devMenuItems : ExpoDevMenuItem [ ] = [
80+ {
81+ name : "Clear tasks" ,
82+ callback : ( ) => {
83+ removeItem ( ) . then ( ( ) => console . log ( "Wiped local store successfully" ) ) ;
84+ setTasks ( undefined )
85+ } ,
86+ shouldCollapse : true ,
87+ } ,
88+ {
89+ name : "Dump locally stored task list in logs" ,
90+ callback : ( ) => {
91+ AsyncStorage . getItem ( "tasks" ) . then ( ( e ) => console . log ( e && JSON . parse ( e ) ) )
92+ } ,
93+ shouldCollapse : false ,
94+ } , {
95+ name : "Dump state stored task list in logs" ,
96+ callback : ( ) => {
97+ console . log ( tasks ) ;
98+ } ,
99+ shouldCollapse : false ,
100+ } ,
101+ {
102+ name : "Generate 25 random tasks" ,
103+ callback : ( ) => {
104+ for ( let i = 0 ; i <= 25 ; i ++ ) {
105+ setTasks ( ( ) => tasks ? [ ...tasks , {
106+ title : Math . random ( ) . toString ( ) ,
107+ completed : Math . random ( ) > 0.5 ? true : false ,
108+ } ] : [ {
109+ title : Math . random ( ) . toString ( ) ,
110+ completed : Math . random ( ) > 0.5 ? true : false ,
111+ } ] )
112+ }
113+ } ,
114+ shouldCollapse : true ,
115+ }
116+ ] ;
117+ registerDevMenuItems ( devMenuItems ) . then ( ( ) => console . log ( "Registered dev menu items successfully" ) ) ;
118+
119+ saveTasks ( ) ;
120+ } , [ tasks ] ) ;
121+
122+ const RI = ( { item, index } : { item : any ; index : number } ) => {
123+ return (
124+ < Task
125+ mainTask = { item }
126+ key = { index }
127+ index = { index }
128+ onPress = { ( ) => {
129+ setTaskToEdit ( index ) ;
130+ setCreationModalVisible ( true ) ;
131+ } }
132+ onDelete = { ( ) => {
133+ deleteTask ( index ) ;
134+ } }
135+ onCheck = { ( task ) => { updateTask ( index , task ) } }
136+ />
137+ ) ;
138+ } ;
139+
140+ // const onLayoutRootView = useCallback(() => {
141+ // if (loaded) {
142+ // SplashScreen.hide();
143+ // }
144+ // }, [loaded]);
145+
146+ // if (!loaded) {
147+ // return null;
148+ // }
149+
150+ return (
151+ < GestureHandlerRootView
152+ // onLayout={onLayoutRootView}
153+ style = { styles . container }
154+ >
155+ { /* this doohickey is to force the modal to rerender again so that the taskToEdit actually goes through */ }
156+
157+ { /* creationModalVisible */ }
158+ < CreateTask
159+ onRequestClose = { ( ) => {
160+ setCreationModalVisible ( false ) ;
161+ setTaskToEdit ( ( ) => undefined ) ;
162+ } }
163+ visibility = { creationModalVisible }
164+ onSubmitEditing = { ( i , newTask ) => {
165+ if ( i !== undefined ) {
166+ updateTask ( i , newTask ) ;
167+ } else {
168+ createTask ( newTask ) ;
169+ }
170+ setCreationModalVisible ( ( ) => false ) ;
171+ setTaskToEdit ( ( ) => undefined ) ;
172+ } }
173+ taskToEdit = { taskToEdit }
174+ tasks = { tasks }
175+ />
176+
177+ < View style = { { flexGrow : 1 } } >
178+ < FlatList
179+ contentContainerStyle = { { flexGrow : 1 } }
180+ data = { tasks }
181+ renderItem = { RI }
182+ keyExtractor = { ( _ , idx ) => idx . toString ( ) }
183+ ListEmptyComponent = { NoTasks }
184+ ListHeaderComponent = { ListHeader }
185+ ListHeaderComponentStyle = { { width : "100%" } }
186+ StickyHeaderComponent = { ListHeader }
187+ stickyHeaderHiddenOnScroll
188+ stickyHeaderIndices = { [ 0 ] }
189+ />
190+ </ View >
191+ < Button
192+ style = { {
193+ position : "absolute" ,
194+ bottom : 0 ,
195+ right : 0 ,
196+ margin : 50 ,
197+ } }
198+ onPress = { ( ) => {
199+ setCreationModalVisible ( true ) ;
200+ } }
201+ />
202+ </ GestureHandlerRootView >
203+ ) ;
11204}
12205
13206const styles = StyleSheet . create ( {
14- container : {
15- flex : 1 ,
16- backgroundColor : '#fff' ,
17- alignItems : 'center' ,
18- justifyContent : 'center' ,
19- } ,
207+ container : {
208+ flex : 1 ,
209+ width : "100%" ,
210+ alignItems : "center" ,
211+ justifyContent : "center" ,
212+ backgroundColor : color . pri ,
213+ } ,
20214} ) ;
215+
216+ function ListHeader ( ) {
217+ return (
218+ < View style = { { padding : 30 , experimental_backgroundImage : [ { type : "linearGradient" , colorStops : [ { color : color . sec } , { color : "transparent" } ] } ] } } >
219+ < Text style = { { color : color . font , fontSize : 30 , fontWeight : "100" } } > Tasks</ Text >
220+ </ View >
221+ )
222+ }
0 commit comments