From cfcc15600c17313ed5b9ba65336dea4088e24029 Mon Sep 17 00:00:00 2001 From: Brandon Presley Date: Wed, 18 Oct 2023 13:18:32 +1300 Subject: [PATCH] Prevent workouts jitter --- EditWorkout.tsx | 29 ++++++++++--------- WorkoutList.tsx | 73 +++++++++++++++++++++++++++++++----------------- WorkoutsPage.tsx | 3 ++ 3 files changed, 65 insertions(+), 40 deletions(-) diff --git a/EditWorkout.tsx b/EditWorkout.tsx index e4e5987..1b15861 100644 --- a/EditWorkout.tsx +++ b/EditWorkout.tsx @@ -1,4 +1,5 @@ import { + NavigationProp, RouteProp, useFocusEffect, useNavigation, @@ -13,7 +14,7 @@ import ConfirmDialog from "./ConfirmDialog"; import { MARGIN, PADDING } from "./constants"; import { getNow, planRepo, setRepo, settingsRepo } from "./db"; import { fixNumeric } from "./fix-numeric"; -import { defaultSet } from "./gym-set"; +import GymSet, { defaultSet } from "./gym-set"; import Settings from "./settings"; import StackHeader from "./StackHeader"; import { toast } from "./toast"; @@ -33,7 +34,7 @@ export default function EditWorkout() { params.gymSet.seconds?.toString() ?? "30" ); const [sets, setSets] = useState(params.gymSet.sets?.toString() ?? "3"); - const navigation = useNavigation(); + const { navigate } = useNavigation>(); const setsRef = useRef(null); const stepsRef = useRef(null); const minutesRef = useRef(null); @@ -47,24 +48,22 @@ export default function EditWorkout() { ); const update = async () => { - await setRepo.update( - { name: params.gymSet.name }, - { - name: name || params.gymSet.name, - sets: Number(sets), - minutes: +minutes, - seconds: +seconds, - steps, - image: removeImage ? "" : uri, - } - ); + const newWorkout = { + name: name || params.gymSet.name, + sets: Number(sets), + minutes: +minutes, + seconds: +seconds, + steps, + image: removeImage ? "" : uri, + } as GymSet; + await setRepo.update({ name: params.gymSet.name }, newWorkout); await planRepo.query( `UPDATE plans SET workouts = REPLACE(workouts, $1, $2) WHERE workouts LIKE $3`, [params.gymSet.name, name, `%${params.gymSet.name}%`] ); - navigation.goBack(); + navigate("WorkoutList", { update: newWorkout }); }; const add = async () => { @@ -80,7 +79,7 @@ export default function EditWorkout() { steps, created: now, }); - navigation.goBack(); + navigate("WorkoutList", { reset: new Date().getTime() }); }; const save = async () => { diff --git a/WorkoutList.tsx b/WorkoutList.tsx index 1bf5d43..cac5b0e 100644 --- a/WorkoutList.tsx +++ b/WorkoutList.tsx @@ -1,22 +1,22 @@ import { NavigationProp, RouteProp, - useFocusEffect, useNavigation, useRoute, } from "@react-navigation/native"; -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { FlatList } from "react-native"; import { List } from "react-native-paper"; import { In } from "typeorm"; import { LIMIT } from "./constants"; import { setRepo, settingsRepo } from "./db"; import DrawerHeader from "./DrawerHeader"; +import { emitter } from "./emitter"; import GymSet from "./gym-set"; import ListMenu from "./ListMenu"; import Page from "./Page"; import SetList from "./SetList"; -import Settings from "./settings"; +import Settings, { SETTINGS } from "./settings"; import WorkoutItem from "./WorkoutItem"; import { WorkoutsPageParams } from "./WorkoutsPage"; @@ -27,10 +27,21 @@ export default function WorkoutList() { const [end, setEnd] = useState(false); const [settings, setSettings] = useState(); const [names, setNames] = useState([]); + const [refreshing, setRefreshing] = useState(false); const navigation = useNavigation>(); const { params } = useRoute>(); - 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 .createQueryBuilder() .select() @@ -39,19 +50,29 @@ export default function WorkoutList() { .orderBy("name") .limit(LIMIT) .getMany(); - console.log(`${WorkoutList.name}`, { newWorkout: newWorkouts[0] }); - setWorkouts(newWorkouts); 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( - useCallback(() => { - refresh(term); - settingsRepo.findOne({ where: {} }).then(setSettings); - if (params?.clearNames) setNames([]); - }, [refresh, term, params]) - ); + useEffect(() => { + console.log(`${WorkoutList.name}.useEffect`, params); + if (!params) reset(""); + if (params?.search) search(params.search); + else if (params?.update) update(params.update); + else if (params?.reset) reset(term); + else if (params?.clearNames) setNames([]); + /* eslint-disable react-hooks/exhaustive-deps */ + }, [params]); const renderItem = useCallback( ({ item }: { item: GymSet }) => ( @@ -68,14 +89,14 @@ export default function WorkoutList() { ); const next = async () => { - if (end) return; - const newOffset = offset + LIMIT; console.log(`${SetList.name}.next:`, { offset, limit: LIMIT, - newOffset, term, + end, }); + if (end) return; + const newOffset = offset + LIMIT; const newWorkouts = await setRepo .createQueryBuilder() .select() @@ -98,13 +119,10 @@ export default function WorkoutList() { }); }, [navigation]); - const search = useCallback( - (value: string) => { - setTerm(value); - refresh(value); - }, - [refresh] - ); + const search = (value: string) => { + setTerm(value); + reset(value); + }; const clear = useCallback(() => { setNames([]); @@ -113,7 +131,7 @@ export default function WorkoutList() { const remove = async () => { setNames([]); if (names.length > 0) await setRepo.delete({ name: In(names) }); - await refresh(term); + await reset(term); }; const select = () => { @@ -152,6 +170,11 @@ export default function WorkoutList() { renderItem={renderItem} keyExtractor={(w) => w.name} onEndReached={next} + refreshing={refreshing} + onRefresh={() => { + setRefreshing(true); + reset("").finally(() => setRefreshing(false)); + }} /> )} diff --git a/WorkoutsPage.tsx b/WorkoutsPage.tsx index 973c105..58133b6 100644 --- a/WorkoutsPage.tsx +++ b/WorkoutsPage.tsx @@ -7,6 +7,9 @@ import WorkoutList from "./WorkoutList"; export type WorkoutsPageParams = { WorkoutList: { clearNames?: boolean; + search?: string; + update?: GymSet; + reset?: number; }; EditWorkout: { gymSet: GymSet;