Skip to content

Commit 3ed25c5

Browse files
committed
WIP: integrating React Navigation to replace use of Modals
1 parent 529d688 commit 3ed25c5

File tree

7 files changed

+84
-83
lines changed

7 files changed

+84
-83
lines changed

index.macos.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { AppRegistry } from "react-native";
2+
import { App } from "./src/App";
3+
import { name as appName } from "./app.json";
4+
5+
AppRegistry.registerComponent(appName, () => App);

src/App.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
* https://github.com/blefebvre/react-native-sqlite-demo/blob/master/LICENSE
55
*/
66
import React, { useState, useEffect } from "react";
7-
import { AppState, StyleSheet, SafeAreaView, AppStateStatus } from "react-native";
7+
import { AppState, StyleSheet, AppStateStatus } from "react-native";
88
import { NavigationContainer } from "@react-navigation/native";
99
import { createStackNavigator } from "@react-navigation/stack";
1010

11-
import { AllLists } from "./components/AllLists";
1211
import { LoadingScreen } from "./components/LoadingScreen";
1312
import { useDatabaseSync } from "./hooks/useDatabaseSync";
14-
import { DatabaseProvider } from "./context/DatabaseContext";
1513
import { HomeScreen } from "./components/HomeScreen";
14+
import { SettingsScreen } from "./components/SettingsScreen";
15+
import { ListDetailsScreen } from "./components/ListDetailsScreen";
1616

