Prevent workouts jitter

This commit is contained in:
Brandon Presley 2023-10-18 13:18:32 +13:00
parent 44184516f7
commit cfcc15600c
3 changed files with 65 additions and 40 deletions

View File

@ -1,4 +1,5 @@
import { import {
NavigationProp,
RouteProp, RouteProp,
useFocusEffect, useFocusEffect,
useNavigation, useNavigation,
@ -13,7 +14,7 @@ import ConfirmDialog from "./ConfirmDialog";
import { MARGIN, PADDING } from "./constants"; import { MARGIN, PADDING } from "./constants";
import { getNow, planRepo, setRepo, settingsRepo } from "./db"; import { getNow, planRepo, setRepo, settingsRepo } from "./db";
import { fixNumeric } from "./fix-numeric"; import { fixNumeric } from "./fix-numeric";
import { defaultSet } from "./gym-set"; import GymSet, { defaultSet } 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";
@ -33,7 +34,7 @@ export default function EditWorkout() {
params.gymSet.seconds?.toString() ?? "30" params.gymSet.seconds?.toString() ?? "30"
); );
const [sets, setSets] = useState(params.gymSet.sets?.toString() ?? "3"); const [sets, setSets] = useState(params.gymSet.sets?.toString() ?? "3");
const navigation = useNavigation(); const { navigate } = useNavigation<NavigationProp<WorkoutsPageParams>>();
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);
@ -47,24 +48,22 @@ export default function EditWorkout() {
); );
const update = async () => { const update = async () => {
await setRepo.update( const newWorkout = {
{ name: params.gymSet.name }, name: name || params.gymSet.name,
{ sets: Number(sets),
name: name || params.gymSet.name, minutes: +minutes,
sets: Number(sets), seconds: +seconds,
minutes: +minutes, steps,
seconds: +seconds, image: removeImage ? "" : uri,
steps, } as GymSet;
image: removeImage ? "" : uri, await setRepo.update({ name: params.gymSet.name }, newWorkout);
}
);
await planRepo.query( await planRepo.query(
`UPDATE plans `UPDATE plans
SET workouts = REPLACE(workouts, $1, $2) SET workouts = REPLACE(workouts, $1, $2)
WHERE workouts LIKE $3`, WHERE workouts LIKE $3`,
[params.gymSet.name, name, `%${params.gymSet.name}%`] [params.gymSet.name, name, `%${params.gymSet.name}%`]
); );
navigation.goBack(); navigate("WorkoutList", { update: newWorkout });
}; };
const add = async () => { const add = async () => {
@ -80,7 +79,7 @@ export default function EditWorkout() {
steps, steps,
created: now, created: now,
}); });
navigation.goBack(); navigate("WorkoutList", { reset: new Date().getTime() });
}; };
const save = async () => { const save = async () => {

View File

@ -1,22 +1,22 @@
import { import {
NavigationProp, NavigationProp,
RouteProp, RouteProp,
useFocusEffect,
useNavigation, useNavigation,
useRoute, useRoute,
} from "@react-navigation/native"; } from "@react-navigation/native";
import { useCallback, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { FlatList } from "react-native"; import { FlatList } from "react-native";
import { List } from "react-native-paper"; import { List } from "react-native-paper";
import { In } from "typeorm"; import { In } from "typeorm";
import { LIMIT } from "./constants"; import { LIMIT } from "./constants";
import { setRepo, settingsRepo } from "./db"; import { setRepo, settingsRepo } from "./db";
import DrawerHeader from "./DrawerHeader"; import DrawerHeader from "./DrawerHeader";
import { emitter } from "./emitter";
import GymSet from "./gym-set"; import GymSet from "./gym-set";
import ListMenu from "./ListMenu"; import ListMenu from "./ListMenu";
import Page from "./Page"; import Page from "./Page";
import SetList from "./SetList"; import SetList from "./SetList";
import Settings from "./settings"; import Settings, { SETTINGS } from "./settings";
import WorkoutItem from "./WorkoutItem"; import WorkoutItem from "./WorkoutItem";
import { WorkoutsPageParams } from "./WorkoutsPage"; import { WorkoutsPageParams } from "./WorkoutsPage";
@ -27,10 +27,21 @@ export default function WorkoutList() {
const [end, setEnd] = useState(false); const [end, setEnd] = useState(false);
const [settings, setSettings] = useState<Settings>(); const [settings, setSettings] = useState<Settings>();
const [names, setNames] = useState<string[]>([]); const [names, setNames] = useState<string[]>([]);
const [refreshing, setRefreshing] = useState(false);
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>(); const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
const { params } = useRoute<RouteProp<WorkoutsPageParams, "WorkoutList">>(); const { params } = useRoute<RouteProp<WorkoutsPageParams, "WorkoutList">>();
const refresh = useCallback(async (value: string) => { const update = (newWorkout: GymSet) => {
console.log(`${WorkoutList.name}.update:`, newWorkout);
if (!workouts) return;
const newWorkouts = workouts.map((workout) =>
workout.name === newWorkout.name ? newWorkout : workout
);
setWorkouts(newWorkouts);
};
const reset = async (value: string) => {
console.log(`${WorkoutList.name}.reset`, value);
const newWorkouts = await setRepo const newWorkouts = await setRepo
.createQueryBuilder() .createQueryBuilder()
.select() .select()
@ -39,19 +50,29 @@ export default function WorkoutList() {
.orderBy("name") .orderBy("name")
.limit(LIMIT) .limit(LIMIT)
.getMany(); .getMany();
console.log(`${WorkoutList.name}`, { newWorkout: newWorkouts[0] });
setWorkouts(newWorkouts);
setOffset(0); setOffset(0);
setEnd(false); console.log(`${WorkoutList.name}.reset`, { length: newWorkouts.length });
setEnd(newWorkouts.length < LIMIT);
setWorkouts(newWorkouts);
};
useEffect(() => {
settingsRepo.findOne({ where: {} }).then(setSettings);
const description = emitter.addListener(SETTINGS, () => {
settingsRepo.findOne({ where: {} }).then(setSettings);
});
return description.remove;
}, []); }, []);
useFocusEffect( useEffect(() => {
useCallback(() => { console.log(`${WorkoutList.name}.useEffect`, params);
refresh(term); if (!params) reset("");
settingsRepo.findOne({ where: {} }).then(setSettings); if (params?.search) search(params.search);
if (params?.clearNames) setNames([]); else if (params?.update) update(params.update);
}, [refresh, term, params]) else if (params?.reset) reset(term);
); else if (params?.clearNames) setNames([]);
/* eslint-disable react-hooks/exhaustive-deps */
}, [params]);
const renderItem = useCallback( const renderItem = useCallback(
({ item }: { item: GymSet }) => ( ({ item }: { item: GymSet }) => (
@ -68,14 +89,14 @@ export default function WorkoutList() {
); );
const next = async () => { const next = async () => {
if (end) return;
const newOffset = offset + LIMIT;
console.log(`${SetList.name}.next:`, { console.log(`${SetList.name}.next:`, {
offset, offset,
limit: LIMIT, limit: LIMIT,
newOffset,
term, term,
end,
}); });
if (end) return;
const newOffset = offset + LIMIT;
const newWorkouts = await setRepo const newWorkouts = await setRepo
.createQueryBuilder() .createQueryBuilder()
.select() .select()
@ -98,13 +119,10 @@ export default function WorkoutList() {
}); });
}, [navigation]); }, [navigation]);
const search = useCallback( const search = (value: string) => {
(value: string) => { setTerm(value);
setTerm(value); reset(value);
refresh(value); };
},
[refresh]
);
const clear = useCallback(() => { const clear = useCallback(() => {
setNames([]); setNames([]);
@ -113,7 +131,7 @@ export default function WorkoutList() {
const remove = async () => { const remove = async () => {
setNames([]); setNames([]);
if (names.length > 0) await setRepo.delete({ name: In(names) }); if (names.length > 0) await setRepo.delete({ name: In(names) });
await refresh(term); await reset(term);
}; };
const select = () => { const select = () => {
@ -152,6 +170,11 @@ export default function WorkoutList() {
renderItem={renderItem} renderItem={renderItem}
keyExtractor={(w) => w.name} keyExtractor={(w) => w.name}
onEndReached={next} onEndReached={next}
refreshing={refreshing}
onRefresh={() => {
setRefreshing(true);
reset("").finally(() => setRefreshing(false));
}}
/> />
)} )}
</Page> </Page>

View File

@ -7,6 +7,9 @@ import WorkoutList from "./WorkoutList";
export type WorkoutsPageParams = { export type WorkoutsPageParams = {
WorkoutList: { WorkoutList: {
clearNames?: boolean; clearNames?: boolean;
search?: string;
update?: GymSet;
reset?: number;
}; };
EditWorkout: { EditWorkout: {
gymSet: GymSet; gymSet: GymSet;