Rename workout -> exercise

A workout would typically refer to a list of
exercises.
This commit is contained in:
Brandon Presley 2023-11-09 18:52:50 +13:00
parent 6754e2a8ae
commit 8988e584ae
17 changed files with 166 additions and 153 deletions

View File

@ -7,7 +7,7 @@ import SetList from "./SetList";
import SettingsPage from "./SettingsPage"; import SettingsPage from "./SettingsPage";
import TimerPage from "./TimerPage"; import TimerPage from "./TimerPage";
import WeightList from "./WeightList"; import WeightList from "./WeightList";
import WorkoutList from "./WorkoutList"; import ExerciseList from "./ExerciseList";
import { DrawerParams } from "./drawer-param-list"; import { DrawerParams } from "./drawer-param-list";
import useDark from "./use-dark"; import useDark from "./use-dark";
@ -29,6 +29,11 @@ export default function AppDrawer() {
component={SetList} component={SetList}
options={{ drawerIcon: () => <IconButton icon="home-outline" /> }} options={{ drawerIcon: () => <IconButton icon="home-outline" /> }}
/> />
<Drawer.Screen
name="Exercises"
component={ExerciseList}
options={{ drawerIcon: () => <IconButton icon="dumbbell" /> }}
/>
<Drawer.Screen <Drawer.Screen
name="Plans" name="Plans"
component={PlanList} component={PlanList}
@ -41,11 +46,6 @@ export default function AppDrawer() {
drawerIcon: () => <IconButton icon="chart-bell-curve-cumulative" />, drawerIcon: () => <IconButton icon="chart-bell-curve-cumulative" />,
}} }}
/> />
<Drawer.Screen
name="Workouts"
component={WorkoutList}
options={{ drawerIcon: () => <IconButton icon="dumbbell" /> }}
/>
<Drawer.Screen <Drawer.Screen
name="Timer" name="Timer"
component={TimerPage} component={TimerPage}

View File

