Use react-native-paper snackbar instead of ToastAndroid
This commit is contained in:
parent
c54396cb9c
commit
2c9242b03f
24
App.tsx
24
App.tsx
|
@ -10,6 +10,7 @@ import {
|
||||||
DarkTheme as PaperDarkTheme,
|
DarkTheme as PaperDarkTheme,
|
||||||
DefaultTheme as PaperDefaultTheme,
|
DefaultTheme as PaperDefaultTheme,
|
||||||
Provider,
|
Provider,
|
||||||
|
Snackbar,
|
||||||
} from 'react-native-paper';
|
} from 'react-native-paper';
|
||||||
import {SQLiteDatabase} from 'react-native-sqlite-storage';
|
import {SQLiteDatabase} from 'react-native-sqlite-storage';
|
||||||
import Ionicon from 'react-native-vector-icons/Ionicons';
|
import Ionicon from 'react-native-vector-icons/Ionicons';
|
||||||
|
@ -25,6 +26,9 @@ export type DrawerParamList = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DatabaseContext = React.createContext<SQLiteDatabase>({} as any);
|
export const DatabaseContext = React.createContext<SQLiteDatabase>({} as any);
|
||||||
|
export const SnackbarContext = React.createContext<{
|
||||||
|
toast: (value: string, timeout: number) => void;
|
||||||
|
}>({toast: () => null});
|
||||||
|
|
||||||
const CombinedDefaultTheme = {
|
const CombinedDefaultTheme = {
|
||||||
...PaperDefaultTheme,
|
...PaperDefaultTheme,
|
||||||
|
@ -45,6 +49,7 @@ const CombinedDarkTheme = {
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [db, setDb] = useState<SQLiteDatabase | null>(null);
|
const [db, setDb] = useState<SQLiteDatabase | null>(null);
|
||||||
|
const [snackbar, setSnackbar] = useState('');
|
||||||
const dark = useColorScheme() === 'dark';
|
const dark = useColorScheme() === 'dark';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -64,6 +69,11 @@ const App = () => {
|
||||||
init();
|
init();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const toast = (value: string, timeout: number) => {
|
||||||
|
setSnackbar(value);
|
||||||
|
setTimeout(() => setSnackbar(''), timeout);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Provider
|
<Provider
|
||||||
theme={dark ? CombinedDarkTheme : CombinedDefaultTheme}
|
theme={dark ? CombinedDarkTheme : CombinedDefaultTheme}
|
||||||
|
@ -71,8 +81,22 @@ const App = () => {
|
||||||
<NavigationContainer
|
<NavigationContainer
|
||||||
theme={dark ? CombinedDarkTheme : CombinedDefaultTheme}>
|
theme={dark ? CombinedDarkTheme : CombinedDefaultTheme}>
|
||||||
<StatusBar barStyle={dark ? 'light-content' : 'dark-content'} />
|
<StatusBar barStyle={dark ? 'light-content' : 'dark-content'} />
|
||||||
|
<SnackbarContext.Provider value={{toast}}>
|
||||||
<Routes db={db} />
|
<Routes db={db} />
|
||||||
|
</SnackbarContext.Provider>
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
|
<Snackbar
|
||||||
|
onDismiss={() => setSnackbar('')}
|
||||||
|
visible={!!snackbar}
|
||||||
|
action={{
|
||||||
|
label: 'Close',
|
||||||
|
onPress: () => setSnackbar(''),
|
||||||
|
color: dark
|
||||||
|
? CombinedDarkTheme.colors.primary
|
||||||
|
: CombinedDefaultTheme.colors.primary,
|
||||||
|
}}>
|
||||||
|
{snackbar}
|
||||||
|
</Snackbar>
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import {NavigationProp, useNavigation} from '@react-navigation/native';
|
import {NavigationProp, useNavigation} from '@react-navigation/native';
|
||||||
import React, {useCallback, useContext, useState} from 'react';
|
import React, {useCallback, useContext, useState} from 'react';
|
||||||
import {ToastAndroid} from 'react-native';
|
|
||||||
import DocumentPicker from 'react-native-document-picker';
|
import DocumentPicker from 'react-native-document-picker';
|
||||||
import {FileSystem} from 'react-native-file-access';
|
import {FileSystem} from 'react-native-file-access';
|
||||||
import {Divider, IconButton, Menu} from 'react-native-paper';
|
import {Divider, IconButton, Menu} from 'react-native-paper';
|
||||||
import {DatabaseContext, DrawerParamList} from './App';
|
import {DatabaseContext, DrawerParamList, SnackbarContext} from './App';
|
||||||
import ConfirmDialog from './ConfirmDialog';
|
import ConfirmDialog from './ConfirmDialog';
|
||||||
import {write} from './file';
|
import {useWrite} from './file';
|
||||||
import {Plan} from './plan';
|
import {Plan} from './plan';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
|
|
||||||
|
@ -17,7 +16,9 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const [showRemove, setShowRemove] = useState(false);
|
const [showRemove, setShowRemove] = useState(false);
|
||||||
const db = useContext(DatabaseContext);
|
const db = useContext(DatabaseContext);
|
||||||
|
const {toast} = useContext(SnackbarContext);
|
||||||
const {reset} = useNavigation<NavigationProp<DrawerParamList>>();
|
const {reset} = useNavigation<NavigationProp<DrawerParamList>>();
|
||||||
|
const {write} = useWrite();
|
||||||
|
|
||||||
const exportSets = useCallback(async () => {
|
const exportSets = useCallback(async () => {
|
||||||
const [result] = await db.executeSql('SELECT * FROM sets');
|
const [result] = await db.executeSql('SELECT * FROM sets');
|
||||||
|
@ -33,7 +34,7 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
|
||||||
.join('\n');
|
.join('\n');
|
||||||
console.log(`${DrawerMenu.name}.exportSets`, {length: sets.length});
|
console.log(`${DrawerMenu.name}.exportSets`, {length: sets.length});
|
||||||
await write('sets.csv', data);
|
await write('sets.csv', data);
|
||||||
}, [db]);
|
}, [db, write]);
|
||||||
|
|
||||||
const exportPlans = useCallback(async () => {
|
const exportPlans = useCallback(async () => {
|
||||||
const [result] = await db.executeSql('SELECT * FROM plans');
|
const [result] = await db.executeSql('SELECT * FROM plans');
|
||||||
|
@ -44,7 +45,7 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
|
||||||
.join('\n');
|
.join('\n');
|
||||||
console.log(`${DrawerMenu.name}.exportPlans`, {length: sets.length});
|
console.log(`${DrawerMenu.name}.exportPlans`, {length: sets.length});
|
||||||
await write('plans.csv', data);
|
await write('plans.csv', data);
|
||||||
}, [db]);
|
}, [db, write]);
|
||||||
|
|
||||||
const download = useCallback(async () => {
|
const download = useCallback(async () => {
|
||||||
setShowMenu(false);
|
setShowMenu(false);
|
||||||
|
@ -57,8 +58,7 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
|
||||||
const file = await FileSystem.readFile(result.uri);
|
const file = await FileSystem.readFile(result.uri);
|
||||||
console.log(`${DrawerMenu.name}.${uploadSets.name}:`, file.length);
|
console.log(`${DrawerMenu.name}.${uploadSets.name}:`, file.length);
|
||||||
const lines = file.split('\n');
|
const lines = file.split('\n');
|
||||||
if (lines[0] != setFields)
|
if (lines[0] != setFields) return toast('Invalid csv.', 3000);
|
||||||
return ToastAndroid.show('Invalid csv.', ToastAndroid.SHORT);
|
|
||||||
const values = lines
|
const values = lines
|
||||||
.slice(1)
|
.slice(1)
|
||||||
.filter(line => line)
|
.filter(line => line)
|
||||||
|
@ -70,17 +70,16 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
|
||||||
await db.executeSql(
|
await db.executeSql(
|
||||||
`INSERT INTO sets(name,reps,weight,created,unit) VALUES ${values}`,
|
`INSERT INTO sets(name,reps,weight,created,unit) VALUES ${values}`,
|
||||||
);
|
);
|
||||||
ToastAndroid.show('Data imported.', ToastAndroid.SHORT);
|
toast('Data imported.', 3000);
|
||||||
reset({index: 0, routes: [{name}]});
|
reset({index: 0, routes: [{name}]});
|
||||||
}, [db, reset, name]);
|
}, [db, reset, name, toast]);
|
||||||
|
|
||||||
const uploadPlans = useCallback(async () => {
|
const uploadPlans = useCallback(async () => {
|
||||||
const result = await DocumentPicker.pickSingle();
|
const result = await DocumentPicker.pickSingle();
|
||||||
const file = await FileSystem.readFile(result.uri);
|
const file = await FileSystem.readFile(result.uri);
|
||||||
console.log(`${DrawerMenu.name}.uploadPlans:`, file.length);
|
console.log(`${DrawerMenu.name}.uploadPlans:`, file.length);
|
||||||
const lines = file.split('\n');
|
const lines = file.split('\n');
|
||||||
if (lines[0] != planFields)
|
if (lines[0] != planFields) return toast('Invalid csv.', 3000);
|
||||||
return ToastAndroid.show('Invalid csv.', ToastAndroid.SHORT);
|
|
||||||
const values = file
|
const values = file
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.slice(1)
|
.slice(1)
|
||||||
|
@ -91,8 +90,8 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
|
||||||
})
|
})
|
||||||
.join(',');
|
.join(',');
|
||||||
await db.executeSql(`INSERT INTO plans(days,workouts) VALUES ${values}`);
|
await db.executeSql(`INSERT INTO plans(days,workouts) VALUES ${values}`);
|
||||||
ToastAndroid.show('Data imported.', ToastAndroid.SHORT);
|
toast('Data imported.', 3000);
|
||||||
}, [db]);
|
}, [db, toast]);
|
||||||
|
|
||||||
const upload = useCallback(async () => {
|
const upload = useCallback(async () => {
|
||||||
setShowMenu(false);
|
setShowMenu(false);
|
||||||
|
@ -106,9 +105,9 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
|
||||||
setShowRemove(false);
|
setShowRemove(false);
|
||||||
if (name === 'Home') await db.executeSql(`DELETE FROM sets`);
|
if (name === 'Home') await db.executeSql(`DELETE FROM sets`);
|
||||||
else if (name === 'Plans') await db.executeSql(`DELETE FROM plans`);
|
else if (name === 'Plans') await db.executeSql(`DELETE FROM plans`);
|
||||||
ToastAndroid.show('All data has been deleted.', ToastAndroid.SHORT);
|
toast('All data has been deleted.', 4000);
|
||||||
reset({index: 0, routes: [{name}]});
|
reset({index: 0, routes: [{name}]});
|
||||||
}, [db, reset, name]);
|
}, [db, reset, name, toast]);
|
||||||
|
|
||||||
if (name === 'Home' || name === 'Plans')
|
if (name === 'Home' || name === 'Plans')
|
||||||
return (
|
return (
|
||||||
|
|
10
EditSet.tsx
10
EditSet.tsx
|
@ -5,9 +5,9 @@ import {
|
||||||
useRoute,
|
useRoute,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import React, {useCallback, useContext} from 'react';
|
import React, {useCallback, useContext} from 'react';
|
||||||
import {NativeModules, ToastAndroid, View} from 'react-native';
|
import {NativeModules, View} from 'react-native';
|
||||||
import {IconButton} from 'react-native-paper';
|
import {IconButton} from 'react-native-paper';
|
||||||
import {DatabaseContext} from './App';
|
import {DatabaseContext, SnackbarContext} from './App';
|
||||||
import {HomePageParams} from './HomePage';
|
import {HomePageParams} from './HomePage';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import SetForm from './SetForm';
|
import SetForm from './SetForm';
|
||||||
|
@ -17,6 +17,7 @@ export default function EditSet() {
|
||||||
const {params} = useRoute<RouteProp<HomePageParams, 'EditSet'>>();
|
const {params} = useRoute<RouteProp<HomePageParams, 'EditSet'>>();
|
||||||
const db = useContext(DatabaseContext);
|
const db = useContext(DatabaseContext);
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
|
const {toast} = useContext(SnackbarContext);
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
|
@ -24,6 +25,7 @@ export default function EditSet() {
|
||||||
headerLeft: () => (
|
headerLeft: () => (
|
||||||
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
||||||
),
|
),
|
||||||
|
headerRight: null,
|
||||||
title: 'Set',
|
title: 'Set',
|
||||||
});
|
});
|
||||||
}, [navigation]),
|
}, [navigation]),
|
||||||
|
@ -62,10 +64,10 @@ export default function EditSet() {
|
||||||
weight > params.set.weight ||
|
weight > params.set.weight ||
|
||||||
(reps > params.set.reps && weight === params.set.weight)
|
(reps > params.set.reps && weight === params.set.weight)
|
||||||
)
|
)
|
||||||
ToastAndroid.show("Great work King, that's a new record!", 6000);
|
toast("Great work King, that's a new record!", 6000);
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
},
|
},
|
||||||
[db, navigation, startTimer, params.set],
|
[db, navigation, startTimer, params.set, toast],
|
||||||
);
|
);
|
||||||
|
|
||||||
const save = useCallback(
|
const save = useCallback(
|
||||||
|
|
|
@ -7,6 +7,7 @@ import React, {useCallback, useContext, useEffect, useState} from 'react';
|
||||||
import {FlatList, StyleSheet, View} from 'react-native';
|
import {FlatList, StyleSheet, View} from 'react-native';
|
||||||
import {List, Searchbar} from 'react-native-paper';
|
import {List, Searchbar} from 'react-native-paper';
|
||||||
import {DatabaseContext} from './App';
|
import {DatabaseContext} from './App';
|
||||||
|
import DrawerMenu from './DrawerMenu';
|
||||||
import {HomePageParams} from './HomePage';
|
import {HomePageParams} from './HomePage';
|
||||||
import MassiveFab from './MassiveFab';
|
import MassiveFab from './MassiveFab';
|
||||||
import {Plan} from './plan';
|
import {Plan} from './plan';
|
||||||
|
@ -132,7 +133,10 @@ export default function SetList() {
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
refresh();
|
refresh();
|
||||||
predict();
|
predict();
|
||||||
}, [refresh, predict]),
|
navigation.getParent()?.setOptions({
|
||||||
|
headerRight: () => <DrawerMenu name="Home" />,
|
||||||
|
});
|
||||||
|
}, [refresh, predict, navigation]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderItem = useCallback(
|
const renderItem = useCallback(
|
||||||
|
|
|
@ -5,15 +5,9 @@ import React, {
|
||||||
useEffect,
|
useEffect,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import {
|
import {NativeModules, StyleSheet, Text, View} from 'react-native';
|
||||||
NativeModules,
|
|
||||||
StyleSheet,
|
|
||||||
Text,
|
|
||||||
ToastAndroid,
|
|
||||||
View,
|
|
||||||
} from 'react-native';
|
|
||||||
import {Searchbar, TextInput} from 'react-native-paper';
|
import {Searchbar, TextInput} from 'react-native-paper';
|
||||||
import {DatabaseContext} from './App';
|
import {DatabaseContext, SnackbarContext} from './App';
|
||||||
import ConfirmDialog from './ConfirmDialog';
|
import ConfirmDialog from './ConfirmDialog';
|
||||||
import MassiveSwitch from './MassiveSwitch';
|
import MassiveSwitch from './MassiveSwitch';
|
||||||
import Settings from './settings';
|
import Settings from './settings';
|
||||||
|
@ -29,6 +23,7 @@ export default function SettingsPage() {
|
||||||
const [ignoring, setIgnoring] = useState(false);
|
const [ignoring, setIgnoring] = useState(false);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const db = useContext(DatabaseContext);
|
const db = useContext(DatabaseContext);
|
||||||
|
const {toast} = useContext(SnackbarContext);
|
||||||
|
|
||||||
const refresh = useCallback(async () => {
|
const refresh = useCallback(async () => {
|
||||||
const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`);
|
const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`);
|
||||||
|
@ -65,12 +60,9 @@ export default function SettingsPage() {
|
||||||
const changePredictive = useCallback(
|
const changePredictive = useCallback(
|
||||||
(enabled: boolean) => {
|
(enabled: boolean) => {
|
||||||
setPredictive(enabled);
|
setPredictive(enabled);
|
||||||
ToastAndroid.show(
|
toast('Predictive sets guess whats next based on todays plan.', 7000);
|
||||||
'Predictive sets guess whats next based on todays plan.',
|
|
||||||
ToastAndroid.LONG,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
[setPredictive],
|
[setPredictive, toast],
|
||||||
);
|
);
|
||||||
|
|
||||||
const changeVibrate = useCallback(
|
const changeVibrate = useCallback(
|
||||||
|
|
14
file.ts
14
file.ts
|
@ -1,7 +1,13 @@
|
||||||
import {PermissionsAndroid, ToastAndroid} from 'react-native';
|
import {useContext} from 'react';
|
||||||
|
import {PermissionsAndroid} from 'react-native';
|
||||||
import {Dirs, FileSystem} from 'react-native-file-access';
|
import {Dirs, FileSystem} from 'react-native-file-access';
|
||||||
|
import {SnackbarContext} from './App';
|
||||||
|
|
||||||
export const write = async (name: string, data: string) => {
|
export const useWrite = () => {
|
||||||
|
const {toast} = useContext(SnackbarContext);
|
||||||
|
|
||||||
|
return {
|
||||||
|
write: async (name: string, data: string) => {
|
||||||
const filePath = `${Dirs.DocumentDir}/${name}`;
|
const filePath = `${Dirs.DocumentDir}/${name}`;
|
||||||
const permission = async () => {
|
const permission = async () => {
|
||||||
const granted = await PermissionsAndroid.request(
|
const granted = await PermissionsAndroid.request(
|
||||||
|
@ -14,5 +20,7 @@ export const write = async (name: string, data: string) => {
|
||||||
await FileSystem.writeFile(filePath, data);
|
await FileSystem.writeFile(filePath, data);
|
||||||
if (!FileSystem.exists(filePath)) return;
|
if (!FileSystem.exists(filePath)) return;
|
||||||
await FileSystem.cpExternal(filePath, name, 'downloads');
|
await FileSystem.cpExternal(filePath, name, 'downloads');
|
||||||
ToastAndroid.show(`Saved "${name}". Check downloads`, ToastAndroid.LONG);
|
toast(`Saved "${name}" in your downloads folder.`, 6000);
|
||||||
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user