Only reset SetList in certain situations
This reduces the jitter in the homepage when you have scrolled down a significant amount. Related to #165. Still need to do other list pages.
This commit is contained in:
parent
8e42e9c3e4
commit
672931746b
34
EditSet.tsx
34
EditSet.tsx
|
@ -1,5 +1,6 @@
|
|||
import { DateTimePickerAndroid } from "@react-native-community/datetimepicker";
|
||||
import {
|
||||
NavigationProp,
|
||||
RouteProp,
|
||||
useFocusEffect,
|
||||
useNavigation,
|
||||
|
@ -24,7 +25,7 @@ import { fixNumeric } from "./fix-numeric";
|
|||
export default function EditSet() {
|
||||
const { params } = useRoute<RouteProp<HomePageParams, "EditSet">>();
|
||||
const { set } = params;
|
||||
const navigation = useNavigation();
|
||||
const { navigate } = useNavigation<NavigationProp<HomePageParams>>();
|
||||
const [settings, setSettings] = useState<Settings>({} as Settings);
|
||||
const [name, setName] = useState(set.name);
|
||||
const [reps, setReps] = useState(set.reps?.toString());
|
||||
|
@ -63,20 +64,18 @@ export default function EditSet() {
|
|||
[settings]
|
||||
);
|
||||
|
||||
const added = useCallback(
|
||||
async (value: GymSet) => {
|
||||
startTimer(value.name);
|
||||
console.log(`${EditSet.name}.add`, { set: value });
|
||||
if (!settings.notify) return;
|
||||
if (
|
||||
value.weight > set.weight ||
|
||||
(value.reps > set.reps && value.weight === set.weight)
|
||||
) {
|
||||
toast("Great work King! That's a new record.");
|
||||
}
|
||||
},
|
||||
[startTimer, set, settings]
|
||||
);
|
||||
const added = async (value: GymSet) => {
|
||||
startTimer(value.name);
|
||||
console.log(`${EditSet.name}.add`, { set: value });
|
||||
if (!settings.notify) return;
|
||||
if (
|
||||
value.weight > set.weight ||
|
||||
(value.reps > set.reps && value.weight === set.weight)
|
||||
) {
|
||||
toast("Great work King! That's a new record.");
|
||||
}
|
||||
navigate("Sets", { added: value.id });
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!name) return;
|
||||
|
@ -104,8 +103,9 @@ export default function EditSet() {
|
|||
if (typeof set.id !== "number") newSet.created = await getNow();
|
||||
|
||||
const saved = await setRepo.save(newSet);
|
||||
if (typeof set.id !== "number") added(saved);
|
||||
navigation.goBack();
|
||||
if (typeof set.id !== "number") return added(saved);
|
||||
if (createdDirty) navigate("Sets", { reset: saved.id });
|
||||
else navigate("Sets", { refresh: saved.id });
|
||||
};
|
||||
|
||||
const changeImage = useCallback(async () => {
|
||||
|
|
169
SetList.tsx
169
SetList.tsx
|
@ -1,9 +1,10 @@
|
|||
import {
|
||||
NavigationProp,
|
||||
useFocusEffect,
|
||||
RouteProp,
|
||||
useNavigation,
|
||||
useRoute,
|
||||
} from "@react-navigation/native";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { FlatList } from "react-native";
|
||||
import { List } from "react-native-paper";
|
||||
import { Like } from "typeorm";
|
||||
|
@ -18,33 +19,77 @@ import SetItem from "./SetItem";
|
|||
import Settings from "./settings";
|
||||
|
||||
export default function SetList() {
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [sets, setSets] = useState<GymSet[]>([]);
|
||||
const [offset, setOffset] = useState(0);
|
||||
const [term, setTerm] = useState("");
|
||||
const [end, setEnd] = useState(false);
|
||||
const [settings, setSettings] = useState<Settings>();
|
||||
const [ids, setIds] = useState<number[]>([]);
|
||||
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
||||
const { params } = useRoute<RouteProp<HomePageParams, "Sets">>();
|
||||
const [term, setTerm] = useState(params?.search || "");
|
||||
|
||||
const refresh = useCallback(async (value: string) => {
|
||||
const newSets = await setRepo.find({
|
||||
where: { name: Like(`%${value.trim()}%`), hidden: 0 as any },
|
||||
take: LIMIT,
|
||||
skip: 0,
|
||||
order: { created: "DESC" },
|
||||
});
|
||||
console.log(`${SetList.name}.refresh:`, { value });
|
||||
const refresh = async ({
|
||||
value,
|
||||
take,
|
||||
skip,
|
||||
}: {
|
||||
value: string;
|
||||
take: number;
|
||||
skip: number;
|
||||
}) => {
|
||||
setRefreshing(true);
|
||||
const newSets = await setRepo
|
||||
.find({
|
||||
where: { name: Like(`%${value.trim()}%`), hidden: 0 as any },
|
||||
take,
|
||||
skip,
|
||||
order: { created: "DESC" },
|
||||
})
|
||||
.finally(() => setRefreshing(false));
|
||||
console.log(`${SetList.name}.refresh:`, { value, take, offset });
|
||||
setSets(newSets);
|
||||
setOffset(0);
|
||||
setEnd(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
settingsRepo.findOne({ where: {} }).then(setSettings);
|
||||
refresh({
|
||||
take: LIMIT,
|
||||
value: "",
|
||||
skip: 0,
|
||||
});
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
}, []);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
refresh(term);
|
||||
settingsRepo.findOne({ where: {} }).then(setSettings);
|
||||
}, [refresh, term])
|
||||
);
|
||||
const search = (value: string) => {
|
||||
setTerm(value);
|
||||
setOffset(0);
|
||||
refresh({
|
||||
skip: 0,
|
||||
take: LIMIT,
|
||||
value,
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!params) return;
|
||||
console.log({ params });
|
||||
if (params.search) search(params.search);
|
||||
else if (params.refresh)
|
||||
refresh({
|
||||
skip: 0,
|
||||
take: offset,
|
||||
value: term,
|
||||
});
|
||||
else if (params.reset)
|
||||
refresh({
|
||||
skip: 0,
|
||||
take: LIMIT,
|
||||
value: term,
|
||||
});
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
}, [params]);
|
||||
|
||||
const renderItem = useCallback(
|
||||
({ item }: { item: GymSet }) => (
|
||||
|
@ -59,22 +104,29 @@ export default function SetList() {
|
|||
[settings, ids]
|
||||
);
|
||||
|
||||
const next = useCallback(async () => {
|
||||
if (end) return;
|
||||
const next = async () => {
|
||||
if (end || refreshing) return;
|
||||
const newOffset = offset + LIMIT;
|
||||
console.log(`${SetList.name}.next:`, { offset, newOffset, term });
|
||||
const newSets = await setRepo.find({
|
||||
where: { name: Like(`%${term}%`), hidden: 0 as any },
|
||||
take: LIMIT,
|
||||
skip: newOffset,
|
||||
order: { created: "DESC" },
|
||||
});
|
||||
setRefreshing(true);
|
||||
const newSets = await setRepo
|
||||
.find({
|
||||
where: { name: Like(`%${term}%`), hidden: 0 as any },
|
||||
take: LIMIT,
|
||||
skip: newOffset,
|
||||
order: { created: "DESC" },
|
||||
})
|
||||
.finally(() => setRefreshing(false));
|
||||
if (newSets.length === 0) return setEnd(true);
|
||||
if (!sets) return;
|
||||
setSets([...sets, ...newSets]);
|
||||
const map = new Map<number, GymSet>();
|
||||
for (const set of sets) map.set(set.id, set);
|
||||
for (const set of newSets) map.set(set.id, set);
|
||||
const unique = Array.from(map.values());
|
||||
setSets(unique);
|
||||
if (newSets.length < LIMIT) return setEnd(true);
|
||||
setOffset(newOffset);
|
||||
}, [term, end, offset, sets]);
|
||||
};
|
||||
|
||||
const onAdd = useCallback(async () => {
|
||||
const now = await getNow();
|
||||
|
@ -85,14 +137,6 @@ export default function SetList() {
|
|||
navigation.navigate("EditSet", { set });
|
||||
}, [navigation, sets]);
|
||||
|
||||
const search = useCallback(
|
||||
(value: string) => {
|
||||
setTerm(value);
|
||||
refresh(value);
|
||||
},
|
||||
[refresh]
|
||||
);
|
||||
|
||||
const edit = useCallback(() => {
|
||||
navigation.navigate("EditSets", { ids });
|
||||
setIds([]);
|
||||
|
@ -112,16 +156,47 @@ export default function SetList() {
|
|||
setIds([]);
|
||||
}, []);
|
||||
|
||||
const remove = useCallback(async () => {
|
||||
const remove = async () => {
|
||||
setIds([]);
|
||||
await setRepo.delete(ids.length > 0 ? ids : {});
|
||||
await refresh(term);
|
||||
}, [ids, refresh, term]);
|
||||
return refresh({
|
||||
skip: 0,
|
||||
take: LIMIT,
|
||||
value: term,
|
||||
});
|
||||
};
|
||||
|
||||
const select = useCallback(() => {
|
||||
setIds(sets.map((set) => set.id));
|
||||
}, [sets]);
|
||||
|
||||
const content = useMemo(() => {
|
||||
if (!settings) return null;
|
||||
if (sets?.length === 0)
|
||||
return (
|
||||
<List.Item
|
||||
title="No sets yet"
|
||||
description="A set is a group of repetitions. E.g. 8 reps of Squats."
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<FlatList
|
||||
data={sets}
|
||||
style={{ flex: 1 }}
|
||||
renderItem={renderItem}
|
||||
onEndReached={next}
|
||||
refreshing={false}
|
||||
onRefresh={() =>
|
||||
refresh({
|
||||
skip: 0,
|
||||
take: LIMIT,
|
||||
value: term,
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
}, [sets, settings, term]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DrawerHeader name={ids.length > 0 ? `${ids.length} selected` : "Home"}>
|
||||
|
@ -136,21 +211,7 @@ export default function SetList() {
|
|||
</DrawerHeader>
|
||||
|
||||
<Page onAdd={onAdd} term={term} search={search}>
|
||||
{sets?.length === 0 ? (
|
||||
<List.Item
|
||||
title="No sets yet"
|
||||
description="A set is a group of repetitions. E.g. 8 reps of Squats."
|
||||
/>
|
||||
) : (
|
||||
settings && (
|
||||
<FlatList
|
||||
data={sets}
|
||||
style={{ flex: 1 }}
|
||||
renderItem={renderItem}
|
||||
onEndReached={next}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
{content}
|
||||
</Page>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -5,6 +5,7 @@ import { List, Menu, RadioButton, useTheme } from "react-native-paper";
|
|||
import { Like } from "typeorm";
|
||||
import CountMany from "./count-many";
|
||||
import { getNow, setRepo } from "./db";
|
||||
import { HomePageParams } from "./home-page-params";
|
||||
import { PlanPageParams } from "./plan-page-params";
|
||||
import { toast } from "./toast";
|
||||
|
||||
|
@ -20,6 +21,8 @@ export default function StartPlanItem(props: Props) {
|
|||
const [anchor, setAnchor] = useState({ x: 0, y: 0 });
|
||||
const [showMenu, setShowMenu] = useState(false);
|
||||
const { navigate } = useNavigation<NavigationProp<PlanPageParams>>();
|
||||
const { navigate: navigateHome } =
|
||||
useNavigation<NavigationProp<HomePageParams>>();
|
||||
|
||||
const undo = useCallback(async () => {
|
||||
const now = await getNow();
|
||||
|
@ -62,6 +65,11 @@ export default function StartPlanItem(props: Props) {
|
|||
navigate("EditSet", { set: first });
|
||||
}, [item.name, navigate]);
|
||||
|
||||
const view = () => {
|
||||
setShowMenu(false);
|
||||
navigateHome("Sets", { search: item.name });
|
||||
};
|
||||
|
||||
const left = useCallback(
|
||||
() => (
|
||||
<View style={{ alignItems: "center", justifyContent: "center" }}>
|
||||
|
@ -89,6 +97,7 @@ export default function StartPlanItem(props: Props) {
|
|||
visible={showMenu}
|
||||
onDismiss={() => setShowMenu(false)}
|
||||
>
|
||||
<Menu.Item leadingIcon="visibility" onPress={view} title="View" />
|
||||
<Menu.Item leadingIcon="edit" onPress={edit} title="Edit" />
|
||||
<Menu.Item leadingIcon="undo" onPress={undo} title="Undo" />
|
||||
</Menu>
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
import GymSet from "./gym-set";
|
||||
|
||||
export type HomePageParams = {
|
||||
Sets: {};
|
||||
Sets: {
|
||||
search?: string;
|
||||
|
||||
/**
|
||||
* Reload the current list with limit = offset
|
||||
*/
|
||||
refresh?: number;
|
||||
|
||||
/**
|
||||
* Reload the list with limit = 0
|
||||
*/
|
||||
reset?: number;
|
||||
};
|
||||
EditSet: {
|
||||
set: GymSet;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user