Add progress to plans

This commit is contained in:
Brandon Presley 2022-07-07 12:45:45 +12:00
parent 67b22f9f51
commit ecb436f8a6
8 changed files with 96 additions and 47 deletions

View File

@ -86,7 +86,7 @@ export default function EditPlan({
<Portal> <Portal>
<Dialog visible={show} onDismiss={() => setShow(false)}> <Dialog visible={show} onDismiss={() => setShow(false)}>
<Dialog.Title>{id ? `Edit "${days}"` : 'Add a plan'}</Dialog.Title> <Dialog.Title>{id ? `Edit "${days}"` : 'Add a plan'}</Dialog.Title>
<Dialog.Content style={{alignItems: 'flex-end'}}> <Dialog.Content>
{days.split(',').map((day, index) => ( {days.split(',').map((day, index) => (
<DayMenu <DayMenu
index={index} index={index}

View File

@ -72,6 +72,7 @@ export default function EditSet({
value={name} value={name}
onChangeText={setName} onChangeText={setName}
onSubmitEditing={() => repsRef.current?.focus()} onSubmitEditing={() => repsRef.current?.focus()}
autoCorrect={false}
/> />
<TextInput <TextInput
style={styles.text} style={styles.text}

View File

@ -1,3 +1,4 @@
import {useFocusEffect} from '@react-navigation/native';
import {NativeStackScreenProps} from '@react-navigation/native-stack'; import {NativeStackScreenProps} from '@react-navigation/native-stack';
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native'; import {FlatList, StyleSheet, View} from 'react-native';
@ -6,9 +7,7 @@ import {RootStackParamList} from './App';
import {getDb} from './db'; import {getDb} from './db';
import Exercise from './exercise'; import Exercise from './exercise';
export default function Exercises({ export default function Exercises() {
navigation,
}: NativeStackScreenProps<RootStackParamList, 'Exercises'>) {
const [exercises, setExercises] = useState<Exercise[]>([]); const [exercises, setExercises] = useState<Exercise[]>([]);
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
const [refreshing, setRefresing] = useState(false); const [refreshing, setRefresing] = useState(false);
@ -26,7 +25,10 @@ export default function Exercises({
setExercises(result.rows.raw()); setExercises(result.rows.raw());
}; };
useEffect(() => navigation.addListener('focus', refresh), [navigation]); useFocusEffect(() => {
refresh();
});
useEffect(() => { useEffect(() => {
refresh(); refresh();
}, [search]); }, [search]);

View File

@ -1,13 +1,7 @@
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import {useNavigation} from '@react-navigation/native'; import {useFocusEffect} from '@react-navigation/native';
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import { import {FlatList, NativeModules, SafeAreaView, StyleSheet} from 'react-native';
FlatList,
NativeModules,
SafeAreaView,
StyleSheet,
View,
} from 'react-native';
import {AnimatedFAB, Searchbar} from 'react-native-paper'; import {AnimatedFAB, Searchbar} from 'react-native-paper';
import {getSets} from './db'; import {getSets} from './db';
import EditSet from './EditSet'; import EditSet from './EditSet';
@ -24,23 +18,26 @@ export default function Home() {
const [showEdit, setShowEdit] = useState(false); const [showEdit, setShowEdit] = useState(false);
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
const [refreshing, setRefresing] = useState(false); const [refreshing, setRefresing] = useState(false);
const navigation = useNavigation();
const refresh = async () => { const refresh = async () => {
setRefresing(true); const [result] = await getSets({search, limit, offset: 0});
const [result] = await getSets({search, limit, offset: 0}).finally(() =>
setRefresing(false),
);
if (!result) return setSets([]); if (!result) return setSets([]);
setSets(result.rows.raw()); setSets(result.rows.raw());
setOffset(0); setOffset(0);
}; };
const refreshLoader = async () => {
setRefresing(true);
refresh().finally(() => setRefresing(false));
};
useEffect(() => { useEffect(() => {
refresh(); refresh();
}, [search]); }, [search]);
useEffect(() => navigation.addListener('focus', refresh), [navigation]); useFocusEffect(() => {
refresh();
});
const renderItem = ({item}: {item: Set}) => ( const renderItem = ({item}: {item: Set}) => (
<SetItem <SetItem
@ -78,13 +75,12 @@ export default function Home() {
<SafeAreaView style={styles.container}> <SafeAreaView style={styles.container}>
<Searchbar placeholder="Search" value={search} onChangeText={setSearch} /> <Searchbar placeholder="Search" value={search} onChangeText={setSearch} />
<FlatList <FlatList
style={{height: '90%'}}
data={sets} data={sets}
renderItem={renderItem} renderItem={renderItem}
keyExtractor={set => set.id.toString()} keyExtractor={set => set.id.toString()}
onEndReached={next} onEndReached={next}
refreshing={refreshing} refreshing={refreshing}
onRefresh={refresh} onRefresh={refreshLoader}
/> />
<EditSet <EditSet
clearId={() => setId(undefined)} clearId={() => setId(undefined)}
@ -113,6 +109,7 @@ const styles = StyleSheet.create({
fontSize: 18, fontSize: 18,
}, },
container: { container: {
flexGrow: 1,
flex: 1, flex: 1,
padding: 10, padding: 10,
}, },

View File

@ -1,10 +1,13 @@
import {useFocusEffect} from '@react-navigation/native';
import {format} from 'date-fns';
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import {FlatList, View} from 'react-native'; import {FlatList, StyleSheet, Text, View} from 'react-native';
import {AnimatedFAB, Searchbar} from 'react-native-paper'; import {AnimatedFAB, ProgressBar, Searchbar} from 'react-native-paper';
import {getPlans} from './db'; import {getPlans, getProgress} from './db';
import EditPlan from './EditPlan'; import EditPlan from './EditPlan';
import {Plan} from './plan'; import {Plan} from './plan';
import PlanItem from './PlanItem'; import PlanItem from './PlanItem';
import Progress from './progress';
export default function Plans() { export default function Plans() {
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
@ -12,12 +15,31 @@ export default function Plans() {
const [refreshing, setRefresing] = useState(false); const [refreshing, setRefresing] = useState(false);
const [id, setId] = useState<number>(); const [id, setId] = useState<number>();
const [showEdit, setShowEdit] = useState(false); const [showEdit, setShowEdit] = useState(false);
const [progresses, setProgresses] = useState<Progress[]>([]);
const today = `%${format(new Date(new Date().toUTCString()), 'EEEE')}%`;
const now = `${format(new Date(new Date().toUTCString()), 'yyyy-MM-dd')}%`;
const refresh = async () => { const refresh = async () => {
const [plansResult] = await getPlans({search}); const [plansResult] = await getPlans({search});
setPlans(plansResult.rows.raw()); setPlans(plansResult.rows.raw());
const [todaysResult] = await getPlans({search: today});
if (todaysResult.rows.length === 0) return;
const workouts: string[] = todaysResult.rows.item(0).workouts.split(',');
const newProgress: Progress[] = [];
for (const workout of workouts) {
const [workoutResult] = await getProgress({
created: now,
name: workout,
});
newProgress.push({name: workout, sets: workoutResult.rows.item(0).count});
}
setProgresses(newProgress);
}; };
useFocusEffect(() => {
refresh();
});
useEffect(() => { useEffect(() => {
refresh(); refresh();
}, [search]); }, [search]);
@ -33,15 +55,24 @@ export default function Plans() {
); );
return ( return (
<View style={{padding: 10}}> <View style={styles.container}>
<Searchbar value={search} onChangeText={setSearch} placeholder="Search" /> <Searchbar value={search} onChangeText={setSearch} placeholder="Search" />
{progresses.map(progress => (
<React.Fragment key={progress.name}>
<Text style={styles.progress}>{progress.name}</Text>
<ProgressBar progress={progress.sets / 3} />
</React.Fragment>
))}
<FlatList <FlatList
style={{height: '90%'}}
data={plans} data={plans}
renderItem={renderItem} renderItem={renderItem}
keyExtractor={set => set.id.toString()} keyExtractor={set => set.id.toString()}
refreshing={refreshing} refreshing={refreshing}
onRefresh={refresh} onRefresh={() => {
setRefresing(true);
refresh().finally(() => setRefresing(false));
}}
/> />
<EditPlan <EditPlan
@ -65,3 +96,13 @@ export default function Plans() {
</View> </View>
); );
} }
const styles = StyleSheet.create({
container: {
flexGrow: 1,
padding: 10,
},
progress: {
marginTop: 10,
},
});

View File

@ -1,28 +1,29 @@
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import {NativeStackScreenProps} from '@react-navigation/native-stack'; import {useFocusEffect, useNavigation} from '@react-navigation/native';
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import {NativeModules, StyleSheet, Text, View} from 'react-native'; import {NativeModules, StyleSheet, Text, View} from 'react-native';
import {Button, Snackbar, Switch, TextInput} from 'react-native-paper'; import {Button, Snackbar, Switch, TextInput} from 'react-native-paper';
import {RootStackParamList} from './App';
import {getDb} from './db';
import BatteryDialog from './BatteryDialog'; import BatteryDialog from './BatteryDialog';
import {getDb} from './db';
export default function Settings({ export default function Settings() {
navigation,
}: NativeStackScreenProps<RootStackParamList, 'Settings'>) {
const [minutes, setMinutes] = useState<string>(''); const [minutes, setMinutes] = useState<string>('');
const [seconds, setSeconds] = useState<string>(''); const [seconds, setSeconds] = useState<string>('');
const [alarmEnabled, setAlarmEnabled] = useState<boolean>(true); const [alarmEnabled, setAlarmEnabled] = useState<boolean>(true);
const [snackbar, setSnackbar] = useState(''); const [snackbar, setSnackbar] = useState('');
const [showBattery, setShowBattery] = useState(false); const [showBattery, setShowBattery] = useState(false);
const [ignoring, setIgnoring] = useState(false);
useEffect(() => { const refresh = async () => {
(async () => { setMinutes((await AsyncStorage.getItem('minutes')) || '3');
setMinutes((await AsyncStorage.getItem('minutes')) || '3'); setSeconds((await AsyncStorage.getItem('seconds')) || '');
setSeconds((await AsyncStorage.getItem('seconds')) || ''); setAlarmEnabled((await AsyncStorage.getItem('alarmEnabled')) === 'true');
setAlarmEnabled((await AsyncStorage.getItem('alarmEnabled')) === 'true'); NativeModules.AlarmModule.ignoringBatteryOptimizations(setIgnoring);
})(); };
}, [navigation]);
useFocusEffect(() => {
refresh();
});
useEffect(() => { useEffect(() => {
if (minutes) AsyncStorage.setItem('minutes', minutes); if (minutes) AsyncStorage.setItem('minutes', minutes);
@ -46,13 +47,8 @@ export default function Settings({
}; };
const changeAlarmEnabled = (enabled: boolean) => { const changeAlarmEnabled = (enabled: boolean) => {
if (!enabled) return setAlarmEnabled(enabled); setAlarmEnabled(enabled);
NativeModules.AlarmModule.ignoringBatteryOptimizations( if (enabled && !ignoring) setShowBattery(true);
(ignoring: boolean) => {
if (ignoring) return setAlarmEnabled(true);
setShowBattery(true);
},
);
}; };
return ( return (

8
db.ts
View File

@ -37,6 +37,14 @@ export const getPlans = ({search}: {search: string}) =>
db.executeSql(selectPlans, [`%${search}%`, `%${search}%`]), db.executeSql(selectPlans, [`%${search}%`, `%${search}%`]),
); );
const selectProgress = `
SELECT count(*) as count from sets
WHERE created LIKE ?
AND name = ?
`;
export const getProgress = ({created, name}: {created: string; name: string}) =>
getDb().then(db => db.executeSql(selectProgress, [`%${created}%`, name]));
const selectSets = ` const selectSets = `
SELECT * from sets SELECT * from sets
WHERE name LIKE ? WHERE name LIKE ?

4
progress.ts Normal file
View File

@ -0,0 +1,4 @@
export default interface Progress {
name: string;
sets: number;
}