@ -4,8 +4,8 @@ import EditPlan from "./EditPlan";
import EditSet from "./EditSet"; import EditSet from "./EditSet";
import EditSets from "./EditSets"; import EditSets from "./EditSets";
import EditWeight from "./EditWeight"; import EditWeight from "./EditWeight";
import EditWorkout from "./EditWorkout"; import EditExercise from "./EditExercise";
import EditWorkouts from "./EditWorkouts"; import EditExercises from "./EditExercises";
import StartPlan from "./StartPlan"; import StartPlan from "./StartPlan";
import ViewGraph from "./ViewGraph"; import ViewGraph from "./ViewGraph";
import ViewWeightGraph from "./ViewWeightGraph"; import ViewWeightGraph from "./ViewWeightGraph";
@ -36,10 +36,10 @@ export type StackParams = {
weight: Weight; weight: Weight;
}; };
ViewWeightGraph: {}; ViewWeightGraph: {};
EditWorkout: { EditExercise: {
gymSet: GymSet; gymSet: GymSet;
}; };
EditWorkouts: { EditExercises: {
names: string[]; names: string[];
}; };
ViewSetList: { ViewSetList: {
@ -62,8 +62,8 @@ export default function AppStack() {
<Stack.Screen name="ViewGraph" component={ViewGraph} /> <Stack.Screen name="ViewGraph" component={ViewGraph} />
<Stack.Screen name="EditWeight" component={EditWeight} /> <Stack.Screen name="EditWeight" component={EditWeight} />
<Stack.Screen name="ViewWeightGraph" component={ViewWeightGraph} /> <Stack.Screen name="ViewWeightGraph" component={ViewWeightGraph} />
<Stack.Screen name="EditWorkout" component={EditWorkout} /> <Stack.Screen name="EditExercise" component={EditExercise} />
<Stack.Screen name="EditWorkouts" component={EditWorkouts} /> <Stack.Screen name="EditExercises" component={EditExercises} />
<Stack.Screen name="ViewSetList" component={ViewSetList} /> <Stack.Screen name="ViewSetList" component={ViewSetList} />
</Stack.Navigator> </Stack.Navigator>
); );

View File

@ -22,8 +22,8 @@ import { toast } from "./toast";
import { DrawerParams } from "./drawer-param-list"; import { DrawerParams } from "./drawer-param-list";
import { StackParams } from "./AppStack"; import { StackParams } from "./AppStack";
export default function EditWorkout() { export default function EditExercise() {
const { params } = useRoute<RouteProp<StackParams, "EditWorkout">>(); const { params } = useRoute<RouteProp<StackParams, "EditExercise">>();
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.gymSet.name); const [name, setName] = useState(params.gymSet.name);
@ -50,7 +50,7 @@ export default function EditWorkout() {
); );
const update = async () => { const update = async () => {
const newWorkout = { const newExercise = {
name: name || params.gymSet.name, name: name || params.gymSet.name,
sets: Number(sets), sets: Number(sets),
minutes: +minutes, minutes: +minutes,
@ -58,14 +58,14 @@ export default function EditWorkout() {
steps, steps,
image: removeImage ? "" : uri, image: removeImage ? "" : uri,
} as GymSet; } as GymSet;
await setRepo.update({ name: params.gymSet.name }, newWorkout); await setRepo.update({ name: params.gymSet.name }, newExercise);
await planRepo.query( await planRepo.query(
`UPDATE plans `UPDATE plans
SET workouts = REPLACE(workouts, $1, $2) SET exercises = REPLACE(exercises, $1, $2)
WHERE workouts LIKE $3`, WHERE exercises LIKE $3`,
[params.gymSet.name, name, `%${params.gymSet.name}%`] [params.gymSet.name, name, `%${params.gymSet.name}%`]
); );
navigate("Workouts", { update: newWorkout }); navigate("Exercises", { update: newExercise });
}; };
const add = async () => { const add = async () => {
@ -82,7 +82,7 @@ export default function EditWorkout() {
created: now, created: now,
}); });
emitter.emit(GYM_SET_CREATED); emitter.emit(GYM_SET_CREATED);
navigate("Workouts", { reset: new Date().getTime() }); navigate("Exercises", { reset: new Date().getTime() });
}; };
const save = async () => { const save = async () => {
@ -112,7 +112,7 @@ export default function EditWorkout() {
return ( return (
<> <>
<StackHeader <StackHeader
title={params.gymSet.name ? "Edit workout" : "Add workout"} title={params.gymSet.name ? "Edit exercise" : "Add exercise"}
/> />
<View style={{ padding: PADDING, flex: 1 }}> <View style={{ padding: PADDING, flex: 1 }}>
<ScrollView style={{ flex: 1 }}> <ScrollView style={{ flex: 1 }}>
@ -143,7 +143,7 @@ export default function EditWorkout() {
if (fixed.length !== newSets.length) if (fixed.length !== newSets.length)
toast("Sets must be a number"); toast("Sets must be a number");
}} }}
label="Sets per workout" label="Sets per exercise"
keyboardType="numeric" keyboardType="numeric"
onSubmitEditing={() => minutesRef.current?.focus()} onSubmitEditing={() => minutesRef.current?.focus()}
/> />

View File

@ -20,10 +20,11 @@ import { GYM_SET_CREATED } from "./gym-set";
import Settings from "./settings"; import Settings from "./settings";
import StackHeader from "./StackHeader"; import StackHeader from "./StackHeader";
import { toast } from "./toast"; import { toast } from "./toast";
import { WorkoutsPageParams } from "./WorkoutsPage"; import { ExercisesPageParams } from "./ExercisesPage";
export default function EditWorkouts() { export default function EditExercises() {
const { params } = useRoute<RouteProp<WorkoutsPageParams, "EditWorkouts">>(); const { params } =
useRoute<RouteProp<ExercisesPageParams, "EditExercises">>();
const [removeImage, setRemoveImage] = useState(false); const [removeImage, setRemoveImage] = useState(false);
const [showRemove, setShowRemove] = useState(false); const [showRemove, setShowRemove] = useState(false);
const [name, setName] = useState(""); const [name, setName] = useState("");
@ -37,7 +38,7 @@ export default function EditWorkouts() {
const [oldSeconds, setOldSeconds] = useState(""); const [oldSeconds, setOldSeconds] = useState("");
const [sets, setSets] = useState(""); const [sets, setSets] = useState("");
const [oldSets, setOldSets] = useState(""); const [oldSets, setOldSets] = useState("");
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>(); const navigation = useNavigation<NavigationProp<ExercisesPageParams>>();
const setsRef = useRef<TextInput>(null); const setsRef = useRef<TextInput>(null);
const stepsRef = useRef<TextInput>(null); const stepsRef = useRef<TextInput>(null);
const minutesRef = useRef<TextInput>(null); const minutesRef = useRef<TextInput>(null);
@ -82,12 +83,12 @@ export default function EditWorkouts() {
.createQueryBuilder() .createQueryBuilder()
.update() .update()
.set({ .set({
workouts: () => `REPLACE(workouts, '${oldName}', '${name}')`, exercises: () => `REPLACE(exercises, '${oldName}', '${name}')`,
}) })
.where("workouts LIKE :name", { name: `%${oldName}%` }) .where("exercises LIKE :name", { name: `%${oldName}%` })
.execute(); .execute();
} }
navigation.navigate("WorkoutList", { clearNames: true }); navigation.navigate("ExerciseList", { clearNames: true });
}; };
const changeImage = useCallback(async () => { const changeImage = useCallback(async () => {
@ -111,7 +112,7 @@ export default function EditWorkouts() {
return ( return (
<> <>
<StackHeader title={`Edit ${params.names.length} workouts`} /> <StackHeader title={`Edit ${params.names.length} exercises`} />
<View style={{ padding: PADDING, flex: 1 }}> <View style={{ padding: PADDING, flex: 1 }}>
<ScrollView style={{ flex: 1 }}> <ScrollView style={{ flex: 1 }}>
<AppInput <AppInput

View File

@ -32,8 +32,8 @@ export default function EditPlan() {
const [days, setDays] = useState<string[]>( const [days, setDays] = useState<string[]>(
plan.days ? plan.days.split(",") : [] plan.days ? plan.days.split(",") : []
); );
const [workouts, setWorkouts] = useState<string[]>( const [exercises, setExercises] = useState<string[]>(
plan.workouts ? plan.workouts.split(",") : [] plan.exercises ? plan.exercises.split(",") : []
); );
const [names, setNames] = useState<string[]>([]); const [names, setNames] = useState<string[]>([]);
const { navigate: drawerNavigate } = const { navigate: drawerNavigate } =
@ -56,27 +56,27 @@ export default function EditPlan() {
}, []); }, []);
const save = useCallback(async () => { const save = useCallback(async () => {
console.log(`${EditPlan.name}.save`, { days, workouts, plan }); console.log(`${EditPlan.name}.save`, { days, exercises, plan });
if (!days || !workouts) return; if (!days || !exercises) return;
const newWorkouts = workouts.filter((workout) => workout).join(","); const newExercises = exercises.filter((exercise) => exercise).join(",");
const newDays = days.filter((day) => day).join(","); const newDays = days.filter((day) => day).join(",");
await planRepo.save({ await planRepo.save({
title: title, title: title,
days: newDays, days: newDays,
workouts: newWorkouts, exercises: newExercises,
id: plan.id, id: plan.id,
}); });
}, [title, days, workouts, plan]); }, [title, days, exercises, plan]);
const toggleWorkout = useCallback( const toggleExercise = useCallback(
(on: boolean, name: string) => { (on: boolean, name: string) => {
if (on) { if (on) {
setWorkouts([...workouts, name]); setExercises([...exercises, name]);
} else { } else {
setWorkouts(workouts.filter((workout) => workout !== name)); setExercises(exercises.filter((exercise) => exercise !== name));
} }
}, },
[setWorkouts, workouts] [setExercises, exercises]
); );
const toggleDay = useCallback( const toggleDay = useCallback(
@ -99,32 +99,32 @@ export default function EditPlan() {
/> />
); );
const renderWorkout = ({ const renderExercise = ({
item, item,
drag, drag,
}: ReorderableListRenderItemInfo<string>) => ( }: ReorderableListRenderItemInfo<string>) => (
<Pressable <Pressable
onLongPress={drag} onLongPress={drag}
onPress={() => toggleWorkout(!workouts.includes(item), item)} onPress={() => toggleExercise(!exercises.includes(item), item)}
style={{ flexDirection: "row", alignItems: "center" }} style={{ flexDirection: "row", alignItems: "center" }}
> >
<PaperSwitch <PaperSwitch
value={workouts.includes(item)} value={exercises.includes(item)}
style={{ marginRight: MARGIN }} style={{ marginRight: MARGIN }}
onValueChange={(value) => toggleWorkout(value, item)} onValueChange={(value) => toggleExercise(value, item)}
/> />
<Text>{item}</Text> <Text>{item}</Text>
</Pressable> </Pressable>
); );
const reorderWorkout = (from: number, to: number) => { const reorderExercise = (from: number, to: number) => {
const newNames = [...names]; const newNames = [...names];
const copy = newNames[from]; const copy = newNames[from];
newNames[from] = newNames[to]; newNames[from] = newNames[to];
newNames[to] = copy; newNames[to] = copy;
const newWorkouts = newNames.filter((name) => workouts.includes(name)); const newExercises = newNames.filter((name) => exercises.includes(name));
console.log({ newWorkouts }); console.log({ newExercises });
setWorkouts(newWorkouts); setExercises(newExercises);
}; };
return ( return (
@ -140,10 +140,10 @@ export default function EditPlan() {
where: { id: plan.id }, where: { id: plan.id },
}); });
let first = await setRepo.findOne({ let first = await setRepo.findOne({
where: { name: workouts[0] }, where: { name: exercises[0] },
order: { created: "desc" }, order: { created: "desc" },
}); });
if (!first) first = { ...defaultSet, name: workouts[0] }; if (!first) first = { ...defaultSet, name: exercises[0] };
delete first.id; delete first.id;
stackNavigate("StartPlan", { plan: newPlan, first }); stackNavigate("StartPlan", { plan: newPlan, first });
}} }}
@ -161,18 +161,18 @@ export default function EditPlan() {
<Text style={styles.title}>Days</Text> <Text style={styles.title}>Days</Text>
{DAYS.map((day) => renderDay(day))} {DAYS.map((day) => renderDay(day))}
<Text style={[styles.title, { marginTop: MARGIN }]}>Workouts</Text> <Text style={[styles.title, { marginTop: MARGIN }]}>Exercises</Text>
{names.length === 0 ? ( {names.length === 0 ? (
<View> <View>
<Text>No workouts found.</Text> <Text>No exercises found.</Text>
</View> </View>
) : ( ) : (
<ReorderableList <ReorderableList
data={names} data={names}
onReorder={({ fromIndex, toIndex }) => onReorder={({ fromIndex, toIndex }) =>
reorderWorkout(fromIndex, toIndex) reorderExercise(fromIndex, toIndex)
} }
renderItem={renderWorkout} renderItem={renderExercise}
keyExtractor={(item) => item} keyExtractor={(item) => item}
dragScale={1.025} dragScale={1.025}
style={{ style={{
@ -183,7 +183,7 @@ export default function EditPlan() {
)} )}
<Button <Button
disabled={workouts.length === 0 && days.length === 0} disabled={exercises.length === 0 && days.length === 0}
style={styles.button} style={styles.button}
mode="outlined" mode="outlined"
icon="content-save" icon="content-save"

View File

@ -6,9 +6,9 @@ import { DARK_RIPPLE } from "./constants";
import { LIGHT_RIPPLE } from "./constants"; import { LIGHT_RIPPLE } from "./constants";
import GymSet from "./gym-set"; import GymSet from "./gym-set";
import useDark from "./use-dark"; import useDark from "./use-dark";
import { WorkoutsPageParams } from "./WorkoutsPage"; import { ExercisesPageParams } from "./ExercisesPage";
export default function WorkoutItem({ export default function ExerciseItem({
item, item,
setNames, setNames,
names, names,
@ -21,7 +21,7 @@ export default function WorkoutItem({
names: string[]; names: string[];
alarm: boolean; alarm: boolean;
}) { }) {
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>(); const navigation = useNavigation<NavigationProp<ExercisesPageParams>>();
const dark = useDark(); const dark = useDark();
const description = useMemo(() => { const description = useMemo(() => {
@ -52,7 +52,7 @@ export default function WorkoutItem({
const press = () => { const press = () => {
console.log({ names }); console.log({ names });
if (names.length === 0) if (names.length === 0)
return navigation.navigate("EditWorkout", { gymSet: item }); return navigation.navigate("EditExercise", { gymSet: item });
const removing = names.find((name) => name === item.name); const removing = names.find((name) => name === item.name);
if (removing) setNames(names.filter((name) => name !== item.name)); if (removing) setNames(names.filter((name) => name !== item.name));
else setNames([...names, item.name]); else setNames([...names, item.name]);

View File

@ -17,12 +17,12 @@ import ListMenu from "./ListMenu";
import Page from "./Page"; import Page from "./Page";
import SetList from "./SetList"; import SetList from "./SetList";
import Settings, { SETTINGS } from "./settings"; import Settings, { SETTINGS } from "./settings";
import WorkoutItem from "./WorkoutItem"; import ExerciseItem from "./ExerciseItem";
import { DrawerParams } from "./drawer-param-list"; import { DrawerParams } from "./drawer-param-list";
import { StackParams } from "./AppStack"; import { StackParams } from "./AppStack";
export default function WorkoutList() { export default function ExerciseList() {
const [workouts, setWorkouts] = useState<GymSet[]>(); const [exercises, setExercises] = useState<GymSet[]>();
const [offset, setOffset] = useState(0); const [offset, setOffset] = useState(0);
const [term, setTerm] = useState(""); const [term, setTerm] = useState("");
const [end, setEnd] = useState(false); const [end, setEnd] = useState(false);
@ -30,20 +30,20 @@ export default function WorkoutList() {
const [names, setNames] = useState<string[]>([]); const [names, setNames] = useState<string[]>([]);
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const navigation = useNavigation<NavigationProp<StackParams>>(); const navigation = useNavigation<NavigationProp<StackParams>>();
const { params } = useRoute<RouteProp<DrawerParams, "Workouts">>(); const { params } = useRoute<RouteProp<DrawerParams, "Exercises">>();
const update = (newWorkout: GymSet) => { const update = (newExercise: GymSet) => {
console.log(`${WorkoutList.name}.update:`, newWorkout); console.log(`${ExerciseList.name}.update:`, newExercise);
if (!workouts) return; if (!exercises) return;
const newWorkouts = workouts.map((workout) => const newExercises = exercises.map((exercise) =>
workout.name === newWorkout.name ? newWorkout : workout exercise.name === newExercise.name ? newExercise : exercise
); );
setWorkouts(newWorkouts); setExercises(newExercises);
}; };
const reset = async (value: string) => { const reset = async (value: string) => {
console.log(`${WorkoutList.name}.reset`, value); console.log(`${ExerciseList.name}.reset`, value);
const newWorkouts = await setRepo const newExercises = await setRepo
.createQueryBuilder() .createQueryBuilder()
.select() .select()
.where("name LIKE :name", { name: `%${value.trim()}%` }) .where("name LIKE :name", { name: `%${value.trim()}%` })
@ -52,9 +52,9 @@ export default function WorkoutList() {
.limit(LIMIT) .limit(LIMIT)
.getMany(); .getMany();
setOffset(0); setOffset(0);
console.log(`${WorkoutList.name}.reset`, { length: newWorkouts.length }); console.log(`${ExerciseList.name}.reset`, { length: newExercises.length });
setEnd(newWorkouts.length < LIMIT); setEnd(newExercises.length < LIMIT);
setWorkouts(newWorkouts); setExercises(newExercises);
}; };
useEffect(() => { useEffect(() => {
@ -66,7 +66,7 @@ export default function WorkoutList() {
}, []); }, []);
useEffect(() => { useEffect(() => {
console.log(`${WorkoutList.name}.useEffect`, params); console.log(`${ExerciseList.name}.useEffect`, params);
if (!params) reset(""); if (!params) reset("");
if (params?.search) search(params.search); if (params?.search) search(params.search);
else if (params?.update) update(params.update); else if (params?.update) update(params.update);
@ -77,7 +77,7 @@ export default function WorkoutList() {
const renderItem = useCallback( const renderItem = useCallback(
({ item }: { item: GymSet }) => ( ({ item }: { item: GymSet }) => (
<WorkoutItem <ExerciseItem
images={settings?.images} images={settings?.images}
alarm={settings?.alarm} alarm={settings?.alarm}
item={item} item={item}
@ -98,7 +98,7 @@ export default function WorkoutList() {
}); });
if (end) return; if (end) return;
const newOffset = offset + LIMIT; const newOffset = offset + LIMIT;
const newWorkouts = await setRepo const newExercises = await setRepo
.createQueryBuilder() .createQueryBuilder()
.select() .select()
.where("name LIKE :name", { name: `%${term.trim()}%` }) .where("name LIKE :name", { name: `%${term.trim()}%` })
@ -107,15 +107,15 @@ export default function WorkoutList() {
.limit(LIMIT) .limit(LIMIT)
.offset(newOffset) .offset(newOffset)
.getMany(); .getMany();
if (newWorkouts.length === 0) return setEnd(true); if (newExercises.length === 0) return setEnd(true);
if (!workouts) return; if (!exercises) return;
setWorkouts([...workouts, ...newWorkouts]); setExercises([...exercises, ...newExercises]);
if (newWorkouts.length < LIMIT) return setEnd(true); if (newExercises.length < LIMIT) return setEnd(true);
setOffset(newOffset); setOffset(newOffset);
}; };
const onAdd = useCallback(async () => { const onAdd = useCallback(async () => {
navigation.navigate("EditWorkout", { navigation.navigate("EditExercise", {
gymSet: new GymSet(), gymSet: new GymSet(),
}); });
}, [navigation]); }, [navigation]);
@ -137,19 +137,19 @@ export default function WorkoutList() {
}; };
const select = () => { const select = () => {
if (!workouts) return; if (!exercises) return;
if (names.length === workouts.length) return setNames([]); if (names.length === exercises.length) return setNames([]);
setNames(workouts.map((workout) => workout.name)); setNames(exercises.map((exercise) => exercise.name));
}; };
const edit = () => { const edit = () => {
navigation.navigate("EditWorkouts", { names }); navigation.navigate("EditExercises", { names });
}; };
return ( return (
<> <>
<DrawerHeader <DrawerHeader
name={names.length > 0 ? `${names.length} selected` : "Workouts"} name={names.length > 0 ? `${names.length} selected` : "Exercises"}
> >
<ListMenu <ListMenu
onClear={clear} onClear={clear}
@ -160,14 +160,14 @@ export default function WorkoutList() {
/> />
</DrawerHeader> </DrawerHeader>
<Page onAdd={onAdd} term={term} search={search}> <Page onAdd={onAdd} term={term} search={search}>
{workouts?.length === 0 ? ( {exercises?.length === 0 ? (
<List.Item <List.Item
title="No workouts yet." title="No exercises yet."
description="A workout is something you do at the gym. E.g. Deadlifts" description="An exercise is something you do at the gym. E.g. Deadlifts"
/> />
) : ( ) : (
<FlatList <FlatList
data={workouts} data={exercises}
style={{ flex: 1 }} style={{ flex: 1 }}
renderItem={renderItem} renderItem={renderItem}
keyExtractor={(w) => w.name} keyExtractor={(w) => w.name}

34
ExercisesPage.tsx Normal file
View File

@ -0,0 +1,34 @@
import { createStackNavigator } from "@react-navigation/stack";
import EditExercise from "./EditExercise";
import EditExercises from "./EditExercises";
import GymSet from "./gym-set";
import ExerciseList from "./ExerciseList";
export type ExercisesPageParams = {
ExerciseList: {
clearNames?: boolean;
search?: string;
update?: GymSet;
reset?: number;
};
EditExercise: {
gymSet: GymSet;
};
EditExercises: {
names: string[];
};
};
const Stack = createStackNavigator<ExercisesPageParams>();
export default function ExercisesPage() {
return (
<Stack.Navigator
screenOptions={{ headerShown: false, animationEnabled: false }}
>
<Stack.Screen name="ExerciseList" component={ExerciseList} />
<Stack.Screen name="EditExercise" component={EditExercise} />
<Stack.Screen name="EditExercises" component={EditExercises} />
</Stack.Navigator>
);
}

View File

@ -36,12 +36,12 @@ export default function PlanItem({
); );
const start = useCallback(async () => { const start = useCallback(async () => {
const workout = item.workouts.split(",")[0]; const exercise = item.exercises.split(",")[0];
let first = await setRepo.findOne({ let first = await setRepo.findOne({
where: { name: workout }, where: { name: exercise },
order: { created: "desc" }, order: { created: "desc" },
}); });
if (!first) first = { ...defaultSet, name: workout }; if (!first) first = { ...defaultSet, name: exercise };
delete first.id; delete first.id;
if (ids.length === 0) { if (ids.length === 0) {
return navigation.navigate("StartPlan", { plan: item, first }); return navigation.navigate("StartPlan", { plan: item, first });
@ -85,8 +85,8 @@ export default function PlanItem({
); );
const description = useMemo( const description = useMemo(
() => (item.title ? currentDays : item.workouts.replace(/,/g, ", ")), () => (item.title ? currentDays : item.exercises.replace(/,/g, ", ")),
[item.title, currentDays, item.workouts] [item.title, currentDays, item.exercises]
); );
const backgroundColor = useMemo(() => { const backgroundColor = useMemo(() => {

View File

@ -28,7 +28,7 @@ export default function PlanList() {
where: [ where: [
{ title: Like(`%${value.trim()}%`) }, { title: Like(`%${value.trim()}%`) },
{ days: Like(`%${value.trim()}%`) }, { days: Like(`%${value.trim()}%`) },
{ workouts: Like(`%${value.trim()}%`) }, { exercises: Like(`%${value.trim()}%`) },
], ],
}) })
.then(setPlans); .then(setPlans);
@ -57,7 +57,7 @@ export default function PlanList() {
const onAdd = () => const onAdd = () =>
navigation.navigate("EditPlan", { navigation.navigate("EditPlan", {
plan: { title: "", days: "", workouts: "" }, plan: { title: "", days: "", exercises: "" },
}); });
const edit = useCallback(async () => { const edit = useCallback(async () => {
@ -107,7 +107,7 @@ export default function PlanList() {
{plans?.length === 0 ? ( {plans?.length === 0 ? (
<List.Item <List.Item
title="No plans yet" title="No plans yet"
description="A plan is a list of workouts for certain days." description="A plan is a list of exercises for certain days."
/> />
) : ( ) : (
<FlatList <FlatList

View File

@ -2,7 +2,7 @@ import { NavigationProp, useNavigation } from "@react-navigation/native";
import { format } from "date-fns"; import { format } from "date-fns";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { NativeModules, ScrollView, View } from "react-native"; import { NativeModules, ScrollView } from "react-native";
import DocumentPicker from "react-native-document-picker"; import DocumentPicker from "react-native-document-picker";
import { Dirs, FileSystem } from "react-native-file-access"; import { Dirs, FileSystem } from "react-native-file-access";
import { Button } from "react-native-paper"; import { Button } from "react-native-paper";
@ -145,8 +145,8 @@ export default function SettingsPage() {
else toast("Hid unit option for sets."); else toast("Hid unit option for sets.");
return; return;
case "steps": case "steps":
if (value) toast("Show steps for a workout."); if (value) toast("Show steps for exercises.");
else toast("Hid steps for workouts."); else toast("Hid steps for exercises.");
return; return;
case "showDate": case "showDate":
if (value) toast("Show date for sets."); if (value) toast("Show date for sets.");

View File

@ -34,7 +34,7 @@ export default function StartPlan() {
const weightRef = useRef<TextInput>(null); const weightRef = useRef<TextInput>(null);
const repsRef = useRef<TextInput>(null); const repsRef = useRef<TextInput>(null);
const unitRef = useRef<TextInput>(null); const unitRef = useRef<TextInput>(null);
const workouts = useMemo(() => params.plan.workouts.split(","), [params]); const exercises = useMemo(() => params.plan.exercises.split(","), [params]);
const navigation = useNavigation<NavigationProp<StackParams>>(); const navigation = useNavigation<NavigationProp<StackParams>>();
const [selection, setSelection] = useState({ const [selection, setSelection] = useState({
@ -43,33 +43,33 @@ export default function StartPlan() {
}); });
const refresh = useCallback(async () => { const refresh = useCallback(async () => {
const questions = workouts const questions = exercises
.map((workout, index) => `('${workout}',${index})`) .map((exercise, index) => `('${exercise}',${index})`)
.join(","); .join(",");
const select = ` const select = `
SELECT workouts.name, COUNT(sets.id) as total, sets.sets SELECT exercises.name, COUNT(sets.id) as total, sets.sets
FROM (select 0 as name, 0 as sequence union values ${questions}) as workouts FROM (select 0 as name, 0 as sequence union values ${questions}) as exercises
LEFT JOIN sets ON sets.name = workouts.name LEFT JOIN sets ON sets.name = exercises.name
AND sets.created LIKE STRFTIME('%Y-%m-%d%%', 'now', 'localtime') AND sets.created LIKE STRFTIME('%Y-%m-%d%%', 'now', 'localtime')
AND NOT sets.hidden AND NOT sets.hidden
GROUP BY workouts.name GROUP BY exercises.name
ORDER BY workouts.sequence ORDER BY exercises.sequence
LIMIT -1 LIMIT -1
OFFSET 1 OFFSET 1
`; `;
const newCounts = await AppDataSource.manager.query(select); const newCounts = await AppDataSource.manager.query(select);
console.log(`${StartPlan.name}.focus:`, { newCounts }); console.log(`${StartPlan.name}.focus:`, { newCounts });
setCounts(newCounts); setCounts(newCounts);
}, [workouts]); }, [exercises]);
const select = useCallback( const select = useCallback(
async (index: number, newCounts?: CountMany[]) => { async (index: number, newCounts?: CountMany[]) => {
setSelected(index); setSelected(index);
if (!counts && !newCounts) return; if (!counts && !newCounts) return;
const workout = counts ? counts[index] : newCounts[index]; const exercise = counts ? counts[index] : newCounts[index];
console.log(`${StartPlan.name}.next:`, { workout }); console.log(`${StartPlan.name}.next:`, { exercise });
const last = await setRepo.findOne({ const last = await setRepo.findOne({
where: { name: workout.name }, where: { name: exercise.name },
order: { created: "desc" }, order: { created: "desc" },
}); });
console.log({ last }); console.log({ last });
@ -92,8 +92,8 @@ export default function StartPlan() {
const handleSubmit = async () => { const handleSubmit = async () => {
const now = await getNow(); const now = await getNow();
const workout = counts[selected]; const exercise = counts[selected];
const best = await getBestSet(workout.name); const best = await getBestSet(exercise.name);
delete best.id; delete best.id;
const newSet: GymSet = { const newSet: GymSet = {
...best, ...best,

View File

@ -1,34 +0,0 @@
import { createStackNavigator } from "@react-navigation/stack";
import EditWorkout from "./EditWorkout";
import EditWorkouts from "./EditWorkouts";
import GymSet from "./gym-set";
import WorkoutList from "./WorkoutList";
export type WorkoutsPageParams = {
WorkoutList: {
clearNames?: boolean;
search?: string;
update?: GymSet;
reset?: number;
};
EditWorkout: {
gymSet: GymSet;
};
EditWorkouts: {
names: string[];
};
};
const Stack = createStackNavigator<WorkoutsPageParams>();
export default function WorkoutsPage() {
return (
<Stack.Navigator
screenOptions={{ headerShown: false, animationEnabled: false }}
>
<Stack.Screen name="WorkoutList" component={WorkoutList} />
<Stack.Screen name="EditWorkout" component={EditWorkout} />
<Stack.Screen name="EditWorkouts" component={EditWorkouts} />
</Stack.Navigator>
);
}

View File

@ -30,6 +30,7 @@ import { weight1697766633971 } from "./migrations/1697766633971-weight";
import { Plan } from "./plan"; import { Plan } from "./plan";
import Settings from "./settings"; import Settings from "./settings";
import Weight from "./weight"; import Weight from "./weight";
import { exercises1699508495726 } from "./migrations/1699508495726-exercises";
export const AppDataSource = new DataSource({ export const AppDataSource = new DataSource({
type: "react-native", type: "react-native",
@ -66,5 +67,6 @@ export const AppDataSource = new DataSource({
addBackup1678334268359, addBackup1678334268359,
planTitle1692654882408, planTitle1692654882408,
weight1697766633971, weight1697766633971,
exercises1699508495726,
], ],
}); });

View File

@ -5,7 +5,7 @@ export type DrawerParams = {
Settings: {}; Settings: {};
Graphs: {}; Graphs: {};
Plans: {}; Plans: {};
Workouts: { Exercises: {
clearNames?: boolean; clearNames?: boolean;
search?: string; search?: string;
update?: GymSet; update?: GymSet;

View File

@ -0,0 +1,10 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class exercises1699508495726 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE plans ADD COLUMN exercises TEXT`);
await queryRunner.query(`UPDATE plans SET exercises = workouts`);
}
public async down(queryRunner: QueryRunner): Promise<void> {}
}

View File

@ -12,5 +12,5 @@ export class Plan {
days: string; days: string;
@Column("text") @Column("text")
workouts: string; exercises: string;
} }