parent
1bd05e1c20
commit
85dd2b6d17
|
@ -53,7 +53,8 @@ export default function EditPlan() {
|
||||||
if (!days || !workouts) return;
|
if (!days || !workouts) return;
|
||||||
const newWorkouts = workouts.filter(workout => workout).join(',');
|
const newWorkouts = workouts.filter(workout => workout).join(',');
|
||||||
const newDays = days.filter(day => day).join(',');
|
const newDays = days.filter(day => day).join(',');
|
||||||
if (!plan.id) await addPlan({days: newDays, workouts: newWorkouts});
|
if (typeof plan.id === 'undefined')
|
||||||
|
await addPlan({days: newDays, workouts: newWorkouts});
|
||||||
else
|
else
|
||||||
await updatePlan({
|
await updatePlan({
|
||||||
days: newDays,
|
days: newDays,
|
||||||
|
|
15
EditSet.tsx
15
EditSet.tsx
|
@ -22,20 +22,22 @@ export default function EditSet() {
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
|
console.log(`${EditSet.name}.focus:`, params);
|
||||||
navigation.getParent()?.setOptions({
|
navigation.getParent()?.setOptions({
|
||||||
headerLeft: () => (
|
headerLeft: () => (
|
||||||
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
||||||
),
|
),
|
||||||
headerRight: null,
|
headerRight: null,
|
||||||
title: params.set.id ? 'Edit set' : 'Create set',
|
title: typeof params.set.id === 'number' ? 'Edit set' : 'Create set',
|
||||||
});
|
});
|
||||||
}, [navigation, params.set.id]),
|
}, [navigation, params]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const startTimer = useCallback(async () => {
|
const startTimer = useCallback(async (set: Set) => {
|
||||||
const settings = await getSettings();
|
const settings = await getSettings();
|
||||||
if (!settings.alarm) return;
|
if (!settings.alarm) return;
|
||||||
const milliseconds = settings.minutes * 60 * 1000 + settings.seconds * 1000;
|
const milliseconds =
|
||||||
|
Number(set.minutes) * 60 * 1000 + Number(set.seconds) * 1000;
|
||||||
NativeModules.AlarmModule.timer(
|
NativeModules.AlarmModule.timer(
|
||||||
milliseconds,
|
milliseconds,
|
||||||
!!settings.vibrate,
|
!!settings.vibrate,
|
||||||
|
@ -54,7 +56,8 @@ export default function EditSet() {
|
||||||
|
|
||||||
const add = useCallback(
|
const add = useCallback(
|
||||||
async (set: Set) => {
|
async (set: Set) => {
|
||||||
startTimer();
|
console.log(`${EditSet.name}.add`, {set});
|
||||||
|
startTimer(set);
|
||||||
await addSet(set);
|
await addSet(set);
|
||||||
const settings = await getSettings();
|
const settings = await getSettings();
|
||||||
if (settings.notify === 0) return navigation.goBack();
|
if (settings.notify === 0) return navigation.goBack();
|
||||||
|
@ -70,7 +73,7 @@ export default function EditSet() {
|
||||||
|
|
||||||
const save = useCallback(
|
const save = useCallback(
|
||||||
async (set: Set) => {
|
async (set: Set) => {
|
||||||
if (params.set.id) return update(set);
|
if (typeof params.set.id === 'number') return update(set);
|
||||||
return add(set);
|
return add(set);
|
||||||
},
|
},
|
||||||
[update, add, params.set.id],
|
[update, add, params.set.id],
|
||||||
|
|
|
@ -11,20 +11,28 @@ 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 MassiveInput from './MassiveInput';
|
import MassiveInput from './MassiveInput';
|
||||||
import {updateWorkouts} from './plan.service';
|
import {updatePlanWorkouts} from './plan.service';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {addSet, getSets, updateSetImage, updateSetName} from './set.service';
|
import {addSet, getSets, updateManySet, updateSetImage} from './set.service';
|
||||||
import Workout from './workout';
|
import Workout from './workout';
|
||||||
import {addWorkout, getWorkout, updateSteps} from './workout.service';
|
import {
|
||||||
|
addWorkout,
|
||||||
|
getWorkout,
|
||||||
|
updateName,
|
||||||
|
updateSteps,
|
||||||
|
} from './workout.service';
|
||||||
import {WorkoutsPageParams} from './WorkoutsPage';
|
import {WorkoutsPageParams} from './WorkoutsPage';
|
||||||
|
|
||||||
export default function EditWorkout() {
|
export default function EditWorkout() {
|
||||||
const [name, setName] = useState('');
|
const {params} = useRoute<RouteProp<WorkoutsPageParams, 'EditWorkout'>>();
|
||||||
|
const [name, setName] = useState(params.value.name);
|
||||||
const [removeImage, setRemoveImage] = useState(false);
|
const [removeImage, setRemoveImage] = useState(false);
|
||||||
const [showRemove, setShowRemove] = useState(false);
|
const [showRemove, setShowRemove] = useState(false);
|
||||||
const [steps, setSteps] = useState('');
|
const [steps, setSteps] = useState('');
|
||||||
const [uri, setUri] = useState<string>();
|
const [uri, setUri] = useState<string>();
|
||||||
const {params} = useRoute<RouteProp<WorkoutsPageParams, 'EditWorkout'>>();
|
const [minutes, setMinutes] = useState('');
|
||||||
|
const [seconds, setSeconds] = useState('');
|
||||||
|
const [sets, setSets] = useState('');
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
|
@ -37,39 +45,60 @@ export default function EditWorkout() {
|
||||||
title: params.value.name ? params.value.name : 'New workout',
|
title: params.value.name ? params.value.name : 'New workout',
|
||||||
});
|
});
|
||||||
if (!params.value.name) return;
|
if (!params.value.name) return;
|
||||||
getSets({search: params.value.name, limit: 1, offset: 0}).then(sets =>
|
getSets({search: params.value.name, limit: 1, offset: 0}).then(
|
||||||
setUri(sets[0]?.image),
|
([set]) => {
|
||||||
|
if (!set) return;
|
||||||
|
setUri(set.image);
|
||||||
|
setMinutes(set.minutes?.toString() ?? '3');
|
||||||
|
setSeconds(set.seconds?.toString() ?? '30');
|
||||||
|
setSets(set.sets?.toString() ?? '3');
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
console.log(`${EditWorkout.name}.focus`, {params});
|
||||||
getWorkout(params.value.name).then(workout => setSteps(workout.steps));
|
getWorkout(params.value.name).then(workout => setSteps(workout.steps));
|
||||||
}, [navigation, params.value.name]),
|
}, [navigation, params]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const update = useCallback(async () => {
|
const update = async () => {
|
||||||
console.log(`${EditWorkout.name}.update`, {
|
console.log(`${EditWorkout.name}.update`, {
|
||||||
params: params.value.name,
|
params: params.value.name,
|
||||||
name,
|
name,
|
||||||
uri,
|
uri,
|
||||||
steps,
|
steps,
|
||||||
});
|
});
|
||||||
if (name) {
|
await updateManySet({
|
||||||
await updateSetName(params.value.name, name);
|
oldName: params.value.name,
|
||||||
await updateWorkouts(params.value.name, name);
|
newName: name || params.value.name,
|
||||||
}
|
sets,
|
||||||
|
seconds,
|
||||||
|
minutes,
|
||||||
|
});
|
||||||
|
await updatePlanWorkouts(params.value.name, name || params.value.name);
|
||||||
|
await updateName(params.value.name, name);
|
||||||
if (uri || removeImage) await updateSetImage(params.value.name, uri || '');
|
if (uri || removeImage) await updateSetImage(params.value.name, uri || '');
|
||||||
if (steps) await updateSteps(params.value.name, steps);
|
if (steps) await updateSteps(params.value.name, steps);
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
}, [navigation, params.value.name, name, uri, steps, removeImage]);
|
};
|
||||||
|
|
||||||
const add = useCallback(async () => {
|
const add = async () => {
|
||||||
await addSet({name, reps: 0, weight: 0, hidden: true, image: uri} as Set);
|
await addSet({
|
||||||
await addWorkout({name, steps} as Workout);
|
name,
|
||||||
|
reps: 0,
|
||||||
|
weight: 0,
|
||||||
|
hidden: true,
|
||||||
|
image: uri,
|
||||||
|
minutes: +minutes,
|
||||||
|
seconds: +seconds,
|
||||||
|
sets: +sets,
|
||||||
|
} as Set);
|
||||||
|
addWorkout({name, steps} as Workout);
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
}, [navigation, name, steps, uri]);
|
};
|
||||||
|
|
||||||
const save = useCallback(async () => {
|
const save = async () => {
|
||||||
if (params.value.name) return update();
|
if (params.value.name) return update();
|
||||||
return add();
|
return add();
|
||||||
}, [update, add, params.value.name]);
|
};
|
||||||
|
|
||||||
const changeImage = useCallback(async () => {
|
const changeImage = useCallback(async () => {
|
||||||
const {fileCopyUri} = await DocumentPicker.pickSingle({
|
const {fileCopyUri} = await DocumentPicker.pickSingle({
|
||||||
|
@ -88,11 +117,7 @@ export default function EditWorkout() {
|
||||||
return (
|
return (
|
||||||
<View style={{padding: PADDING}}>
|
<View style={{padding: PADDING}}>
|
||||||
<ScrollView style={{height: '90%'}}>
|
<ScrollView style={{height: '90%'}}>
|
||||||
<MassiveInput
|
<MassiveInput label="Name" value={name} onChangeText={setName} />
|
||||||
label={params.value.name || 'Name'}
|
|
||||||
value={name}
|
|
||||||
onChangeText={setName}
|
|
||||||
/>
|
|
||||||
<MassiveInput
|
<MassiveInput
|
||||||
selectTextOnFocus={false}
|
selectTextOnFocus={false}
|
||||||
value={steps}
|
value={steps}
|
||||||
|
@ -100,6 +125,24 @@ export default function EditWorkout() {
|
||||||
label="Steps"
|
label="Steps"
|
||||||
multiline
|
multiline
|
||||||
/>
|
/>
|
||||||
|
<MassiveInput
|
||||||
|
value={sets}
|
||||||
|
onChangeText={setSets}
|
||||||
|
label="Sets per workout"
|
||||||
|
keyboardType="numeric"
|
||||||
|
/>
|
||||||
|
<MassiveInput
|
||||||
|
value={minutes}
|
||||||
|
onChangeText={setMinutes}
|
||||||
|
label="Rest minutes"
|
||||||
|
keyboardType="numeric"
|
||||||
|
/>
|
||||||
|
<MassiveInput
|
||||||
|
value={seconds}
|
||||||
|
onChangeText={setSeconds}
|
||||||
|
label="Rest seconds"
|
||||||
|
keyboardType="numeric"
|
||||||
|
/>
|
||||||
{uri ? (
|
{uri ? (
|
||||||
<TouchableRipple
|
<TouchableRipple
|
||||||
style={{marginBottom: MARGIN}}
|
style={{marginBottom: MARGIN}}
|
||||||
|
|
|
@ -18,7 +18,7 @@ export default function PlanItem({
|
||||||
const navigation = useNavigation<NavigationProp<PlanPageParams>>();
|
const navigation = useNavigation<NavigationProp<PlanPageParams>>();
|
||||||
|
|
||||||
const remove = useCallback(async () => {
|
const remove = useCallback(async () => {
|
||||||
if (item.id) await deletePlan(item.id);
|
if (typeof item.id === 'number') await deletePlan(item.id);
|
||||||
setShow(false);
|
setShow(false);
|
||||||
onRemove();
|
onRemove();
|
||||||
}, [setShow, item.id, onRemove]);
|
}, [setShow, item.id, onRemove]);
|
||||||
|
|
|
@ -43,7 +43,7 @@ export default function PlanList() {
|
||||||
);
|
);
|
||||||
|
|
||||||
const onAdd = () =>
|
const onAdd = () =>
|
||||||
navigation.navigate('EditPlan', {plan: {days: '', workouts: '', id: 0}});
|
navigation.navigate('EditPlan', {plan: {days: '', workouts: ''}});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
||||||
|
|
61
SetForm.tsx
61
SetForm.tsx
|
@ -1,6 +1,6 @@
|
||||||
import React, {useEffect, useRef, useState} from 'react';
|
import React, {useEffect, useRef, useState} from 'react';
|
||||||
import {ScrollView} from 'react-native';
|
import {ScrollView, View} from 'react-native';
|
||||||
import {Button, Text} from 'react-native-paper';
|
import {Button} from 'react-native-paper';
|
||||||
import {MARGIN} from './constants';
|
import {MARGIN} from './constants';
|
||||||
import MassiveInput from './MassiveInput';
|
import MassiveInput from './MassiveInput';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
|
@ -20,18 +20,23 @@ export default function SetForm({
|
||||||
const [weight, setWeight] = useState(set.weight.toString());
|
const [weight, setWeight] = useState(set.weight.toString());
|
||||||
const [unit, setUnit] = useState(set.unit);
|
const [unit, setUnit] = useState(set.unit);
|
||||||
const [uri, setUri] = useState(set.image);
|
const [uri, setUri] = useState(set.image);
|
||||||
|
const [minutes, setMinutes] = useState(set.minutes?.toString());
|
||||||
|
const [seconds, setSeconds] = useState(set.seconds?.toString());
|
||||||
const [selection, setSelection] = useState({
|
const [selection, setSelection] = useState({
|
||||||
start: 0,
|
start: 0,
|
||||||
end: set.reps.toString().length,
|
end: set.reps.toString().length,
|
||||||
});
|
});
|
||||||
const weightRef = useRef<any>(null);
|
const weightRef = useRef<any>(null);
|
||||||
const repsRef = useRef<any>(null);
|
const repsRef = useRef<any>(null);
|
||||||
|
const unitRef = useRef<any>(null);
|
||||||
|
const minutesRef = useRef<any>(null);
|
||||||
|
const secondsRef = useRef<any>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('SetForm.useEffect:', {uri, name: set.name});
|
console.log('SetForm.useEffect:', {uri, name: set.name});
|
||||||
if (!uri)
|
if (!uri)
|
||||||
getSets({search: set.name, limit: 1, offset: 0}).then(sets =>
|
getSets({search: set.name, limit: 1, offset: 0}).then(([s]) =>
|
||||||
setUri(sets[0]?.image),
|
setUri(s?.image),
|
||||||
);
|
);
|
||||||
}, [uri, set.name]);
|
}, [uri, set.name]);
|
||||||
|
|
||||||
|
@ -44,6 +49,9 @@ export default function SetForm({
|
||||||
id: set.id,
|
id: set.id,
|
||||||
unit,
|
unit,
|
||||||
image: uri,
|
image: uri,
|
||||||
|
minutes: Number(minutes ?? 3),
|
||||||
|
seconds: Number(seconds ?? 30),
|
||||||
|
sets: set.sets ?? 3,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,7 +83,7 @@ export default function SetForm({
|
||||||
keyboardType="numeric"
|
keyboardType="numeric"
|
||||||
value={weight}
|
value={weight}
|
||||||
onChangeText={setWeight}
|
onChangeText={setWeight}
|
||||||
onSubmitEditing={handleSubmit}
|
onSubmitEditing={() => unitRef.current?.focus()}
|
||||||
innerRef={weightRef}
|
innerRef={weightRef}
|
||||||
/>
|
/>
|
||||||
<MassiveInput
|
<MassiveInput
|
||||||
|
@ -83,22 +91,35 @@ export default function SetForm({
|
||||||
label="Unit"
|
label="Unit"
|
||||||
value={unit}
|
value={unit}
|
||||||
onChangeText={setUnit}
|
onChangeText={setUnit}
|
||||||
onSubmitEditing={handleSubmit}
|
onSubmitEditing={() => minutesRef.current?.focus()}
|
||||||
|
innerRef={unitRef}
|
||||||
/>
|
/>
|
||||||
<Text style={{marginBottom: MARGIN}}>
|
{workouts && (
|
||||||
{workouts?.map((workout, index) => (
|
<MassiveInput
|
||||||
<React.Fragment key={workout}>
|
label="Todays workout"
|
||||||
<Text
|
value={workouts?.join(', ')}
|
||||||
style={{
|
editable={false}
|
||||||
fontWeight: workout === name ? 'bold' : 'normal',
|
/>
|
||||||
textDecorationLine: workout === name ? 'underline' : 'none',
|
)}
|
||||||
}}>
|
{!set.id && (
|
||||||
{workout}
|
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
|
||||||
</Text>
|
<MassiveInput
|
||||||
{index === workouts.length - 1 ? '.' : ', '}
|
style={{width: '48%'}}
|
||||||
</React.Fragment>
|
label="Rest minutes"
|
||||||
))}
|
value={minutes}
|
||||||
</Text>
|
onChangeText={setMinutes}
|
||||||
|
innerRef={minutesRef}
|
||||||
|
onSubmitEditing={() => secondsRef.current?.focus()}
|
||||||
|
/>
|
||||||
|
<MassiveInput
|
||||||
|
style={{width: '48%', marginLeft: MARGIN}}
|
||||||
|
label="Rest seconds"
|
||||||
|
value={seconds}
|
||||||
|
onChangeText={setSeconds}
|
||||||
|
innerRef={secondsRef}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
<Button
|
<Button
|
||||||
disabled={!name}
|
disabled={!name}
|
||||||
|
|
|
@ -26,14 +26,14 @@ export default function SetItem({
|
||||||
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
||||||
|
|
||||||
const remove = useCallback(async () => {
|
const remove = useCallback(async () => {
|
||||||
await deleteSet(item.id);
|
if (typeof item.id === 'number') await deleteSet(item.id);
|
||||||
setShowMenu(false);
|
setShowMenu(false);
|
||||||
onRemove();
|
onRemove();
|
||||||
}, [setShowMenu, onRemove, item.id]);
|
}, [setShowMenu, onRemove, item.id]);
|
||||||
|
|
||||||
const copy = useCallback(() => {
|
const copy = useCallback(() => {
|
||||||
const set: Set = {...item};
|
const set: Set = {...item};
|
||||||
set.id = 0;
|
delete set.id;
|
||||||
setShowMenu(false);
|
setShowMenu(false);
|
||||||
navigation.navigate('EditSet', {set});
|
navigation.navigate('EditSet', {set});
|
||||||
}, [navigation, item]);
|
}, [navigation, item]);
|
||||||
|
|
15
SetList.tsx
15
SetList.tsx
|
@ -31,6 +31,7 @@ export default function SetList() {
|
||||||
|
|
||||||
const refresh = useCallback(async () => {
|
const refresh = useCallback(async () => {
|
||||||
const newSets = await getSets({search: `%${search}%`, limit, offset: 0});
|
const newSets = await getSets({search: `%${search}%`, limit, offset: 0});
|
||||||
|
console.log(`${SetList.name}.refresh:`, {newSets});
|
||||||
if (newSets.length === 0) return setSets([]);
|
if (newSets.length === 0) return setSets([]);
|
||||||
setSets(newSets);
|
setSets(newSets);
|
||||||
setOffset(0);
|
setOffset(0);
|
||||||
|
@ -50,20 +51,22 @@ export default function SetList() {
|
||||||
const todaysSets = await getTodaysSets();
|
const todaysSets = await getTodaysSets();
|
||||||
const todaysWorkouts = todaysPlan[0].workouts.split(',');
|
const todaysWorkouts = todaysPlan[0].workouts.split(',');
|
||||||
let workout = todaysWorkouts[0];
|
let workout = todaysWorkouts[0];
|
||||||
console.log(`${SetList.name}.predict:`, {todaysSets});
|
console.log(`${SetList.name}.predict:`, {todaysSet: todaysSets[0]});
|
||||||
console.log(`${SetList.name}.predict:`, {todaysWorkouts});
|
console.log(`${SetList.name}.predict:`, {todaysWorkouts});
|
||||||
|
let best = await getBestSet(workout);
|
||||||
if (todaysWorkouts.includes(todaysSets[0]?.name) && todaysSets.length > 0) {
|
if (todaysWorkouts.includes(todaysSets[0]?.name) && todaysSets.length > 0) {
|
||||||
const count = todaysSets.filter(
|
const count = todaysSets.filter(
|
||||||
s => s.name === todaysSets[0].name,
|
s => s.name === todaysSets[0].name,
|
||||||
).length;
|
).length;
|
||||||
workout = todaysSets[0].name;
|
workout = todaysSets[0].name;
|
||||||
if (count >= Number(settings.sets))
|
best = await getBestSet(workout);
|
||||||
workout =
|
if (count >= Number(best.sets))
|
||||||
todaysWorkouts[todaysWorkouts.indexOf(todaysSets[0].name!) + 1];
|
best = await getBestSet(
|
||||||
|
todaysWorkouts[todaysWorkouts.indexOf(todaysSets[0].name!) + 1],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
console.log(`${SetList.name}.predict:`, {workout});
|
console.log(`${SetList.name}.predict:`, {workout});
|
||||||
const best = await getBestSet(workout);
|
console.log(`${SetList.name}.predict:`, {best});
|
||||||
console.log(`${SetList.name}.predict:`, {bestName: best.name});
|
|
||||||
setSet({...best});
|
setSet({...best});
|
||||||
setWorkouts(todaysWorkouts);
|
setWorkouts(todaysWorkouts);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
|
@ -4,7 +4,6 @@ import DocumentPicker from 'react-native-document-picker';
|
||||||
import {Button, Text} from 'react-native-paper';
|
import {Button, Text} from 'react-native-paper';
|
||||||
import ConfirmDialog from './ConfirmDialog';
|
import ConfirmDialog from './ConfirmDialog';
|
||||||
import {MARGIN} from './constants';
|
import {MARGIN} from './constants';
|
||||||
import MassiveInput from './MassiveInput';
|
|
||||||
import {SnackbarContext} from './MassiveSnack';
|
import {SnackbarContext} from './MassiveSnack';
|
||||||
import MassiveSwitch from './MassiveSwitch';
|
import MassiveSwitch from './MassiveSwitch';
|
||||||
import Page from './Page';
|
import Page from './Page';
|
||||||
|
@ -18,9 +17,6 @@ interface Input<T> {
|
||||||
|
|
||||||
export default function SettingsPage() {
|
export default function SettingsPage() {
|
||||||
const [vibrate, setVibrate] = useState(true);
|
const [vibrate, setVibrate] = useState(true);
|
||||||
const [minutes, setMinutes] = useState<string>('');
|
|
||||||
const [sets, setSets] = useState<string>('3');
|
|
||||||
const [seconds, setSeconds] = useState<string>('');
|
|
||||||
const [alarm, setAlarm] = useState(false);
|
const [alarm, setAlarm] = useState(false);
|
||||||
const [predict, setPredict] = useState(false);
|
const [predict, setPredict] = useState(false);
|
||||||
const [sound, setSound] = useState<string>('');
|
const [sound, setSound] = useState<string>('');
|
||||||
|
@ -34,11 +30,8 @@ export default function SettingsPage() {
|
||||||
const refresh = useCallback(async () => {
|
const refresh = useCallback(async () => {
|
||||||
const settings = await getSettings();
|
const settings = await getSettings();
|
||||||
console.log('SettingsPage.refresh:', {settings});
|
console.log('SettingsPage.refresh:', {settings});
|
||||||
setMinutes(settings.minutes.toString());
|
|
||||||
setSeconds(settings.seconds.toString());
|
|
||||||
setAlarm(!!settings.alarm);
|
setAlarm(!!settings.alarm);
|
||||||
setPredict(!!settings.predict);
|
setPredict(!!settings.predict);
|
||||||
setSets(settings.sets.toString());
|
|
||||||
setVibrate(!!settings.vibrate);
|
setVibrate(!!settings.vibrate);
|
||||||
setSound(settings.sound);
|
setSound(settings.sound);
|
||||||
setNotify(!!settings.notify);
|
setNotify(!!settings.notify);
|
||||||
|
@ -53,16 +46,13 @@ export default function SettingsPage() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateSettings({
|
updateSettings({
|
||||||
vibrate: +vibrate,
|
vibrate: +vibrate,
|
||||||
minutes: +minutes,
|
|
||||||
seconds: +seconds,
|
|
||||||
alarm: +alarm,
|
alarm: +alarm,
|
||||||
predict: +predict,
|
predict: +predict,
|
||||||
sound,
|
sound,
|
||||||
notify: +notify,
|
notify: +notify,
|
||||||
images: +images,
|
images: +images,
|
||||||
sets: +sets,
|
|
||||||
});
|
});
|
||||||
}, [vibrate, minutes, sets, seconds, alarm, predict, sound, notify, images]);
|
}, [vibrate, alarm, predict, sound, notify, images]);
|
||||||
|
|
||||||
const changeAlarmEnabled = useCallback(
|
const changeAlarmEnabled = useCallback(
|
||||||
(enabled: boolean) => {
|
(enabled: boolean) => {
|
||||||
|
@ -120,12 +110,6 @@ export default function SettingsPage() {
|
||||||
[toast],
|
[toast],
|
||||||
);
|
);
|
||||||
|
|
||||||
const inputs: Input<string>[] = [
|
|
||||||
{name: 'Sets per workout', value: sets, onChange: setSets},
|
|
||||||
{name: 'Rest minutes', value: minutes, onChange: setMinutes},
|
|
||||||
{name: 'Rest seconds', value: seconds, onChange: setSeconds},
|
|
||||||
];
|
|
||||||
|
|
||||||
const switches: Input<boolean>[] = [
|
const switches: Input<boolean>[] = [
|
||||||
{name: 'Rest timers', value: alarm, onChange: changeAlarmEnabled},
|
{name: 'Rest timers', value: alarm, onChange: changeAlarmEnabled},
|
||||||
{name: 'Vibrate', value: vibrate, onChange: changeVibrate},
|
{name: 'Vibrate', value: vibrate, onChange: changeVibrate},
|
||||||
|
@ -136,20 +120,7 @@ export default function SettingsPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page search={search} setSearch={setSearch}>
|
<Page search={search} setSearch={setSearch}>
|
||||||
<ScrollView style={{marginTop: MARGIN}}>
|
<ScrollView style={{margin: MARGIN}}>
|
||||||
{inputs
|
|
||||||
.filter(input =>
|
|
||||||
input.name.toLowerCase().includes(search.toLowerCase()),
|
|
||||||
)
|
|
||||||
.map(input => (
|
|
||||||
<MassiveInput
|
|
||||||
key={input.name}
|
|
||||||
label={input.name}
|
|
||||||
value={input.value}
|
|
||||||
keyboardType="numeric"
|
|
||||||
onChangeText={input.onChange}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
{switches
|
{switches
|
||||||
.filter(input =>
|
.filter(input =>
|
||||||
input.name.toLowerCase().includes(search.toLowerCase()),
|
input.name.toLowerCase().includes(search.toLowerCase()),
|
||||||
|
@ -165,7 +136,7 @@ export default function SettingsPage() {
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
{'alarm sound'.includes(search.toLowerCase()) && (
|
{'alarm sound'.includes(search.toLowerCase()) && (
|
||||||
<Button onPress={changeSound}>
|
<Button style={{alignSelf: 'flex-start'}} onPress={changeSound}>
|
||||||
Alarm sound
|
Alarm sound
|
||||||
{sound
|
{sound
|
||||||
? ': ' + sound.split('/')[sound.split('/').length - 1]
|
? ': ' + sound.split('/')[sound.split('/').length - 1]
|
||||||
|
|
|
@ -35,11 +35,15 @@ export default function WorkoutItem({
|
||||||
[setShowMenu, setAnchor],
|
[setShowMenu, setAnchor],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const minutes = item.minutes.toString().padStart(2, '0');
|
||||||
|
const seconds = item.seconds.toString().padStart(2, '0');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<List.Item
|
<List.Item
|
||||||
onPress={() => navigation.navigate('EditWorkout', {value: item})}
|
onPress={() => navigation.navigate('EditWorkout', {value: item})}
|
||||||
title={item.name}
|
title={item.name}
|
||||||
|
description={`${item.sets} sets with ${minutes}:${seconds} rest`}
|
||||||
onLongPress={longPress}
|
onLongPress={longPress}
|
||||||
left={() =>
|
left={() =>
|
||||||
item.image && (
|
item.image && (
|
||||||
|
|
|
@ -73,7 +73,7 @@ export default function WorkoutList() {
|
||||||
|
|
||||||
const onAdd = useCallback(async () => {
|
const onAdd = useCallback(async () => {
|
||||||
navigation.navigate('EditWorkout', {
|
navigation.navigate('EditWorkout', {
|
||||||
value: {name: '', sets: 3, image: '', steps: ''},
|
value: {name: '', sets: 3, image: '', steps: ''} as Workout,
|
||||||
});
|
});
|
||||||
}, [navigation]);
|
}, [navigation]);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const getBestSet = async (name: string): Promise<Set> => {
|
||||||
GROUP BY name;
|
GROUP BY name;
|
||||||
`;
|
`;
|
||||||
const bestReps = `
|
const bestReps = `
|
||||||
SELECT name, MAX(reps) as reps, unit, weight
|
SELECT name, MAX(reps) as reps, unit, weight, sets, minutes, seconds
|
||||||
FROM sets
|
FROM sets
|
||||||
WHERE name = ? AND weight = ? AND NOT hidden
|
WHERE name = ? AND weight = ? AND NOT hidden
|
||||||
GROUP BY name;
|
GROUP BY name;
|
||||||
|
|
30
db.ts
30
db.ts
|
@ -79,6 +79,30 @@ const insertWorkouts = `
|
||||||
INSERT OR IGNORE INTO workouts (name) SELECT DISTINCT name FROM sets;
|
INSERT OR IGNORE INTO workouts (name) SELECT DISTINCT name FROM sets;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const removeSeconds = `
|
||||||
|
ALTER TABLE settings DROP COLUMN seconds
|
||||||
|
`;
|
||||||
|
|
||||||
|
const removeMinutes = `
|
||||||
|
ALTER TABLE settings DROP COLUMN minutes
|
||||||
|
`;
|
||||||
|
|
||||||
|
const removeSets = `
|
||||||
|
ALTER TABLE settings DROP COLUMN sets
|
||||||
|
`;
|
||||||
|
|
||||||
|
const addSets = `
|
||||||
|
ALTER TABLE sets ADD COLUMN sets INTEGER NOT NULL DEFAULT 3
|
||||||
|
`;
|
||||||
|
|
||||||
|
const addMinutes = `
|
||||||
|
ALTER TABLE sets ADD COLUMN minutes INTEGER NOT NULL DEFAULT 3
|
||||||
|
`;
|
||||||
|
|
||||||
|
const addSeconds = `
|
||||||
|
ALTER TABLE sets ADD COLUMN seconds INTEGER NOT NULL DEFAULT 30
|
||||||
|
`;
|
||||||
|
|
||||||
export let db: SQLiteDatabase;
|
export let db: SQLiteDatabase;
|
||||||
|
|
||||||
export const migrations = async () => {
|
export const migrations = async () => {
|
||||||
|
@ -94,6 +118,12 @@ export const migrations = async () => {
|
||||||
await db.executeSql(addImages).catch(() => null);
|
await db.executeSql(addImages).catch(() => null);
|
||||||
await db.executeSql(addSteps).catch(() => null);
|
await db.executeSql(addSteps).catch(() => null);
|
||||||
await db.executeSql(insertWorkouts).catch(() => null);
|
await db.executeSql(insertWorkouts).catch(() => null);
|
||||||
|
await db.executeSql(removeSeconds).catch(() => null);
|
||||||
|
await db.executeSql(removeMinutes).catch(() => null);
|
||||||
|
await db.executeSql(removeSets).catch(() => null);
|
||||||
|
await db.executeSql(addSets).catch(() => null);
|
||||||
|
await db.executeSql(addMinutes).catch(() => null);
|
||||||
|
await db.executeSql(addSeconds).catch(() => null);
|
||||||
const [result] = await db.executeSql(selectSettings);
|
const [result] = await db.executeSql(selectSettings);
|
||||||
if (result.rows.length === 0) await db.executeSql(insertSettings);
|
if (result.rows.length === 0) await db.executeSql(insertSettings);
|
||||||
};
|
};
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 84 KiB |
Binary file not shown.
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 87 KiB |
BIN
metadata/en-US/images/phoneScreenshots/workout.png
Normal file
BIN
metadata/en-US/images/phoneScreenshots/workout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
|
@ -20,7 +20,7 @@ export const getTodaysPlan = async (): Promise<Plan[]> => {
|
||||||
return result.rows.raw();
|
return result.rows.raw();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateWorkouts = async (oldName: string, newName: string) => {
|
export const updatePlanWorkouts = async (oldName: string, newName: string) => {
|
||||||
const update = `
|
const update = `
|
||||||
UPDATE plans SET workouts = REPLACE(workouts, ?, ?)
|
UPDATE plans SET workouts = REPLACE(workouts, ?, ?)
|
||||||
WHERE workouts LIKE ?
|
WHERE workouts LIKE ?
|
||||||
|
|
|
@ -26,12 +26,14 @@ export const addSets = async (values: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addSet = async (value: Set) => {
|
export const addSet = async (value: Set) => {
|
||||||
|
const keys = Object.keys(value) as (keyof Set)[];
|
||||||
|
const questions = keys.map(() => '?').join(',');
|
||||||
const insert = `
|
const insert = `
|
||||||
INSERT INTO sets(name, reps, weight, created, unit, image)
|
INSERT INTO sets(${keys.join(',')},created)
|
||||||
VALUES (?,?,?,strftime('%Y-%m-%dT%H:%M:%S', 'now', 'localtime'),?, ?)
|
VALUES (${questions},strftime('%Y-%m-%dT%H:%M:%S','now','localtime'))
|
||||||
`;
|
`;
|
||||||
const {name, reps, weight, unit, image} = value;
|
const values = keys.map(key => value[key]);
|
||||||
return db.executeSql(insert, [name, reps, weight, unit, image]);
|
return db.executeSql(insert, values);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteSets = async () => {
|
export const deleteSets = async () => {
|
||||||
|
@ -90,9 +92,24 @@ export const defaultSet = {
|
||||||
unit: 'kg',
|
unit: 'kg',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateSetName = async (oldName: string, newName: string) => {
|
export const updateManySet = async ({
|
||||||
const update = `UPDATE sets SET name = ? WHERE name = ?`;
|
oldName,
|
||||||
return db.executeSql(update, [newName, oldName]);
|
newName,
|
||||||
|
minutes,
|
||||||
|
seconds,
|
||||||
|
sets,
|
||||||
|
}: {
|
||||||
|
oldName: string;
|
||||||
|
newName: string;
|
||||||
|
minutes: string;
|
||||||
|
seconds: string;
|
||||||
|
sets: string;
|
||||||
|
}) => {
|
||||||
|
const update = `
|
||||||
|
UPDATE sets SET name = ?, minutes = ?, seconds = ?, sets = ?
|
||||||
|
WHERE name = ?
|
||||||
|
`;
|
||||||
|
return db.executeSql(update, [newName, minutes, seconds, sets, oldName]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateSetImage = async (name: string, image: string) => {
|
export const updateSetImage = async (name: string, image: string) => {
|
||||||
|
@ -112,9 +129,10 @@ export const getDistinctSets = async ({
|
||||||
offset,
|
offset,
|
||||||
}: PageParams): Promise<Workout[]> => {
|
}: PageParams): Promise<Workout[]> => {
|
||||||
const select = `
|
const select = `
|
||||||
SELECT DISTINCT sets.name, sets.image
|
SELECT DISTINCT name, image, sets, minutes, seconds
|
||||||
FROM sets
|
FROM sets
|
||||||
WHERE sets.name LIKE ?
|
WHERE sets.name LIKE ?
|
||||||
|
GROUP BY sets.name
|
||||||
ORDER BY sets.name
|
ORDER BY sets.name
|
||||||
LIMIT ? OFFSET ?
|
LIMIT ? OFFSET ?
|
||||||
`;
|
`;
|
||||||
|
|
5
set.ts
5
set.ts
|
@ -1,8 +1,11 @@
|
||||||
export default interface Set {
|
export default interface Set {
|
||||||
id: number;
|
id?: number;
|
||||||
name: string;
|
name: string;
|
||||||
reps: number;
|
reps: number;
|
||||||
weight: number;
|
weight: number;
|
||||||
|
sets?: number;
|
||||||
|
minutes?: number;
|
||||||
|
seconds?: number;
|
||||||
created?: string;
|
created?: string;
|
||||||
unit?: string;
|
unit?: string;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
export default interface Settings {
|
export default interface Settings {
|
||||||
minutes: number;
|
|
||||||
seconds: number;
|
|
||||||
alarm: number;
|
alarm: number;
|
||||||
vibrate: number;
|
vibrate: number;
|
||||||
predict: number;
|
predict: number;
|
||||||
sets: number;
|
|
||||||
sound: string;
|
sound: string;
|
||||||
notify: number;
|
notify: number;
|
||||||
images: number;
|
images: number;
|
||||||
|
|
|
@ -11,11 +11,18 @@ export const getWorkout = async (name: string): Promise<Workout> => {
|
||||||
return result.rows.raw()[0];
|
return result.rows.raw()[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const updateName = (oldName: string, newName: string) => {
|
||||||
|
const update = `
|
||||||
|
UPDATE workouts SET name = ? WHERE name = ?
|
||||||
|
`;
|
||||||
|
return db.executeSql(update, [newName, oldName]);
|
||||||
|
};
|
||||||
|
|
||||||
export const updateSteps = (name: string, steps: string): Promise<unknown> => {
|
export const updateSteps = (name: string, steps: string): Promise<unknown> => {
|
||||||
const select = `
|
const update = `
|
||||||
UPDATE workouts SET steps = ? WHERE name = ?
|
UPDATE workouts SET steps = ? WHERE name = ?
|
||||||
`;
|
`;
|
||||||
return db.executeSql(select, [steps, name]);
|
return db.executeSql(update, [steps, name]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addWorkout = (value: Workout) => {
|
export const addWorkout = (value: Workout) => {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
export default interface Workout {
|
export default interface Workout {
|
||||||
name: string;
|
name: string;
|
||||||
sets: number;
|
sets: number;
|
||||||
|
minutes: number;
|
||||||
|
seconds: number;
|
||||||
image: string;
|
image: string;
|
||||||
steps: string;
|
steps: string;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user