Replace usage of react-native-async-storage with sqlite

This commit is contained in:
Brandon Presley 2022-08-24 12:01:39 +12:00
parent 37803ad0d4
commit 75b71b5851
6 changed files with 71 additions and 50 deletions

31
App.tsx
View File

@ -1,4 +1,3 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import {createDrawerNavigator} from '@react-navigation/drawer'; import {createDrawerNavigator} from '@react-navigation/drawer';
import { import {
DarkTheme as NavigationDarkTheme, DarkTheme as NavigationDarkTheme,
@ -14,7 +13,7 @@ import {
} 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';
import {createPlans, createSets, getDb} from './db'; import {createPlans, createSets, createSettings, getDb} from './db';
import Routes from './Routes'; import Routes from './Routes';
export const Drawer = createDrawerNavigator<DrawerParamList>(); export const Drawer = createDrawerNavigator<DrawerParamList>();
@ -27,8 +26,6 @@ export type DrawerParamList = {
export const DatabaseContext = React.createContext<SQLiteDatabase>({} as any); export const DatabaseContext = React.createContext<SQLiteDatabase>({} as any);
const {getItem, setItem} = AsyncStorage;
const CombinedDefaultTheme = { const CombinedDefaultTheme = {
...PaperDefaultTheme, ...PaperDefaultTheme,
...NavigationDefaultTheme, ...NavigationDefaultTheme,
@ -52,21 +49,17 @@ const App = () => {
useEffect(() => { useEffect(() => {
const init = async () => { const init = async () => {
const gotDb = await getDb(); const _db = await getDb();
await gotDb.executeSql(createPlans); await _db.executeSql(createPlans);
await gotDb.executeSql(createSets); await _db.executeSql(createSets);
setDb(gotDb); await _db.executeSql(createSettings);
const minutes = await getItem('minutes'); setDb(_db);
if (minutes === null) await setItem('minutes', '3'); const [result] = await _db.executeSql(`SELECT * FROM settings LIMIT 1`);
const seconds = await getItem('seconds'); if (result.rows.length === 0)
if (seconds === null) await setItem('seconds', '30'); return _db.executeSql(`
const alarmEnabled = await getItem('alarmEnabled'); INSERT INTO settings(minutes,seconds,alarm,vibrate,predict,sets)
if (alarmEnabled === null) await setItem('alarmEnabled', 'false'); VALUES(3,30,false,true,true,3);
const vibrate = await getItem('vibrate'); `);
if (vibrate === null) await setItem('vibrate', 'true');
if (!(await getItem('predictiveSets')))
await setItem('predictiveSets', 'true');
if (!(await getItem('maxSets'))) await setItem('maxSets', '3');
}; };
init(); init();
}, []); }, []);

View File

@ -1,4 +1,3 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { import {
RouteProp, RouteProp,
useFocusEffect, useFocusEffect,
@ -12,6 +11,7 @@ import {DatabaseContext} 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';
import Settings from './settings';
export default function EditSet() { export default function EditSet() {
const {params} = useRoute<RouteProp<HomePageParams, 'EditSet'>>(); const {params} = useRoute<RouteProp<HomePageParams, 'EditSet'>>();
@ -30,14 +30,12 @@ export default function EditSet() {
); );
const startTimer = useCallback(async () => { const startTimer = useCallback(async () => {
const enabled = await AsyncStorage.getItem('alarmEnabled'); const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`);
if (enabled !== 'true') return; const settings: Settings = result.rows.item(0);
const minutes = await AsyncStorage.getItem('minutes'); if (!settings.alarm) return;
const seconds = await AsyncStorage.getItem('seconds'); const milliseconds = settings.minutes * 60 * 1000 + settings.seconds * 1000;
const milliseconds = Number(minutes) * 60 * 1000 + Number(seconds) * 1000; NativeModules.AlarmModule.timer(milliseconds, !!settings.vibrate);
const vibrate = (await AsyncStorage.getItem('vibrate')) === 'true'; }, [db]);
NativeModules.AlarmModule.timer(milliseconds, vibrate);
}, []);
const update = useCallback( const update = useCallback(
async (set: Set) => { async (set: Set) => {

View File

@ -5,7 +5,6 @@ import {
} from '@react-navigation/native'; } from '@react-navigation/native';
import React, {useCallback, useContext, useEffect, useState} from 'react'; import React, {useCallback, useContext, useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native'; import {FlatList, StyleSheet, View} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {List, Searchbar} from 'react-native-paper'; import {List, Searchbar} from 'react-native-paper';
import {DatabaseContext} from './App'; import {DatabaseContext} from './App';
import {HomePageParams} from './HomePage'; import {HomePageParams} from './HomePage';
@ -13,6 +12,7 @@ import MassiveFab from './MassiveFab';
import {Plan} from './plan'; import {Plan} from './plan';
import Set from './set'; import Set from './set';
import SetItem from './SetItem'; import SetItem from './SetItem';
import Settings from './settings';
import {DAYS} from './time'; import {DAYS} from './time';
const limit = 15; const limit = 15;
@ -105,7 +105,9 @@ export default function SetList() {
); );
const predict = useCallback(async () => { const predict = useCallback(async () => {
if ((await AsyncStorage.getItem('predictiveSets')) === 'false') return; const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`);
const settings: Settings = result.rows.item(0);
if (!settings.predict) return;
const todaysPlan = await getTodaysPlan(); const todaysPlan = await getTodaysPlan();
if (todaysPlan.length === 0) return; if (todaysPlan.length === 0) return;
const todaysSets = await getTodaysSets(); const todaysSets = await getTodaysSets();
@ -115,15 +117,14 @@ export default function SetList() {
const count = todaysSets.filter( const count = todaysSets.filter(
s => s.name === todaysSets[0].name, s => s.name === todaysSets[0].name,
).length; ).length;
const maxSets = await AsyncStorage.getItem('maxSets');
nextWorkout = todaysSets[0].name; nextWorkout = todaysSets[0].name;
if (count >= Number(maxSets)) if (count >= Number(settings.sets))
nextWorkout = nextWorkout =
todaysWorkouts[todaysWorkouts.indexOf(todaysSets[0].name!) + 1]; todaysWorkouts[todaysWorkouts.indexOf(todaysSets[0].name!) + 1];
} }
const best = await getBest(nextWorkout); const best = await getBest(nextWorkout);
setNextSet({...best}); setNextSet({...best});
}, [getTodaysSets, getTodaysPlan, getBest]); }, [getTodaysSets, getTodaysPlan, getBest, db]);
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {

View File

@ -1,9 +1,8 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import React, { import React, {
ReactNode, ReactNode,
useCallback, useCallback,
useContext,
useEffect, useEffect,
useMemo,
useState, useState,
} from 'react'; } from 'react';
import { import {
@ -14,10 +13,10 @@ import {
View, View,
} from 'react-native'; } from 'react-native';
import {Searchbar, TextInput} from 'react-native-paper'; import {Searchbar, TextInput} from 'react-native-paper';
import {DatabaseContext} from './App';
import ConfirmDialog from './ConfirmDialog'; import ConfirmDialog from './ConfirmDialog';
import MassiveSwitch from './MassiveSwitch'; import MassiveSwitch from './MassiveSwitch';
import Settings from './settings';
const {getItem, setItem} = AsyncStorage;
export default function SettingsPage() { export default function SettingsPage() {
const [vibrate, setVibrate] = useState(true); const [vibrate, setVibrate] = useState(true);
@ -29,25 +28,36 @@ export default function SettingsPage() {
const [battery, setBattery] = useState(false); const [battery, setBattery] = useState(false);
const [ignoring, setIgnoring] = useState(false); const [ignoring, setIgnoring] = useState(false);
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
const db = useContext(DatabaseContext);
const refresh = useCallback(async () => { const refresh = useCallback(async () => {
setMinutes((await getItem('minutes')) || ''); const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`);
setSeconds((await getItem('seconds')) || ''); const settings: Settings = result.rows.item(0);
setAlarm((await getItem('alarmEnabled')) === 'true'); console.log('SettingsPage.refresh:', {settings});
setPredictive((await getItem('predictiveSets')) === 'true'); setMinutes(settings.minutes.toString());
setMaxSets((await getItem('maxSets')) || ''); setSeconds(settings.seconds.toString());
setAlarm(!!settings.alarm);
setPredictive(!!settings.predict);
setMaxSets(settings.sets.toString());
setVibrate(!!settings.vibrate);
NativeModules.AlarmModule.ignoringBattery(setIgnoring); NativeModules.AlarmModule.ignoringBattery(setIgnoring);
}, []); }, [db]);
useEffect(() => { useEffect(() => {
refresh(); refresh();
}, [refresh]); }, [refresh]);
useEffect(() => {
db.executeSql(
`UPDATE settings SET vibrate=?,minutes=?,sets=?,seconds=?,alarm=?,predict=?`,
[vibrate, minutes, maxSets, seconds, alarm, predictive],
);
}, [vibrate, minutes, maxSets, seconds, alarm, predictive, db]);
const changeAlarmEnabled = useCallback( const changeAlarmEnabled = useCallback(
(enabled: boolean) => { (enabled: boolean) => {
setAlarm(enabled); setAlarm(enabled);
if (enabled && !ignoring) setBattery(true); if (enabled && !ignoring) setBattery(true);
setItem('alarmEnabled', enabled ? 'true' : 'false');
}, },
[setBattery, ignoring], [setBattery, ignoring],
); );
@ -55,7 +65,6 @@ export default function SettingsPage() {
const changePredictive = useCallback( const changePredictive = useCallback(
(enabled: boolean) => { (enabled: boolean) => {
setPredictive(enabled); setPredictive(enabled);
setItem('predictiveSets', enabled ? 'true' : 'false');
ToastAndroid.show( ToastAndroid.show(
'Predictive sets guess whats next based on todays plan.', 'Predictive sets guess whats next based on todays plan.',
ToastAndroid.LONG, ToastAndroid.LONG,
@ -67,7 +76,6 @@ export default function SettingsPage() {
const changeVibrate = useCallback( const changeVibrate = useCallback(
(value: boolean) => { (value: boolean) => {
setVibrate(value); setVibrate(value);
setItem('vibrate', value ? 'true' : 'false');
}, },
[setVibrate], [setVibrate],
); );
@ -82,7 +90,6 @@ export default function SettingsPage() {
keyboardType="numeric" keyboardType="numeric"
onChangeText={value => { onChangeText={value => {
setMaxSets(value); setMaxSets(value);
setItem('maxSets', value);
}} }}
style={styles.text} style={styles.text}
selectTextOnFocus selectTextOnFocus
@ -99,7 +106,6 @@ export default function SettingsPage() {
placeholder="30" placeholder="30"
onChangeText={s => { onChangeText={s => {
setSeconds(s); setSeconds(s);
setItem('seconds', s);
}} }}
style={styles.text} style={styles.text}
selectTextOnFocus selectTextOnFocus
@ -116,7 +122,6 @@ export default function SettingsPage() {
placeholder="3" placeholder="3"
onChangeText={text => { onChangeText={text => {
setMinutes(text); setMinutes(text);
setItem('minutes', text);
}} }}
style={styles.text} style={styles.text}
selectTextOnFocus selectTextOnFocus
@ -166,7 +171,12 @@ export default function SettingsPage() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Searchbar placeholder="Search" value={search} onChangeText={setSearch} /> <Searchbar
style={{marginBottom: 10}}
placeholder="Search"
value={search}
onChangeText={setSearch}
/>
{items {items
.filter(item => item.name.toLowerCase().includes(search.toLowerCase())) .filter(item => item.name.toLowerCase().includes(search.toLowerCase()))
.map(item => ( .map(item => (

11
db.ts
View File

@ -21,3 +21,14 @@ export const createPlans = `
workouts TEXT NOT NULL workouts TEXT NOT NULL
); );
`; `;
export const createSettings = `
CREATE TABLE IF NOT EXISTS settings (
minutes INTEGER NOT NULL DEFAULT 3,
seconds INTEGER NOT NULL DEFAULT 30,
alarm BOOLEAN NOT NULL DEFAULT false,
vibrate BOOLEAN NOT NULL DEFAULT true,
predict BOOLEAN NOT NULL DEFAULT true,
sets INTEGER NOT NULL DEFAULT 3
);
`;

8
settings.ts Normal file
View File

@ -0,0 +1,8 @@
export default interface Settings {
minutes: number;
seconds: number;
alarm: number;
vibrate: number;
predict: number;
sets: number;
}