Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
3ec685a76e | |||
8a74d750c4 | |||
5fc4c758b6 |
74
BestList.tsx
74
BestList.tsx
|
@ -1,74 +0,0 @@
|
||||||
import {
|
|
||||||
NavigationProp,
|
|
||||||
useFocusEffect,
|
|
||||||
useNavigation,
|
|
||||||
} from '@react-navigation/native';
|
|
||||||
import React, {useCallback, useEffect, useState} from 'react';
|
|
||||||
import {FlatList, Image} from 'react-native';
|
|
||||||
import {List} from 'react-native-paper';
|
|
||||||
import {getBestReps, getBestWeights} from './best.service';
|
|
||||||
import {BestPageParams} from './BestPage';
|
|
||||||
import Page from './Page';
|
|
||||||
import Set from './set';
|
|
||||||
import {settings} from './settings.service';
|
|
||||||
|
|
||||||
export default function BestList() {
|
|
||||||
const [bests, setBests] = useState<Set[]>([]);
|
|
||||||
const [search, setSearch] = useState('');
|
|
||||||
const navigation = useNavigation<NavigationProp<BestPageParams>>();
|
|
||||||
|
|
||||||
const refresh = useCallback(async () => {
|
|
||||||
const weights = await getBestWeights(search);
|
|
||||||
console.log(`${BestList.name}.refresh:`, {length: weights.length});
|
|
||||||
let newBest: Set[] = [];
|
|
||||||
for (const set of weights) {
|
|
||||||
const reps = await getBestReps(set.name, set.weight);
|
|
||||||
newBest.push(...reps);
|
|
||||||
}
|
|
||||||
setBests(newBest);
|
|
||||||
}, [search]);
|
|
||||||
|
|
||||||
useFocusEffect(
|
|
||||||
useCallback(() => {
|
|
||||||
refresh();
|
|
||||||
navigation.getParent()?.setOptions({
|
|
||||||
headerRight: () => null,
|
|
||||||
});
|
|
||||||
}, [refresh, navigation]),
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
refresh();
|
|
||||||
}, [search, refresh]);
|
|
||||||
|
|
||||||
const renderItem = ({item}: {item: Set}) => (
|
|
||||||
<List.Item
|
|
||||||
key={item.name}
|
|
||||||
title={item.name}
|
|
||||||
description={`${item.reps} x ${item.weight}${item.unit || 'kg'}`}
|
|
||||||
onPress={() => navigation.navigate('ViewBest', {best: item})}
|
|
||||||
left={() =>
|
|
||||||
(settings.images && item.image && (
|
|
||||||
<Image source={{uri: item.image}} style={{height: 75, width: 75}} />
|
|
||||||
)) ||
|
|
||||||
null
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page search={search} setSearch={setSearch}>
|
|
||||||
<FlatList
|
|
||||||
style={{height: '99%'}}
|
|
||||||
ListEmptyComponent={
|
|
||||||
<List.Item
|
|
||||||
title="No exercises yet"
|
|
||||||
description="Once sets have been added, this will highlight your personal bests."
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
renderItem={renderItem}
|
|
||||||
data={bests}
|
|
||||||
/>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
98
BestPage.tsx
98
BestPage.tsx
|
@ -1,42 +1,74 @@
|
||||||
import {DrawerNavigationProp} from '@react-navigation/drawer';
|
import {
|
||||||
import {useNavigation} from '@react-navigation/native';
|
NavigationProp,
|
||||||
import {createStackNavigator} from '@react-navigation/stack';
|
useFocusEffect,
|
||||||
import React from 'react';
|
useNavigation,
|
||||||
import {IconButton} from 'react-native-paper';
|
} from '@react-navigation/native';
|
||||||
import BestList from './BestList';
|
import {default as React, useCallback, useEffect, useState} from 'react';
|
||||||
|
import {FlatList, Image} from 'react-native';
|
||||||
|
import {List} from 'react-native-paper';
|
||||||
|
import {getBestReps, getBestWeights} from './best.service';
|
||||||
import {DrawerParamList} from './drawer-param-list';
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
|
import Page from './Page';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import ViewBest from './ViewBest';
|
import {settings} from './settings.service';
|
||||||
|
|
||||||
const Stack = createStackNavigator<BestPageParams>();
|
|
||||||
export type BestPageParams = {
|
|
||||||
BestList: {};
|
|
||||||
ViewBest: {
|
|
||||||
best: Set;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function BestPage() {
|
export default function BestPage() {
|
||||||
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
|
const [bests, setBests] = useState<Set[]>([]);
|
||||||
|
const [search, setSearch] = useState('');
|
||||||
|
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
|
||||||
|
|
||||||
|
const refresh = useCallback(async () => {
|
||||||
|
const weights = await getBestWeights(search);
|
||||||
|
console.log(`${BestPage.name}.refresh:`, {length: weights.length});
|
||||||
|
let newBest: Set[] = [];
|
||||||
|
for (const set of weights) {
|
||||||
|
const reps = await getBestReps(set.name, set.weight);
|
||||||
|
newBest.push(...reps);
|
||||||
|
}
|
||||||
|
setBests(newBest);
|
||||||
|
}, [search]);
|
||||||
|
|
||||||
|
useFocusEffect(
|
||||||
|
useCallback(() => {
|
||||||
|
refresh();
|
||||||
|
navigation.getParent()?.setOptions({
|
||||||
|
headerRight: () => null,
|
||||||
|
});
|
||||||
|
}, [refresh, navigation]),
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
refresh();
|
||||||
|
}, [search, refresh]);
|
||||||
|
|
||||||
|
const renderItem = ({item}: {item: Set}) => (
|
||||||
|
<List.Item
|
||||||
|
key={item.name}
|
||||||
|
title={item.name}
|
||||||
|
description={`${item.reps} x ${item.weight}${item.unit || 'kg'}`}
|
||||||
|
onPress={() => navigation.navigate('View best', {best: item})}
|
||||||
|
left={() =>
|
||||||
|
(settings.images && item.image && (
|
||||||
|
<Image source={{uri: item.image}} style={{height: 75, width: 75}} />
|
||||||
|
)) ||
|
||||||
|
null
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator
|
<Page search={search} setSearch={setSearch}>
|
||||||
screenOptions={{headerShown: false, animationEnabled: false}}>
|
<FlatList
|
||||||
<Stack.Screen name="BestList" component={BestList} />
|
style={{height: '99%'}}
|
||||||
<Stack.Screen
|
ListEmptyComponent={
|
||||||
name="ViewBest"
|
<List.Item
|
||||||
component={ViewBest}
|
title="No exercises yet"
|
||||||
listeners={{
|
description="Once sets have been added, this will highlight your personal bests."
|
||||||
beforeRemove: () => {
|
|
||||||
navigation.setOptions({
|
|
||||||
headerLeft: () => (
|
|
||||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
|
||||||
),
|
|
||||||
title: 'Best',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
}
|
||||||
|
renderItem={renderItem}
|
||||||
|
data={bests}
|
||||||
|
/>
|
||||||
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
18
EditPlan.tsx
18
EditPlan.tsx
|
@ -6,18 +6,17 @@ import {
|
||||||
useRoute,
|
useRoute,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import React, {useCallback, useEffect, useState} from 'react';
|
import React, {useCallback, useEffect, useState} from 'react';
|
||||||
import {ScrollView, StyleSheet, View} from 'react-native';
|
import {BackHandler, ScrollView, StyleSheet, View} from 'react-native';
|
||||||
import {Button, IconButton, Text} from 'react-native-paper';
|
import {Button, IconButton, Text} from 'react-native-paper';
|
||||||
import {MARGIN, PADDING} from './constants';
|
import {MARGIN, PADDING} from './constants';
|
||||||
import {DrawerParamList} from './drawer-param-list';
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
import {PlanPageParams} from './plan-page-params';
|
|
||||||
import {addPlan, updatePlan} from './plan.service';
|
import {addPlan, updatePlan} from './plan.service';
|
||||||
import {getNames} from './set.service';
|
import {getNames} from './set.service';
|
||||||
import Switch from './Switch';
|
import Switch from './Switch';
|
||||||
import {DAYS} from './time';
|
import {DAYS} from './time';
|
||||||
|
|
||||||
export default function EditPlan() {
|
export default function EditPlan() {
|
||||||
const {params} = useRoute<RouteProp<PlanPageParams, 'EditPlan'>>();
|
const {params} = useRoute<RouteProp<DrawerParamList, 'Edit plan'>>();
|
||||||
const {plan} = params;
|
const {plan} = params;
|
||||||
const [days, setDays] = useState<string[]>(
|
const [days, setDays] = useState<string[]>(
|
||||||
plan.days ? plan.days.split(',') : [],
|
plan.days ? plan.days.split(',') : [],
|
||||||
|
@ -31,13 +30,22 @@ export default function EditPlan() {
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
console.log(`${EditPlan.name}.focus:`, {plan});
|
console.log(`${EditPlan.name}.focus:`, {plan});
|
||||||
navigation.getParent()?.setOptions({
|
navigation.setOptions({
|
||||||
headerLeft: () => (
|
headerLeft: () => (
|
||||||
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
<IconButton
|
||||||
|
icon="arrow-back"
|
||||||
|
onPress={() => navigation.navigate('Plans', {})}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
headerRight: () => null,
|
headerRight: () => null,
|
||||||
title: plan.id ? 'Edit plan' : 'Create plan',
|
title: plan.id ? 'Edit plan' : 'Create plan',
|
||||||
});
|
});
|
||||||
|
const onBack = () => {
|
||||||
|
navigation.navigate('Plans', {});
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
BackHandler.addEventListener('hardwareBackPress', onBack);
|
||||||
|
return () => BackHandler.removeEventListener('hardwareBackPress', onBack);
|
||||||
}, [navigation, plan]),
|
}, [navigation, plan]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
27
EditSet.tsx
27
EditSet.tsx
|
@ -1,14 +1,15 @@
|
||||||
import {
|
import {
|
||||||
|
NavigationProp,
|
||||||
RouteProp,
|
RouteProp,
|
||||||
useFocusEffect,
|
useFocusEffect,
|
||||||
useNavigation,
|
useNavigation,
|
||||||
useRoute,
|
useRoute,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import React, {useCallback, useContext} from 'react';
|
import React, {useCallback, useContext} from 'react';
|
||||||
import {NativeModules, View} from 'react-native';
|
import {BackHandler, NativeModules, View} from 'react-native';
|
||||||
import {IconButton} from 'react-native-paper';
|
import {IconButton} from 'react-native-paper';
|
||||||
import {PADDING} from './constants';
|
import {PADDING} from './constants';
|
||||||
import {HomePageParams} from './home-page-params';
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
import {SnackbarContext} from './MassiveSnack';
|
import {SnackbarContext} from './MassiveSnack';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {addSet, updateSet} from './set.service';
|
import {addSet, updateSet} from './set.service';
|
||||||
|
@ -16,9 +17,9 @@ import SetForm from './SetForm';
|
||||||
import {getSettings, settings, updateSettings} from './settings.service';
|
import {getSettings, settings, updateSettings} from './settings.service';
|
||||||
|
|
||||||
export default function EditSet() {
|
export default function EditSet() {
|
||||||
const {params} = useRoute<RouteProp<HomePageParams, 'EditSet'>>();
|
const {params} = useRoute<RouteProp<DrawerParamList, 'Edit set'>>();
|
||||||
const {set, count, workouts} = params;
|
const {set, count, workouts} = params;
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
|
||||||
const {toast} = useContext(SnackbarContext);
|
const {toast} = useContext(SnackbarContext);
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
|
@ -28,13 +29,21 @@ export default function EditSet() {
|
||||||
if (typeof set.id === 'number') title = 'Edit set';
|
if (typeof set.id === 'number') title = 'Edit set';
|
||||||
else if (Number(set.sets) > 0)
|
else if (Number(set.sets) > 0)
|
||||||
title = `${set.name} (${count + 1} / ${set.sets})`;
|
title = `${set.name} (${count + 1} / ${set.sets})`;
|
||||||
navigation.getParent()?.setOptions({
|
navigation.setOptions({
|
||||||
headerLeft: () => (
|
|
||||||
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
|
||||||
),
|
|
||||||
headerRight: null,
|
|
||||||
title,
|
title,
|
||||||
|
headerLeft: () => (
|
||||||
|
<IconButton
|
||||||
|
icon="arrow-back"
|
||||||
|
onPress={() => navigation.navigate('Home', {})}
|
||||||
|
/>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
const onBack = () => {
|
||||||
|
navigation.navigate('Home', {});
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
BackHandler.addEventListener('hardwareBackPress', onBack);
|
||||||
|
return () => BackHandler.removeEventListener('hardwareBackPress', onBack);
|
||||||
}, [navigation, set, count]),
|
}, [navigation, set, count]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
import {
|
import {
|
||||||
|
NavigationProp,
|
||||||
RouteProp,
|
RouteProp,
|
||||||
useFocusEffect,
|
useFocusEffect,
|
||||||
useNavigation,
|
useNavigation,
|
||||||
useRoute,
|
useRoute,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import React, {useCallback, useContext, useState} from 'react';
|
import React, {useCallback, useContext, useState} from 'react';
|
||||||
import {ScrollView, View} from 'react-native';
|
import {BackHandler, ScrollView, View} from 'react-native';
|
||||||
import DocumentPicker from 'react-native-document-picker';
|
import DocumentPicker from 'react-native-document-picker';
|
||||||
import {Button, Card, IconButton, TouchableRipple} from 'react-native-paper';
|
import {Button, Card, IconButton, TouchableRipple} from 'react-native-paper';
|
||||||
import ConfirmDialog from './ConfirmDialog';
|
import ConfirmDialog from './ConfirmDialog';
|
||||||
import {MARGIN, PADDING} from './constants';
|
import {MARGIN, PADDING} from './constants';
|
||||||
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
import MassiveInput from './MassiveInput';
|
import MassiveInput from './MassiveInput';
|
||||||
import {SnackbarContext} from './MassiveSnack';
|
import {SnackbarContext} from './MassiveSnack';
|
||||||
import {updatePlanWorkouts} from './plan.service';
|
import {updatePlanWorkouts} from './plan.service';
|
||||||
import {addSet, updateManySet, updateSetImage} from './set.service';
|
import {addSet, updateManySet, updateSetImage} from './set.service';
|
||||||
import {settings} from './settings.service';
|
import {settings} from './settings.service';
|
||||||
import {WorkoutsPageParams} from './WorkoutsPage';
|
|
||||||
|
|
||||||
export default function EditWorkout() {
|
export default function EditWorkout() {
|
||||||
const {params} = useRoute<RouteProp<WorkoutsPageParams, 'EditWorkout'>>();
|
const {params} = useRoute<RouteProp<DrawerParamList, 'Edit workout'>>();
|
||||||
const [removeImage, setRemoveImage] = useState(false);
|
const [removeImage, setRemoveImage] = useState(false);
|
||||||
const [showRemove, setShowRemove] = useState(false);
|
const [showRemove, setShowRemove] = useState(false);
|
||||||
const [name, setName] = useState(params.value.name);
|
const [name, setName] = useState(params.value.name);
|
||||||
|
@ -32,19 +33,27 @@ export default function EditWorkout() {
|
||||||
);
|
);
|
||||||
const [sets, setSets] = useState(params.value.sets?.toString() ?? '3');
|
const [sets, setSets] = useState(params.value.sets?.toString() ?? '3');
|
||||||
const {toast} = useContext(SnackbarContext);
|
const {toast} = useContext(SnackbarContext);
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
navigation.getParent()?.setOptions({
|
navigation.setOptions({
|
||||||
headerLeft: () => (
|
headerLeft: () => (
|
||||||
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
<IconButton
|
||||||
|
icon="arrow-back"
|
||||||
|
onPress={() => navigation.navigate('Workouts', {})}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
headerRight: null,
|
headerRight: null,
|
||||||
title: params.value.name || 'New workout',
|
title: params.value.name || 'New workout',
|
||||||
});
|
});
|
||||||
if (!name) return;
|
const onBack = () => {
|
||||||
}, [navigation, name, params.value.name]),
|
navigation.navigate('Workouts', {});
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
BackHandler.addEventListener('hardwareBackPress', onBack);
|
||||||
|
return () => BackHandler.removeEventListener('hardwareBackPress', onBack);
|
||||||
|
}, [navigation, params.value.name]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const update = async () => {
|
const update = async () => {
|
||||||
|
|
153
HomePage.tsx
153
HomePage.tsx
|
@ -1,36 +1,135 @@
|
||||||
import {DrawerNavigationProp} from '@react-navigation/drawer';
|
import {
|
||||||
import {useNavigation} from '@react-navigation/native';
|
NavigationProp,
|
||||||
import {createStackNavigator} from '@react-navigation/stack';
|
useFocusEffect,
|
||||||
import React from 'react';
|
useNavigation,
|
||||||
import {IconButton} from 'react-native-paper';
|
} from '@react-navigation/native';
|
||||||
|
import {default as React, useCallback, useEffect, useState} from 'react';
|
||||||
|
import {FlatList} from 'react-native';
|
||||||
|
import {List} from 'react-native-paper';
|
||||||
|
import {getBestSet} from './best.service';
|
||||||
import {DrawerParamList} from './drawer-param-list';
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
import EditSet from './EditSet';
|
import Page from './Page';
|
||||||
import {HomePageParams} from './home-page-params';
|
import {getTodaysPlan} from './plan.service';
|
||||||
import SetList from './SetList';
|
import Set from './set';
|
||||||
|
import {countToday, defaultSet, getSets, getToday} from './set.service';
|
||||||
|
import SetItem from './SetItem';
|
||||||
|
import {settings} from './settings.service';
|
||||||
|
|
||||||
const Stack = createStackNavigator<HomePageParams>();
|
const limit = 15;
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
|
const [sets, setSets] = useState<Set[]>();
|
||||||
|
const [set, setSet] = useState<Set>();
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
const [workouts, setWorkouts] = useState<string[]>([]);
|
||||||
|
const [offset, setOffset] = useState(0);
|
||||||
|
const [search, setSearch] = useState('');
|
||||||
|
const [end, setEnd] = useState(false);
|
||||||
|
const [dates, setDates] = useState(false);
|
||||||
|
const [images, setImages] = useState(true);
|
||||||
|
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
|
||||||
|
|
||||||
|
const predict = useCallback(async () => {
|
||||||
|
setCount(0);
|
||||||
|
setSet({...defaultSet});
|
||||||
|
if (!settings.predict) return;
|
||||||
|
const todaysPlan = await getTodaysPlan();
|
||||||
|
console.log(`${HomePage.name}.predict:`, {todaysPlan});
|
||||||
|
if (todaysPlan.length === 0) return;
|
||||||
|
const todaysWorkouts = todaysPlan[0].workouts.split(',');
|
||||||
|
setWorkouts(todaysWorkouts);
|
||||||
|
let best = await getBestSet(todaysWorkouts[0]);
|
||||||
|
const todaysSet = await getToday();
|
||||||
|
if (!todaysSet || !todaysWorkouts.includes(todaysSet.name))
|
||||||
|
return setSet({...best});
|
||||||
|
let _count = await countToday(todaysSet.name);
|
||||||
|
best = await getBestSet(todaysSet.name);
|
||||||
|
const index = todaysWorkouts.indexOf(todaysSet.name) + 1;
|
||||||
|
if (_count >= Number(best.sets)) {
|
||||||
|
best = await getBestSet(todaysWorkouts[index]);
|
||||||
|
_count = 0;
|
||||||
|
}
|
||||||
|
if (best.name === '') setCount(0);
|
||||||
|
else setCount(_count);
|
||||||
|
setSet({...best});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const refresh = useCallback(async () => {
|
||||||
|
predict();
|
||||||
|
const newSets = await getSets({search: `%${search}%`, limit, offset: 0});
|
||||||
|
console.log(`${HomePage.name}.refresh:`, {first: newSets[0]});
|
||||||
|
if (newSets.length === 0) return setSets([]);
|
||||||
|
setSets(newSets);
|
||||||
|
setOffset(0);
|
||||||
|
setEnd(false);
|
||||||
|
}, [search, predict]);
|
||||||
|
|
||||||
|
useFocusEffect(
|
||||||
|
useCallback(() => {
|
||||||
|
refresh();
|
||||||
|
setImages(!!settings.images);
|
||||||
|
}, [refresh]),
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
refresh();
|
||||||
|
}, [search, refresh]);
|
||||||
|
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({item}: {item: Set}) => (
|
||||||
|
<SetItem
|
||||||
|
dates={dates}
|
||||||
|
setDates={setDates}
|
||||||
|
images={images}
|
||||||
|
setImages={setImages}
|
||||||
|
item={item}
|
||||||
|
key={item.id}
|
||||||
|
onRemove={refresh}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[refresh, dates, setDates, images, setImages],
|
||||||
|
);
|
||||||
|
|
||||||
|
const next = useCallback(async () => {
|
||||||
|
if (end) return;
|
||||||
|
const newOffset = offset + limit;
|
||||||
|
console.log(`${HomePage.name}.next:`, {offset, newOffset, search});
|
||||||
|
const newSets = await getSets({
|
||||||
|
search: `%${search}%`,
|
||||||
|
limit,
|
||||||
|
offset: newOffset,
|
||||||
|
});
|
||||||
|
if (newSets.length === 0) return setEnd(true);
|
||||||
|
if (!sets) return;
|
||||||
|
setSets([...sets, ...newSets]);
|
||||||
|
if (newSets.length < limit) return setEnd(true);
|
||||||
|
setOffset(newOffset);
|
||||||
|
}, [search, end, offset, sets]);
|
||||||
|
|
||||||
|
const onAdd = useCallback(async () => {
|
||||||
|
console.log(`${HomePage.name}.onAdd`, {set, workouts});
|
||||||
|
navigation.navigate('Edit set', {
|
||||||
|
set: set || {...defaultSet},
|
||||||
|
workouts,
|
||||||
|
count,
|
||||||
|
});
|
||||||
|
}, [navigation, set, workouts, count]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator
|
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
||||||
screenOptions={{headerShown: false, animationEnabled: false}}>
|
<FlatList
|
||||||
<Stack.Screen name="Sets" component={SetList} />
|
data={sets}
|
||||||
<Stack.Screen
|
style={{height: '99%'}}
|
||||||
name="EditSet"
|
ListEmptyComponent={
|
||||||
component={EditSet}
|
<List.Item
|
||||||
listeners={{
|
title="No sets yet"
|
||||||
beforeRemove: () => {
|
description="A set is a group of repetitions. E.g. 8 reps of Squats."
|
||||||
navigation.setOptions({
|
|
||||||
headerLeft: () => (
|
|
||||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
|
||||||
),
|
|
||||||
title: 'Home',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
}
|
||||||
|
renderItem={renderItem}
|
||||||
|
keyExtractor={s => s.id!.toString()}
|
||||||
|
onEndReached={next}
|
||||||
|
/>
|
||||||
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ import {NavigationProp, useNavigation} from '@react-navigation/native';
|
||||||
import React, {useCallback, useState} from 'react';
|
import React, {useCallback, useState} from 'react';
|
||||||
import {GestureResponderEvent} from 'react-native';
|
import {GestureResponderEvent} from 'react-native';
|
||||||
import {List, Menu} from 'react-native-paper';
|
import {List, Menu} from 'react-native-paper';
|
||||||
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
import {Plan} from './plan';
|
import {Plan} from './plan';
|
||||||
import {PlanPageParams} from './plan-page-params';
|
|
||||||
import {deletePlan} from './plan.service';
|
import {deletePlan} from './plan.service';
|
||||||
|
|
||||||
export default function PlanItem({
|
export default function PlanItem({
|
||||||
|
@ -15,7 +15,7 @@ export default function PlanItem({
|
||||||
}) {
|
}) {
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
||||||
const navigation = useNavigation<NavigationProp<PlanPageParams>>();
|
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
|
||||||
|
|
||||||
const remove = useCallback(async () => {
|
const remove = useCallback(async () => {
|
||||||
if (typeof item.id === 'number') await deletePlan(item.id);
|
if (typeof item.id === 'number') await deletePlan(item.id);
|
||||||
|
@ -34,7 +34,7 @@ export default function PlanItem({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<List.Item
|
<List.Item
|
||||||
onPress={() => navigation.navigate('EditPlan', {plan: item})}
|
onPress={() => navigation.navigate('Edit plan', {plan: item})}
|
||||||
title={
|
title={
|
||||||
item.days
|
item.days
|
||||||
? item.days.replace(/,/g, ', ')
|
? item.days.replace(/,/g, ', ')
|
||||||
|
|
64
PlanList.tsx
64
PlanList.tsx
|
@ -1,64 +0,0 @@
|
||||||
import {
|
|
||||||
NavigationProp,
|
|
||||||
useFocusEffect,
|
|
||||||
useNavigation,
|
|
||||||
} from '@react-navigation/native';
|
|
||||||
import React, {useCallback, useEffect, useState} from 'react';
|
|
||||||
import {FlatList} from 'react-native';
|
|
||||||
import {List} from 'react-native-paper';
|
|
||||||
import DrawerMenu from './DrawerMenu';
|
|
||||||
import Page from './Page';
|
|
||||||
import {Plan} from './plan';
|
|
||||||
import {PlanPageParams} from './plan-page-params';
|
|
||||||
import {getPlans} from './plan.service';
|
|
||||||
import PlanItem from './PlanItem';
|
|
||||||
|
|
||||||
export default function PlanList() {
|
|
||||||
const [search, setSearch] = useState('');
|
|
||||||
const [plans, setPlans] = useState<Plan[]>([]);
|
|
||||||
const navigation = useNavigation<NavigationProp<PlanPageParams>>();
|
|
||||||
|
|
||||||
const refresh = useCallback(async () => {
|
|
||||||
getPlans(search).then(setPlans);
|
|
||||||
}, [search]);
|
|
||||||
|
|
||||||
useFocusEffect(
|
|
||||||
useCallback(() => {
|
|
||||||
refresh();
|
|
||||||
navigation.getParent()?.setOptions({
|
|
||||||
headerRight: () => <DrawerMenu name="Plans" />,
|
|
||||||
});
|
|
||||||
}, [refresh, navigation]),
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
refresh();
|
|
||||||
}, [search, refresh]);
|
|
||||||
|
|
||||||
const renderItem = useCallback(
|
|
||||||
({item}: {item: Plan}) => (
|
|
||||||
<PlanItem item={item} key={item.id} onRemove={refresh} />
|
|
||||||
),
|
|
||||||
[refresh],
|
|
||||||
);
|
|
||||||
|
|
||||||
const onAdd = () =>
|
|
||||||
navigation.navigate('EditPlan', {plan: {days: '', workouts: ''}});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
|
||||||
<FlatList
|
|
||||||
style={{height: '99%'}}
|
|
||||||
data={plans}
|
|
||||||
renderItem={renderItem}
|
|
||||||
keyExtractor={set => set.id?.toString() || ''}
|
|
||||||
ListEmptyComponent={
|
|
||||||
<List.Item
|
|
||||||
title="No plans yet"
|
|
||||||
description="A plan is a list of workouts for certain days."
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
84
PlanPage.tsx
84
PlanPage.tsx
|
@ -1,36 +1,64 @@
|
||||||
import {DrawerNavigationProp} from '@react-navigation/drawer';
|
import {
|
||||||
import {useNavigation} from '@react-navigation/native';
|
NavigationProp,
|
||||||
import {createStackNavigator} from '@react-navigation/stack';
|
useFocusEffect,
|
||||||
import React from 'react';
|
useNavigation,
|
||||||
import {IconButton} from 'react-native-paper';
|
} from '@react-navigation/native';
|
||||||
|
import {default as React, useCallback, useEffect, useState} from 'react';
|
||||||
|
import {FlatList} from 'react-native';
|
||||||
|
import {List} from 'react-native-paper';
|
||||||
import {DrawerParamList} from './drawer-param-list';
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
import EditPlan from './EditPlan';
|
import DrawerMenu from './DrawerMenu';
|
||||||
import {PlanPageParams} from './plan-page-params';
|
import Page from './Page';
|
||||||
import PlanList from './PlanList';
|
import {Plan} from './plan';
|
||||||
|
import {getPlans} from './plan.service';
|
||||||
const Stack = createStackNavigator<PlanPageParams>();
|
import PlanItem from './PlanItem';
|
||||||
|
|
||||||
export default function PlanPage() {
|
export default function PlanPage() {
|
||||||
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
|
const [search, setSearch] = useState('');
|
||||||
|
const [plans, setPlans] = useState<Plan[]>([]);
|
||||||
|
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
|
||||||
|
|
||||||
|
const refresh = useCallback(async () => {
|
||||||
|
getPlans(search).then(setPlans);
|
||||||
|
}, [search]);
|
||||||
|
|
||||||
|
useFocusEffect(
|
||||||
|
useCallback(() => {
|
||||||
|
refresh();
|
||||||
|
navigation.getParent()?.setOptions({
|
||||||
|
headerRight: () => <DrawerMenu name="Plans" />,
|
||||||
|
});
|
||||||
|
}, [refresh, navigation]),
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
refresh();
|
||||||
|
}, [search, refresh]);
|
||||||
|
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({item}: {item: Plan}) => (
|
||||||
|
<PlanItem item={item} key={item.id} onRemove={refresh} />
|
||||||
|
),
|
||||||
|
[refresh],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onAdd = () =>
|
||||||
|
navigation.navigate('Edit plan', {plan: {days: '', workouts: ''}});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator
|
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
||||||
screenOptions={{headerShown: false, animationEnabled: false}}>
|
<FlatList
|
||||||
<Stack.Screen name="PlanList" component={PlanList} />
|
style={{height: '99%'}}
|
||||||
<Stack.Screen
|
data={plans}
|
||||||
name="EditPlan"
|
renderItem={renderItem}
|
||||||
component={EditPlan}
|
keyExtractor={set => set.id?.toString() || ''}
|
||||||
listeners={{
|
ListEmptyComponent={
|
||||||
beforeRemove: () => {
|
<List.Item
|
||||||
navigation.setOptions({
|
title="No plans yet"
|
||||||
headerLeft: () => (
|
description="A plan is a list of workouts for certain days."
|
||||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
|
||||||
),
|
|
||||||
title: 'Plans',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
}
|
||||||
|
/>
|
||||||
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
25
Routes.tsx
25
Routes.tsx
|
@ -6,11 +6,16 @@ import {CustomTheme} from './App';
|
||||||
import BestPage from './BestPage';
|
import BestPage from './BestPage';
|
||||||
import {runMigrations} from './db';
|
import {runMigrations} from './db';
|
||||||
import {DrawerParamList} from './drawer-param-list';
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
|
import DrawerMenu from './DrawerMenu';
|
||||||
|
import EditPlan from './EditPlan';
|
||||||
|
import EditSet from './EditSet';
|
||||||
|
import EditWorkout from './EditWorkout';
|
||||||
import HomePage from './HomePage';
|
import HomePage from './HomePage';
|
||||||
import PlanPage from './PlanPage';
|
import PlanPage from './PlanPage';
|
||||||
import Route from './route';
|
import Route from './route';
|
||||||
import {getSettings, settings} from './settings.service';
|
import {getSettings, settings} from './settings.service';
|
||||||
import SettingsPage from './SettingsPage';
|
import SettingsPage from './SettingsPage';
|
||||||
|
import ViewBest from './ViewBest';
|
||||||
import WorkoutsPage from './WorkoutsPage';
|
import WorkoutsPage from './WorkoutsPage';
|
||||||
|
|
||||||
const Drawer = createDrawerNavigator<DrawerParamList>();
|
const Drawer = createDrawerNavigator<DrawerParamList>();
|
||||||
|
@ -39,6 +44,13 @@ export default function Routes() {
|
||||||
{name: 'Settings', component: SettingsPage, icon: 'settings'},
|
{name: 'Settings', component: SettingsPage, icon: 'settings'},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const hiddenRoutes: Route[] = [
|
||||||
|
{name: 'Edit set', component: EditSet},
|
||||||
|
{name: 'Edit plan', component: EditPlan},
|
||||||
|
{name: 'Edit workout', component: EditWorkout},
|
||||||
|
{name: 'View best', component: ViewBest},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer.Navigator
|
<Drawer.Navigator
|
||||||
screenOptions={{
|
screenOptions={{
|
||||||
|
@ -51,7 +63,18 @@ export default function Routes() {
|
||||||
name={route.name}
|
name={route.name}
|
||||||
component={route.component}
|
component={route.component}
|
||||||
options={{
|
options={{
|
||||||
drawerIcon: () => <IconButton icon={route.icon} />,
|
drawerIcon: () => <IconButton icon={route.icon || ''} />,
|
||||||
|
headerRight: () => <DrawerMenu name={route.name} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{hiddenRoutes.map(route => (
|
||||||
|
<Drawer.Screen
|
||||||
|
key={route.name}
|
||||||
|
name={route.name}
|
||||||
|
component={route.component}
|
||||||
|
options={{
|
||||||
|
drawerItemStyle: {height: 0},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
31
SetForm.tsx
31
SetForm.tsx
|
@ -1,4 +1,11 @@
|
||||||
import React, {useContext, useEffect, useRef, useState} from 'react';
|
import {useFocusEffect} from '@react-navigation/native';
|
||||||
|
import React, {
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
import {ScrollView, View} from 'react-native';
|
import {ScrollView, View} from 'react-native';
|
||||||
import {Button, Text} from 'react-native-paper';
|
import {Button, Text} from 'react-native-paper';
|
||||||
import MassiveInput from './MassiveInput';
|
import MassiveInput from './MassiveInput';
|
||||||
|
@ -30,13 +37,25 @@ export default function SetForm({
|
||||||
const repsRef = useRef<any>(null);
|
const repsRef = useRef<any>(null);
|
||||||
const unitRef = useRef<any>(null);
|
const unitRef = useRef<any>(null);
|
||||||
|
|
||||||
|
useFocusEffect(
|
||||||
|
useCallback(() => {
|
||||||
|
repsRef?.current.focus();
|
||||||
|
}, []),
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('SetForm.useEffect:', {uri, name: set.name});
|
console.log('SetForm.useEffect:', {uri, set});
|
||||||
if (!uri)
|
setName(set.name);
|
||||||
|
setReps(set.reps.toString());
|
||||||
|
setWeight(set.weight.toString());
|
||||||
|
setUnit(set.unit);
|
||||||
|
if (!set.image)
|
||||||
getSets({search: set.name, limit: 1, offset: 0}).then(([s]) =>
|
getSets({search: set.name, limit: 1, offset: 0}).then(([s]) =>
|
||||||
setUri(s?.image),
|
setUri(s?.image),
|
||||||
);
|
);
|
||||||
}, [uri, set.name]);
|
else setUri(set.image);
|
||||||
|
repsRef?.current.focus();
|
||||||
|
}, [uri, set]);
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (!name) return;
|
if (!name) return;
|
||||||
|
@ -73,7 +92,6 @@ export default function SetForm({
|
||||||
value={name}
|
value={name}
|
||||||
onChangeText={handleName}
|
onChangeText={handleName}
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
autoFocus={!name}
|
|
||||||
blurOnSubmit={false}
|
blurOnSubmit={false}
|
||||||
onSubmitEditing={() => repsRef.current?.focus()}
|
onSubmitEditing={() => repsRef.current?.focus()}
|
||||||
/>
|
/>
|
||||||
|
@ -85,7 +103,6 @@ export default function SetForm({
|
||||||
onSubmitEditing={() => weightRef.current?.focus()}
|
onSubmitEditing={() => weightRef.current?.focus()}
|
||||||
selection={selection}
|
selection={selection}
|
||||||
onSelectionChange={e => setSelection(e.nativeEvent.selection)}
|
onSelectionChange={e => setSelection(e.nativeEvent.selection)}
|
||||||
autoFocus={!!name}
|
|
||||||
blurOnSubmit={false}
|
blurOnSubmit={false}
|
||||||
innerRef={repsRef}
|
innerRef={repsRef}
|
||||||
/>
|
/>
|
||||||
|
@ -109,7 +126,7 @@ export default function SetForm({
|
||||||
{workouts.length > 0 && !!settings.workouts && (
|
{workouts.length > 0 && !!settings.workouts && (
|
||||||
<View style={{flexDirection: 'row'}}>
|
<View style={{flexDirection: 'row'}}>
|
||||||
{workouts.map((workout, index) => (
|
{workouts.map((workout, index) => (
|
||||||
<Text>
|
<Text key={workout}>
|
||||||
<Text
|
<Text
|
||||||
style={
|
style={
|
||||||
workout === name
|
workout === name
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {NavigationProp, useNavigation} from '@react-navigation/native';
|
||||||
import React, {useCallback, useState} from 'react';
|
import React, {useCallback, useState} from 'react';
|
||||||
import {GestureResponderEvent, Image} from 'react-native';
|
import {GestureResponderEvent, Image} from 'react-native';
|
||||||
import {Divider, List, Menu, Text} from 'react-native-paper';
|
import {Divider, List, Menu, Text} from 'react-native-paper';
|
||||||
import {HomePageParams} from './home-page-params';
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {deleteSet} from './set.service';
|
import {deleteSet} from './set.service';
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ export default function SetItem({
|
||||||
}) {
|
}) {
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
||||||
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
|
||||||
|
|
||||||
const remove = useCallback(async () => {
|
const remove = useCallback(async () => {
|
||||||
if (typeof item.id === 'number') await deleteSet(item.id);
|
if (typeof item.id === 'number') await deleteSet(item.id);
|
||||||
|
@ -35,7 +35,7 @@ export default function SetItem({
|
||||||
const set: Set = {...item};
|
const set: Set = {...item};
|
||||||
delete set.id;
|
delete set.id;
|
||||||
setShowMenu(false);
|
setShowMenu(false);
|
||||||
navigation.navigate('EditSet', {set, workouts: [], count: 0});
|
navigation.navigate('Edit set', {set, workouts: [], count: 0});
|
||||||
}, [navigation, item]);
|
}, [navigation, item]);
|
||||||
|
|
||||||
const longPress = useCallback(
|
const longPress = useCallback(
|
||||||
|
@ -60,7 +60,7 @@ export default function SetItem({
|
||||||
<>
|
<>
|
||||||
<List.Item
|
<List.Item
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
navigation.navigate('EditSet', {set: item, workouts: [], count: 0})
|
navigation.navigate('Edit set', {set: item, workouts: [], count: 0})
|
||||||
}
|
}
|
||||||
title={item.name}
|
title={item.name}
|
||||||
description={`${item.reps} x ${item.weight}${item.unit || 'kg'}`}
|
description={`${item.reps} x ${item.weight}${item.unit || 'kg'}`}
|
||||||
|
|
140
SetList.tsx
140
SetList.tsx
|
@ -1,140 +0,0 @@
|
||||||
import {
|
|
||||||
NavigationProp,
|
|
||||||
useFocusEffect,
|
|
||||||
useNavigation,
|
|
||||||
} from '@react-navigation/native';
|
|
||||||
import React, {useCallback, useEffect, useState} from 'react';
|
|
||||||
import {FlatList} from 'react-native';
|
|
||||||
import {List} from 'react-native-paper';
|
|
||||||
import {getBestSet} from './best.service';
|
|
||||||
import DrawerMenu from './DrawerMenu';
|
|
||||||
import {HomePageParams} from './home-page-params';
|
|
||||||
import Page from './Page';
|
|
||||||
import {getTodaysPlan} from './plan.service';
|
|
||||||
import Set from './set';
|
|
||||||
import {countToday, defaultSet, getSets, getToday} from './set.service';
|
|
||||||
import SetItem from './SetItem';
|
|
||||||
import {settings} from './settings.service';
|
|
||||||
|
|
||||||
const limit = 15;
|
|
||||||
|
|
||||||
export default function SetList() {
|
|
||||||
const [sets, setSets] = useState<Set[]>();
|
|
||||||
const [set, setSet] = useState<Set>();
|
|
||||||
const [count, setCount] = useState(0);
|
|
||||||
const [workouts, setWorkouts] = useState<string[]>([]);
|
|
||||||
const [offset, setOffset] = useState(0);
|
|
||||||
const [search, setSearch] = useState('');
|
|
||||||
const [end, setEnd] = useState(false);
|
|
||||||
const [dates, setDates] = useState(false);
|
|
||||||
const [images, setImages] = useState(true);
|
|
||||||
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
|
||||||
|
|
||||||
const predict = useCallback(async () => {
|
|
||||||
setCount(0);
|
|
||||||
setSet({...defaultSet});
|
|
||||||
if (!settings.predict) return;
|
|
||||||
const todaysPlan = await getTodaysPlan();
|
|
||||||
if (todaysPlan.length === 0) return;
|
|
||||||
const todaysWorkouts = todaysPlan[0].workouts.split(',');
|
|
||||||
setWorkouts(todaysWorkouts);
|
|
||||||
let workout = todaysWorkouts[0];
|
|
||||||
let best = await getBestSet(workout);
|
|
||||||
const todaysSet = await getToday();
|
|
||||||
if (!todaysSet || !todaysWorkouts.includes(todaysSet.name))
|
|
||||||
return setSet(best);
|
|
||||||
let _count = await countToday(todaysSet.name);
|
|
||||||
workout = todaysSet.name;
|
|
||||||
best = await getBestSet(workout);
|
|
||||||
const index = todaysWorkouts.indexOf(todaysSet.name) + 1;
|
|
||||||
if (_count >= Number(best.sets)) {
|
|
||||||
best = await getBestSet(todaysWorkouts[index]);
|
|
||||||
_count = 0;
|
|
||||||
}
|
|
||||||
if (best.name === '') setCount(0);
|
|
||||||
else setCount(_count);
|
|
||||||
setSet(best);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const refresh = useCallback(async () => {
|
|
||||||
predict();
|
|
||||||
const newSets = await getSets({search: `%${search}%`, limit, offset: 0});
|
|
||||||
console.log(`${SetList.name}.refresh:`, {first: newSets[0]});
|
|
||||||
if (newSets.length === 0) return setSets([]);
|
|
||||||
setSets(newSets);
|
|
||||||
setOffset(0);
|
|
||||||
setEnd(false);
|
|
||||||
}, [search, predict]);
|
|
||||||
|
|
||||||
useFocusEffect(
|
|
||||||
useCallback(() => {
|
|
||||||
refresh();
|
|
||||||
navigation.getParent()?.setOptions({
|
|
||||||
headerRight: () => <DrawerMenu name="Home" />,
|
|
||||||
});
|
|
||||||
setImages(!!settings.images);
|
|
||||||
}, [refresh, navigation]),
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
refresh();
|
|
||||||
}, [search, refresh]);
|
|
||||||
|
|
||||||
const renderItem = useCallback(
|
|
||||||
({item}: {item: Set}) => (
|
|
||||||
<SetItem
|
|
||||||
dates={dates}
|
|
||||||
setDates={setDates}
|
|
||||||
images={images}
|
|
||||||
setImages={setImages}
|
|
||||||
item={item}
|
|
||||||
key={item.id}
|
|
||||||
onRemove={refresh}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[refresh, dates, setDates, images, setImages],
|
|
||||||
);
|
|
||||||
|
|
||||||
const next = useCallback(async () => {
|
|
||||||
if (end) return;
|
|
||||||
const newOffset = offset + limit;
|
|
||||||
console.log(`${SetList.name}.next:`, {offset, newOffset, search});
|
|
||||||
const newSets = await getSets({
|
|
||||||
search: `%${search}%`,
|
|
||||||
limit,
|
|
||||||
offset: newOffset,
|
|
||||||
});
|
|
||||||
if (newSets.length === 0) return setEnd(true);
|
|
||||||
if (!sets) return;
|
|
||||||
setSets([...sets, ...newSets]);
|
|
||||||
if (newSets.length < limit) return setEnd(true);
|
|
||||||
setOffset(newOffset);
|
|
||||||
}, [search, end, offset, sets]);
|
|
||||||
|
|
||||||
const onAdd = useCallback(async () => {
|
|
||||||
console.log(`${SetList.name}.onAdd`, {set, defaultSet, workouts});
|
|
||||||
navigation.navigate('EditSet', {
|
|
||||||
set: set || {...defaultSet},
|
|
||||||
workouts,
|
|
||||||
count,
|
|
||||||
});
|
|
||||||
}, [navigation, set, workouts, count]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
|
||||||
<FlatList
|
|
||||||
data={sets}
|
|
||||||
style={{height: '99%'}}
|
|
||||||
ListEmptyComponent={
|
|
||||||
<List.Item
|
|
||||||
title="No sets yet"
|
|
||||||
description="A set is a group of repetitions. E.g. 8 reps of Squats."
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
renderItem={renderItem}
|
|
||||||
keyExtractor={s => s.id!.toString()}
|
|
||||||
onEndReached={next}
|
|
||||||
/>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -27,6 +27,7 @@ export default function SettingsPage() {
|
||||||
const [showUnit, setShowUnit] = useState(!!settings.showUnit);
|
const [showUnit, setShowUnit] = useState(!!settings.showUnit);
|
||||||
const [workouts, setWorkouts] = useState(!!settings.workouts);
|
const [workouts, setWorkouts] = useState(!!settings.workouts);
|
||||||
const [steps, setSteps] = useState(!!settings.steps);
|
const [steps, setSteps] = useState(!!settings.steps);
|
||||||
|
const [focus, setFocus] = useState(settings.focus);
|
||||||
const {color, setColor} = useContext(CustomTheme);
|
const {color, setColor} = useContext(CustomTheme);
|
||||||
const {toast} = useContext(SnackbarContext);
|
const {toast} = useContext(SnackbarContext);
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ export default function SettingsPage() {
|
||||||
color,
|
color,
|
||||||
workouts: +workouts,
|
workouts: +workouts,
|
||||||
steps: +steps,
|
steps: +steps,
|
||||||
|
focus,
|
||||||
});
|
});
|
||||||
getSettings();
|
getSettings();
|
||||||
}, [
|
}, [
|
||||||
|
@ -61,6 +63,7 @@ export default function SettingsPage() {
|
||||||
color,
|
color,
|
||||||
workouts,
|
workouts,
|
||||||
steps,
|
steps,
|
||||||
|
focus,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const changeAlarmEnabled = useCallback(
|
const changeAlarmEnabled = useCallback(
|
||||||
|
@ -173,6 +176,18 @@ export default function SettingsPage() {
|
||||||
{input.name}
|
{input.name}
|
||||||
</Switch>
|
</Switch>
|
||||||
))}
|
))}
|
||||||
|
{'focus'.includes(search.toLowerCase()) && (
|
||||||
|
<Picker
|
||||||
|
style={{color}}
|
||||||
|
dropdownIconColor={color}
|
||||||
|
selectedValue={focus}
|
||||||
|
onValueChange={value => setFocus(value)}>
|
||||||
|
<Picker.Item value="" label="Don't auto focus" />
|
||||||
|
<Picker.Item value="name" label="Auto focus Name" />
|
||||||
|
<Picker.Item value="reps" label="Auto focus Reps" />
|
||||||
|
<Picker.Item value="weight" label="Auto focus Weight" />
|
||||||
|
</Picker>
|
||||||
|
)}
|
||||||
{'theme'.includes(search.toLowerCase()) && (
|
{'theme'.includes(search.toLowerCase()) && (
|
||||||
<Picker
|
<Picker
|
||||||
style={{color}}
|
style={{color}}
|
||||||
|
@ -190,7 +205,9 @@ export default function SettingsPage() {
|
||||||
</Picker>
|
</Picker>
|
||||||
)}
|
)}
|
||||||
{'alarm sound'.includes(search.toLowerCase()) && (
|
{'alarm sound'.includes(search.toLowerCase()) && (
|
||||||
<Button style={{alignSelf: 'flex-start'}} onPress={changeSound}>
|
<Button
|
||||||
|
style={{alignSelf: 'flex-start', marginTop: MARGIN}}
|
||||||
|
onPress={changeSound}>
|
||||||
Alarm sound
|
Alarm sound
|
||||||
{sound
|
{sound
|
||||||
? ': ' + sound.split('/')[sound.split('/').length - 1]
|
? ': ' + sound.split('/')[sound.split('/').length - 1]
|
||||||
|
|
|
@ -12,9 +12,9 @@ import {IconButton} from 'react-native-paper';
|
||||||
import Share from 'react-native-share';
|
import Share from 'react-native-share';
|
||||||
import {captureScreen} from 'react-native-view-shot';
|
import {captureScreen} from 'react-native-view-shot';
|
||||||
import {getVolumes, getWeightsBy} from './best.service';
|
import {getVolumes, getWeightsBy} from './best.service';
|
||||||
import {BestPageParams} from './BestPage';
|
|
||||||
import Chart from './Chart';
|
import Chart from './Chart';
|
||||||
import {PADDING} from './constants';
|
import {PADDING} from './constants';
|
||||||
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
import {Metrics} from './metrics';
|
import {Metrics} from './metrics';
|
||||||
import {Periods} from './periods';
|
import {Periods} from './periods';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
|
@ -22,7 +22,7 @@ import {formatMonth} from './time';
|
||||||
import Volume from './volume';
|
import Volume from './volume';
|
||||||
|
|
||||||
export default function ViewBest() {
|
export default function ViewBest() {
|
||||||
const {params} = useRoute<RouteProp<BestPageParams, 'ViewBest'>>();
|
const {params} = useRoute<RouteProp<DrawerParamList, 'View best'>>();
|
||||||
const dark = useColorScheme() === 'dark';
|
const dark = useColorScheme() === 'dark';
|
||||||
const [weights, setWeights] = useState<Set[]>([]);
|
const [weights, setWeights] = useState<Set[]>([]);
|
||||||
const [volumes, setVolumes] = useState<Volume[]>([]);
|
const [volumes, setVolumes] = useState<Volume[]>([]);
|
||||||
|
|
|
@ -3,9 +3,9 @@ import React, {useCallback, useState} from 'react';
|
||||||
import {GestureResponderEvent, Image} from 'react-native';
|
import {GestureResponderEvent, Image} from 'react-native';
|
||||||
import {List, Menu, Text} from 'react-native-paper';
|
import {List, Menu, Text} from 'react-native-paper';
|
||||||
import ConfirmDialog from './ConfirmDialog';
|
import ConfirmDialog from './ConfirmDialog';
|
||||||
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {deleteSetsBy} from './set.service';
|
import {deleteSetsBy} from './set.service';
|
||||||
import {WorkoutsPageParams} from './WorkoutsPage';
|
|
||||||
|
|
||||||
export default function WorkoutItem({
|
export default function WorkoutItem({
|
||||||
item,
|
item,
|
||||||
|
@ -17,7 +17,7 @@ export default function WorkoutItem({
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
||||||
const [showRemove, setShowRemove] = useState('');
|
const [showRemove, setShowRemove] = useState('');
|
||||||
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
|
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
|
||||||
|
|
||||||
const remove = useCallback(async () => {
|
const remove = useCallback(async () => {
|
||||||
await deleteSetsBy(item.name);
|
await deleteSetsBy(item.name);
|
||||||
|
@ -39,7 +39,7 @@ export default function WorkoutItem({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<List.Item
|
<List.Item
|
||||||
onPress={() => navigation.navigate('EditWorkout', {value: item})}
|
onPress={() => navigation.navigate('Edit workout', {value: item})}
|
||||||
title={item.name}
|
title={item.name}
|
||||||
description={`${item.sets} sets ${minutes}:${seconds} rest`}
|
description={`${item.sets} sets ${minutes}:${seconds} rest`}
|
||||||
onLongPress={longPress}
|
onLongPress={longPress}
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
import {
|
|
||||||
NavigationProp,
|
|
||||||
useFocusEffect,
|
|
||||||
useNavigation,
|
|
||||||
} from '@react-navigation/native';
|
|
||||||
import React, {useCallback, useEffect, useState} from 'react';
|
|
||||||
import {FlatList} from 'react-native';
|
|
||||||
import {List} from 'react-native-paper';
|
|
||||||
import Page from './Page';
|
|
||||||
import Set from './set';
|
|
||||||
import {getDistinctSets} from './set.service';
|
|
||||||
import SetList from './SetList';
|
|
||||||
import WorkoutItem from './WorkoutItem';
|
|
||||||
import {WorkoutsPageParams} from './WorkoutsPage';
|
|
||||||
|
|
||||||
const limit = 15;
|
|
||||||
|
|
||||||
export default function WorkoutList() {
|
|
||||||
const [workouts, setWorkouts] = useState<Set[]>();
|
|
||||||
const [offset, setOffset] = useState(0);
|
|
||||||
const [search, setSearch] = useState('');
|
|
||||||
const [end, setEnd] = useState(false);
|
|
||||||
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
|
|
||||||
|
|
||||||
const refresh = useCallback(async () => {
|
|
||||||
const newWorkouts = await getDistinctSets({
|
|
||||||
search: `%${search}%`,
|
|
||||||
limit,
|
|
||||||
offset: 0,
|
|
||||||
});
|
|
||||||
console.log(`${WorkoutList.name}`, {newWorkout: newWorkouts[0]});
|
|
||||||
setWorkouts(newWorkouts);
|
|
||||||
setOffset(0);
|
|
||||||
setEnd(false);
|
|
||||||
}, [search]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
refresh();
|
|
||||||
}, [search, refresh]);
|
|
||||||
|
|
||||||
useFocusEffect(
|
|
||||||
useCallback(() => {
|
|
||||||
refresh();
|
|
||||||
}, [refresh]),
|
|
||||||
);
|
|
||||||
|
|
||||||
const renderItem = useCallback(
|
|
||||||
({item}: {item: Set}) => (
|
|
||||||
<WorkoutItem item={item} key={item.name} onRemoved={refresh} />
|
|
||||||
),
|
|
||||||
[refresh],
|
|
||||||
);
|
|
||||||
|
|
||||||
const next = useCallback(async () => {
|
|
||||||
if (end) return;
|
|
||||||
const newOffset = offset + limit;
|
|
||||||
console.log(`${SetList.name}.next:`, {
|
|
||||||
offset,
|
|
||||||
limit,
|
|
||||||
newOffset,
|
|
||||||
search,
|
|
||||||
});
|
|
||||||
const newWorkouts = await getDistinctSets({
|
|
||||||
search: `%${search}%`,
|
|
||||||
limit,
|
|
||||||
offset: newOffset,
|
|
||||||
});
|
|
||||||
if (newWorkouts.length === 0) return setEnd(true);
|
|
||||||
if (!workouts) return;
|
|
||||||
setWorkouts([...workouts, ...newWorkouts]);
|
|
||||||
if (newWorkouts.length < limit) return setEnd(true);
|
|
||||||
setOffset(newOffset);
|
|
||||||
}, [search, end, offset, workouts]);
|
|
||||||
|
|
||||||
const onAdd = useCallback(async () => {
|
|
||||||
navigation.navigate('EditWorkout', {
|
|
||||||
value: {name: '', sets: 3, image: '', steps: '', reps: 0, weight: 0},
|
|
||||||
});
|
|
||||||
}, [navigation]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
|
||||||
<FlatList
|
|
||||||
data={workouts}
|
|
||||||
style={{height: '99%'}}
|
|
||||||
ListEmptyComponent={
|
|
||||||
<List.Item
|
|
||||||
title="No workouts yet."
|
|
||||||
description="A workout is something you do at the gym. For example Deadlifts are a workout."
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
renderItem={renderItem}
|
|
||||||
keyExtractor={w => w.name}
|
|
||||||
onEndReached={next}
|
|
||||||
/>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
120
WorkoutsPage.tsx
120
WorkoutsPage.tsx
|
@ -1,43 +1,97 @@
|
||||||
import {DrawerNavigationProp} from '@react-navigation/drawer';
|
import {
|
||||||
import {useNavigation} from '@react-navigation/native';
|
NavigationProp,
|
||||||
import {createStackNavigator} from '@react-navigation/stack';
|
useFocusEffect,
|
||||||
import React from 'react';
|
useNavigation,
|
||||||
import {IconButton} from 'react-native-paper';
|
} from '@react-navigation/native';
|
||||||
|
import React, {useCallback, useEffect, useState} from 'react';
|
||||||
|
import {FlatList} from 'react-native';
|
||||||
|
import {List} from 'react-native-paper';
|
||||||
import {DrawerParamList} from './drawer-param-list';
|
import {DrawerParamList} from './drawer-param-list';
|
||||||
import EditWorkout from './EditWorkout';
|
import Page from './Page';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import WorkoutList from './WorkoutList';
|
import {getDistinctSets} from './set.service';
|
||||||
|
import WorkoutItem from './WorkoutItem';
|
||||||
|
|
||||||
export type WorkoutsPageParams = {
|
const limit = 15;
|
||||||
WorkoutList: {};
|
|
||||||
EditWorkout: {
|
|
||||||
value: Set;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const Stack = createStackNavigator<WorkoutsPageParams>();
|
|
||||||
|
|
||||||
export default function WorkoutsPage() {
|
export default function WorkoutsPage() {
|
||||||
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
|
const [workouts, setWorkouts] = useState<Set[]>();
|
||||||
|
const [offset, setOffset] = useState(0);
|
||||||
|
const [search, setSearch] = useState('');
|
||||||
|
const [end, setEnd] = useState(false);
|
||||||
|
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
|
||||||
|
|
||||||
|
const refresh = useCallback(async () => {
|
||||||
|
const newWorkouts = await getDistinctSets({
|
||||||
|
search: `%${search}%`,
|
||||||
|
limit,
|
||||||
|
offset: 0,
|
||||||
|
});
|
||||||
|
console.log(`${WorkoutsPage.name}`, {newWorkout: newWorkouts[0]});
|
||||||
|
setWorkouts(newWorkouts);
|
||||||
|
setOffset(0);
|
||||||
|
setEnd(false);
|
||||||
|
}, [search]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
refresh();
|
||||||
|
}, [search, refresh]);
|
||||||
|
|
||||||
|
useFocusEffect(
|
||||||
|
useCallback(() => {
|
||||||
|
refresh();
|
||||||
|
}, [refresh]),
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({item}: {item: Set}) => (
|
||||||
|
<WorkoutItem item={item} key={item.name} onRemoved={refresh} />
|
||||||
|
),
|
||||||
|
[refresh],
|
||||||
|
);
|
||||||
|
|
||||||
|
const next = useCallback(async () => {
|
||||||
|
if (end) return;
|
||||||
|
const newOffset = offset + limit;
|
||||||
|
console.log(`${WorkoutsPage.name}.next:`, {
|
||||||
|
offset,
|
||||||
|
limit,
|
||||||
|
newOffset,
|
||||||
|
search,
|
||||||
|
});
|
||||||
|
const newWorkouts = await getDistinctSets({
|
||||||
|
search: `%${search}%`,
|
||||||
|
limit,
|
||||||
|
offset: newOffset,
|
||||||
|
});
|
||||||
|
if (newWorkouts.length === 0) return setEnd(true);
|
||||||
|
if (!workouts) return;
|
||||||
|
setWorkouts([...workouts, ...newWorkouts]);
|
||||||
|
if (newWorkouts.length < limit) return setEnd(true);
|
||||||
|
setOffset(newOffset);
|
||||||
|
}, [search, end, offset, workouts]);
|
||||||
|
|
||||||
|
const onAdd = useCallback(async () => {
|
||||||
|
navigation.navigate('Edit workout', {
|
||||||
|
value: {name: '', sets: 3, image: '', steps: '', reps: 0, weight: 0},
|
||||||
|
});
|
||||||
|
}, [navigation]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator
|
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
||||||
screenOptions={{headerShown: false, animationEnabled: false}}>
|
<FlatList
|
||||||
<Stack.Screen name="WorkoutList" component={WorkoutList} />
|
data={workouts}
|
||||||
<Stack.Screen
|
style={{height: '99%'}}
|
||||||
name="EditWorkout"
|
ListEmptyComponent={
|
||||||
component={EditWorkout}
|
<List.Item
|
||||||
listeners={{
|
title="No workouts yet."
|
||||||
beforeRemove: () => {
|
description="A workout is something you do at the gym. For example Deadlifts are a workout."
|
||||||
navigation.setOptions({
|
|
||||||
headerLeft: () => (
|
|
||||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
|
||||||
),
|
|
||||||
title: 'Workouts',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
}
|
||||||
|
renderItem={renderItem}
|
||||||
|
keyExtractor={w => w.name}
|
||||||
|
onEndReached={next}
|
||||||
|
/>
|
||||||
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
3
db.ts
3
db.ts
|
@ -103,6 +103,9 @@ const migrations = [
|
||||||
`
|
`
|
||||||
ALTER TABLE settings ADD COLUMN nextAlarm TEXT NULL
|
ALTER TABLE settings ADD COLUMN nextAlarm TEXT NULL
|
||||||
`,
|
`,
|
||||||
|
`
|
||||||
|
ALTER TABLE settings ADD COLUMN focus TEXT NULL
|
||||||
|
`,
|
||||||
];
|
];
|
||||||
|
|
||||||
export let db: SQLiteDatabase;
|
export let db: SQLiteDatabase;
|
||||||
|
|
|
@ -1,7 +1,24 @@
|
||||||
|
import {Plan} from './plan';
|
||||||
|
import Set from './set';
|
||||||
|
|
||||||
export type DrawerParamList = {
|
export type DrawerParamList = {
|
||||||
Home: {};
|
Home: {};
|
||||||
Settings: {};
|
Settings: {};
|
||||||
Best: {};
|
Best: {};
|
||||||
Plans: {};
|
Plans: {};
|
||||||
Workouts: {};
|
Workouts: {};
|
||||||
|
'Edit set': {
|
||||||
|
set: Set;
|
||||||
|
workouts: string[];
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
'Edit plan': {
|
||||||
|
plan: Plan;
|
||||||
|
};
|
||||||
|
'Edit workout': {
|
||||||
|
value: Set;
|
||||||
|
};
|
||||||
|
'View best': {
|
||||||
|
best: Set;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
import Set from './set';
|
|
||||||
|
|
||||||
export type HomePageParams = {
|
|
||||||
Sets: {};
|
|
||||||
EditSet: {
|
|
||||||
set: Set;
|
|
||||||
workouts: string[];
|
|
||||||
count: number;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -16,7 +16,6 @@
|
||||||
"@react-native-picker/picker": "^2.4.4",
|
"@react-native-picker/picker": "^2.4.4",
|
||||||
"@react-navigation/drawer": "^6.5.0",
|
"@react-navigation/drawer": "^6.5.0",
|
||||||
"@react-navigation/native": "^6.0.13",
|
"@react-navigation/native": "^6.0.13",
|
||||||
"@react-navigation/stack": "^6.3.0",
|
|
||||||
"@types/d3-shape": "^3.1.0",
|
"@types/d3-shape": "^3.1.0",
|
||||||
"@types/react-native-sqlite-storage": "^5.0.2",
|
"@types/react-native-sqlite-storage": "^5.0.2",
|
||||||
"@types/react-native-svg-charts": "^5.0.12",
|
"@types/react-native-svg-charts": "^5.0.12",
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import {Plan} from './plan';
|
|
||||||
|
|
||||||
export type PlanPageParams = {
|
|
||||||
PlanList: {};
|
|
||||||
EditPlan: {
|
|
||||||
plan: Plan;
|
|
||||||
};
|
|
||||||
};
|
|
2
route.ts
2
route.ts
|
@ -3,5 +3,5 @@ import {DrawerParamList} from './drawer-param-list';
|
||||||
export default interface Route {
|
export default interface Route {
|
||||||
name: keyof DrawerParamList;
|
name: keyof DrawerParamList;
|
||||||
component: React.ComponentType<any>;
|
component: React.ComponentType<any>;
|
||||||
icon: string;
|
icon?: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,4 +10,5 @@ export default interface Settings {
|
||||||
workouts: number;
|
workouts: number;
|
||||||
steps: number;
|
steps: number;
|
||||||
nextAlarm?: string;
|
nextAlarm?: string;
|
||||||
|
focus?: 'name' | 'reps' | 'weight';
|
||||||
}
|
}
|
||||||
|
|
19
yarn.lock
19
yarn.lock
|
@ -2393,24 +2393,6 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@react-navigation/stack@npm:^6.3.0":
|
|
||||||
version: 6.3.0
|
|
||||||
resolution: "@react-navigation/stack@npm:6.3.0"
|
|
||||||
dependencies:
|
|
||||||
"@react-navigation/elements": ^1.3.6
|
|
||||||
color: ^4.2.3
|
|
||||||
warn-once: ^0.1.0
|
|
||||||
peerDependencies:
|
|
||||||
"@react-navigation/native": ^6.0.0
|
|
||||||
react: "*"
|
|
||||||
react-native: "*"
|
|
||||||
react-native-gesture-handler: ">= 1.0.0"
|
|
||||||
react-native-safe-area-context: ">= 3.0.0"
|
|
||||||
react-native-screens: ">= 3.0.0"
|
|
||||||
checksum: fac540297b827249317e1383b6b4d47b3f356e6d20f8e9acadfb5ce5973faf63e56b74b18846837031c15264fc37518701aae16efcf9b8131d22b66f47c19d14
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@sideway/address@npm:^4.1.3":
|
"@sideway/address@npm:^4.1.3":
|
||||||
version: 4.1.4
|
version: 4.1.4
|
||||||
resolution: "@sideway/address@npm:4.1.4"
|
resolution: "@sideway/address@npm:4.1.4"
|
||||||
|
@ -6434,7 +6416,6 @@ __metadata:
|
||||||
"@react-native-picker/picker": ^2.4.4
|
"@react-native-picker/picker": ^2.4.4
|
||||||
"@react-navigation/drawer": ^6.5.0
|
"@react-navigation/drawer": ^6.5.0
|
||||||
"@react-navigation/native": ^6.0.13
|
"@react-navigation/native": ^6.0.13
|
||||||
"@react-navigation/stack": ^6.3.0
|
|
||||||
"@types/d3-shape": ^3.1.0
|
"@types/d3-shape": ^3.1.0
|
||||||
"@types/react-native": ^0.69.0
|
"@types/react-native": ^0.69.0
|
||||||
"@types/react-native-sqlite-storage": ^5.0.2
|
"@types/react-native-sqlite-storage": ^5.0.2
|
||||||
|
|
Loading…
Reference in New Issue
Block a user