1717
// Track the current state of the app as a regular variable (instead of in state), since
1818
// we do not want to re-render when this value changes.
@@ -76,7 +76,9 @@ export const App: React.FunctionComponent = function() {
7676
return (
7777
<NavigationContainer>
7878
<Stack.Navigator>
79-
<Stack.Screen name="Home" component={HomeScreen} />
79+
<Stack.Screen name="SQLite List App" component={HomeScreen} />
80+
<Stack.Screen name="Settings" component={SettingsScreen} />
81+
<Stack.Screen name="List Details" component={ListDetailsScreen} />
8082
</Stack.Navigator>
8183
</NavigationContainer>
8284
);

src/components/AllLists.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import { NewItem } from "./NewItem";
1010
import { Header } from "./Header";
1111
import { List } from "../types/List";
1212
import { ListRow } from "./ListRow";
13-
import { ViewListModal } from "./ViewListModal";
14-
import { SettingsModal } from "./SettingsModal";
13+
import { ListDetailsScreen } from "./ListDetailsScreen";
1514
import { useLists } from "../hooks/useLists";
1615

1716
// Main page of the app. This component renders:
@@ -20,8 +19,6 @@ import { useLists } from "../hooks/useLists";
2019
// - and a list of all the Lists saved locally in the app's database
2120
export const AllLists: React.FunctionComponent = function() {
2221
const [newListTitle, setNewListTitle] = useState("");
23-
const [isListModalVisible, setIsListModalVisible] = useState(false);
24-
const [isSettingsModalVisible, setIsSettingsModalVisible] = useState(false);
2522

2623
// Use the useLists hook to simplify list management.
2724
const { lists, selectList, selectedList, createList, deleteList } = useLists();
@@ -30,13 +27,17 @@ export const AllLists: React.FunctionComponent = function() {
3027
console.log(`List clicked! Title: ${list.title}`);
3128
await selectList(list);
3229
// Open a modal dialog to view and manage the items of a single list
33-
setIsListModalVisible(true);
30+
//setIsListModalVisible(true);
3431
}
3532

3633
return (
3734
<View style={styles.container} testID="allListsView">
3835
<View style={styles.headerWithSettings}>
39-
<TouchableOpacity style={styles.settingsButton} onPress={() => setIsSettingsModalVisible(true)}>
36+
<TouchableOpacity
37+
style={styles.settingsButton}
38+
onPress={() => {
39+
/* setIsSettingsModalVisible(true) */
40+
}}>
4041
<Text style={styles.settingsButtonText}>⚙️</Text>
4142
</TouchableOpacity>
4243
<Header title="SQLite List App - with Hooks" />
@@ -59,15 +60,14 @@ export const AllLists: React.FunctionComponent = function() {
5960
/>
6061

6162
{selectedList !== undefined && (
62-
<ViewListModal
63-
visible={isListModalVisible}
63+
<ListDetailsScreen
6464
list={selectedList}
65-
back={() => setIsListModalVisible(false)}
65+
back={() => {
66+
/* setIsListModalVisible(false) */
67+
}}
6668
deleteList={deleteList}
6769
/>
6870
)}
69-
70-
<SettingsModal visible={isSettingsModalVisible} back={() => setIsSettingsModalVisible(false)} />
7171
</View>
7272
);
7373
};

src/components/ViewListModal.tsx renamed to src/components/ListDetailsScreen.tsx

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* https://github.com/blefebvre/react-native-sqlite-demo/blob/master/LICENSE
55
*/
66
import React, { useState } from "react";
7-
import { View, StyleSheet, Modal, Text, SafeAreaView, TouchableOpacity, FlatList, Alert } from "react-native";
7+
import { View, StyleSheet, Text, SafeAreaView, TouchableOpacity, FlatList, Alert } from "react-native";
88
import { Header } from "./Header";
99
import { List } from "../types/List";
1010
import { NewItem } from "./NewItem";
@@ -14,15 +14,14 @@ import { sharedStyle } from "../style/Shared";
1414
import { useListItems } from "../hooks/useListItems";
1515

1616
interface Props {
17-
visible: boolean;
1817
list: List;
1918
back(): void;
2019
deleteList(list: List): Promise<void>;
2120
}
2221

2322
// Modal dialog to view and manage the items of a single list
24-
export const ViewListModal: React.FunctionComponent<Props> = function(props) {
25-
const { visible, list } = props;
23+
export const ListDetailsScreen: React.FunctionComponent<Props> = function(props) {
24+
const { list } = props;
2625
const [newItemText, setNewItemText] = useState("");
2726

2827
// Use the useListItems hook to manage list items, instead of using the DB object directly
@@ -61,36 +60,34 @@ export const ViewListModal: React.FunctionComponent<Props> = function(props) {
6160
}
6261

6362
return (
64-
<Modal animationType="slide" transparent={false} visible={visible} onRequestClose={() => props.back()}>
65-
<SafeAreaView style={styles.container} testID="viewListModal">
66-
<View style={sharedStyle.headerWithButton}>
67-
<Header title={`List: ${list.title}`} />
63+
<SafeAreaView style={styles.container} testID="viewListModal">
64+
<View style={sharedStyle.headerWithButton}>
65+
<Header title={`List: ${list.title}`} />
6866

69-
<TouchableOpacity style={sharedStyle.headerButton} onPress={() => props.back()}>
70-
<Text>✖️</Text>
71-
</TouchableOpacity>
72-
</View>
67+
<TouchableOpacity style={sharedStyle.headerButton} onPress={() => props.back()}>
68+
<Text>✖️</Text>
69+
</TouchableOpacity>
70+
</View>
7371

74-
<NewItem
75-
newItemName={newItemText}
76-
handleNameChange={(value) => setNewItemText(value)}
77-
handleCreateNewItem={handleAddNewItemToList}
78-
placeholderText="Enter a new list item"
79-
createButtonText="Add item"
80-
/>
72+
<NewItem
73+
newItemName={newItemText}
74+
handleNameChange={(value) => setNewItemText(value)}
75+
handleCreateNewItem={handleAddNewItemToList}
76+
placeholderText="Enter a new list item"
77+
createButtonText="Add item"
78+
/>
8179

82-
<FlatList
83-
data={selectedListsItems}
84-
renderItem={({ item }) => <ListItemRow listItem={item} handleListItemClicked={toggleListItemDoneness} />}
85-
keyExtractor={(_, index) => `item-${index}`}
86-
ListFooterComponent={
87-
<TouchableOpacity style={styles.deleteList} onPress={promptToDeleteList} testID="deleteListButton">
88-
<Text>Delete list</Text>
89-
</TouchableOpacity>
90-
}
91-
/>
92-
</SafeAreaView>
93-
</Modal>
80+
<FlatList
81+
data={selectedListsItems}
82+
renderItem={({ item }) => <ListItemRow listItem={item} handleListItemClicked={toggleListItemDoneness} />}
83+
keyExtractor={(_, index) => `item-${index}`}
84+
ListFooterComponent={
85+
<TouchableOpacity style={styles.deleteList} onPress={promptToDeleteList} testID="deleteListButton">
86+
<Text>Delete list</Text>
87+
</TouchableOpacity>
88+
}
89+
/>
90+
</SafeAreaView>
9491
);
9592
};
9693

src/components/ListRow.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const ListRow: React.FunctionComponent<Props> = function(props) {
1616
const { list, handleListClicked } = props;
1717
return (
1818
<TouchableOpacity onPress={() => handleListClicked(list)} style={styles.row} testID={`listButton:${list.title}`}>
19-
<Text>{list.title}</Text>
19+
<Text style={styles.text}>{list.title}</Text>
2020
</TouchableOpacity>
2121
);
2222
};
@@ -26,7 +26,7 @@ const styles = StyleSheet.create({
2626
borderWidth: 1,
2727
padding: 15,
2828
marginTop: 10,
29-
backgroundColor: "#EEE",
29+
backgroundColor: "#444",
3030
borderRadius: 3,
3131
shadowColor: "#000",
3232
shadowOffset: {
@@ -36,4 +36,7 @@ const styles = StyleSheet.create({
3636
shadowOpacity: 0.25,
3737
shadowRadius: 3,
3838
},
39+
text: {
40+
color: "#EEE",
41+
},
3942
});

src/components/SettingsModal.tsx renamed to src/components/SettingsScreen.tsx

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
* Copyright (c) 2018-2020 Bruce Lefebvre <[email protected]>
44
* https://github.com/blefebvre/react-native-sqlite-demo/blob/master/LICENSE
55
*/
6-
import React, { useState } from "react";
7-
import { View, StyleSheet, Modal, Text, SafeAreaView, TouchableOpacity, Alert } from "react-native";
6+
import React, { useEffect, useState } from "react";
7+
import { View, StyleSheet, Text, SafeAreaView, TouchableOpacity, Alert } from "react-native";
88
import RNRestart from "react-native-restart";
99
import { Header } from "./Header";
1010
import { sharedStyle } from "../style/Shared";
@@ -13,20 +13,28 @@ import { DropboxDatabaseSync } from "../sync/dropbox/DropboxDatabaseSync";
1313
import { LoadingScreen } from "./LoadingScreen";
1414

1515
interface Props {
16-
visible: boolean;
1716
back(): void;
1817
}
1918

2019
const dropboxAuth: DropboxAuthorize = new DropboxAuthorize();
2120
const dropboxSync: DropboxDatabaseSync = new DropboxDatabaseSync();
2221

23-
export const SettingsModal: React.FunctionComponent<Props> = function(props) {
24-
const { visible } = props;
22+
export const SettingsScreen: React.FunctionComponent<Props> = function(props) {
2523
// Initialize state
2624
const [isDropboxStatusKnown, setIsDropboxStatusKnown] = useState(false);
2725
const [hasAuthorizedWithDropbox, setHasAuthorizedWithDropbox] = useState(false);
2826
const [isDownloading, setIsDownloading] = useState(false);
2927

28+
useEffect(() => {
29+
async function checkIfAuthorizedWithDropbox() {
30+
// Check if this user has already authorized with Dropbox
31+
const isAuthorized = await dropboxAuth.hasUserAuthorized();
32+
setIsDropboxStatusKnown(true);
33+
setHasAuthorizedWithDropbox(isAuthorized);
34+
}
35+
checkIfAuthorizedWithDropbox();
36+
}, []); // [] = effect has no dependencies, so run this code only on component mount
37+
3038
function renderDropboxComponents() {
3139
if (hasAuthorizedWithDropbox) {
3240
return (
@@ -129,36 +137,20 @@ export const SettingsModal: React.FunctionComponent<Props> = function(props) {
129137
setHasAuthorizedWithDropbox(false);
130138
}
131139

132-
async function modalOnShow() {
133-
// Check if this user has already authorized with Dropbox
134-
const isAuthorized = await dropboxAuth.hasUserAuthorized();
135-
setIsDropboxStatusKnown(true);
136-
setHasAuthorizedWithDropbox(isAuthorized);
137-
}
138-
139-
return (
140-
<Modal
141-
animationType="slide"
142-
transparent={false}
143-
visible={visible}
144-
onRequestClose={() => props.back()}
145-
onShow={modalOnShow}>
146-
{isDownloading ? (
147-
<LoadingScreen text="Downloading database..." />
148-
) : (
149-
<SafeAreaView style={styles.container} testID="settingsModal">
150-
<View style={sharedStyle.headerWithButton}>
151-
<Header title={`Settings`} />
140+
return isDownloading ? (
141+
<LoadingScreen text="Downloading database..." />
142+
) : (
143+
<SafeAreaView style={styles.container} testID="settingsModal">
144+
<View style={sharedStyle.headerWithButton}>
145+
<Header title={`Settings`} />
152146

153-
<TouchableOpacity style={sharedStyle.headerButton} onPress={() => props.back()}>
154-
<Text>✖️</Text>
155-
</TouchableOpacity>
156-
</View>
147+
<TouchableOpacity style={sharedStyle.headerButton} onPress={() => props.back()}>
148+
<Text>✖️</Text>
149+
</TouchableOpacity>
150+
</View>
157151

158-
{isDropboxStatusKnown && renderDropboxComponents()}
159-
</SafeAreaView>
160-
)}
161-
</Modal>
152+
{isDropboxStatusKnown && renderDropboxComponents()}
153+
</SafeAreaView>
162154
);
163155
};
164156

src/sync/dropbox/DropboxDatabaseSync.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ export class DropboxDatabaseSync implements DatabaseSync {
166166

167167
console.log("[Dropbox backup] DOWNLOADING and applying DB from Dropbox: beginning.");
168168

169+
//console.log("RNFetchBlob", RNFetchBlob);
170+
169171
// Download the backup file, replacing the existing database
170172
/*return RNFetchBlob.config({
171173
// DB data will be saved to this path
@@ -339,8 +341,8 @@ export class DropboxDatabaseSync implements DatabaseSync {
339341
}
340342

341343
private getLocalDBFilePath(): string {
342-
return "xxxxx";
343-
//return RNFS.LibraryDirectoryPath + "/LocalDatabase/" + this.getDatabaseName();
344+
//return "xxxxx";
345+
return RNFS.LibraryDirectoryPath + "/LocalDatabase/" + this.getDatabaseName();
344346
}
345347

346348
private getLocalDBBackupFilePath(): string {

0 commit comments

Comments
 (0)