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