import { DateTimePickerAndroid } from "@react-native-community/datetimepicker"; import { NavigationProp, RouteProp, useFocusEffect, useNavigation, useRoute, } from "@react-navigation/native"; import { format } from "date-fns"; import { useCallback, useRef, useState } from "react"; import { NativeModules, TextInput, View } from "react-native"; import DocumentPicker from "react-native-document-picker"; import { Button, Card, IconButton, Menu, TouchableRipple, } from "react-native-paper"; import { check, PERMISSIONS, request, RESULTS } from "react-native-permissions"; import AppInput from "./AppInput"; import { StackParams } from "./AppStack"; import ConfirmDialog from "./ConfirmDialog"; import { MARGIN, PADDING } from "./constants"; import { convert } from "./conversions"; import { getNow, setRepo, settingsRepo } from "./db"; import { DrawerParams } from "./drawer-params"; import { fixNumeric } from "./fix-numeric"; import GymSet from "./gym-set"; import Select from "./Select"; import Settings from "./settings"; import StackHeader from "./StackHeader"; import { toast } from "./toast"; import PrimaryButton from "./PrimaryButton"; export default function EditSet() { const { params } = useRoute>(); const { set } = params; const { navigate } = useNavigation>(); const [settings, setSettings] = useState({} as Settings); const [name, setName] = useState(set.name); const [reps, setReps] = useState(set.reps?.toString()); const [weight, setWeight] = useState(set.weight?.toString()); const [newImage, setNewImage] = useState(set.image); const [unit, setUnit] = useState(set.unit); const [showDelete, setShowDelete] = useState(false); const [showMenu, setShowMenu] = useState(false); const [created, setCreated] = useState( set.created ? new Date(set.created) : new Date() ); const [createdDirty, setCreatedDirty] = useState(false); const [showRemoveImage, setShowRemoveImage] = useState(false); const [removeImage, setRemoveImage] = useState(false); const [setOptions, setSets] = useState([]); const weightRef = useRef(null); const repsRef = useRef(null); const [selection, setSelection] = useState({ start: 0, end: set.reps?.toString().length, }); useFocusEffect( useCallback(() => { settingsRepo.findOne({ where: {} }).then(gotSettings => { setSettings(gotSettings); console.log(`${EditSet.name}.focus:`, { gotSettings }) }); }, []) ); const startTimer = useCallback( async (value: string) => { if (!settings.alarm) return; const first = await setRepo.findOne({ where: { name: value } }); const milliseconds = (first?.minutes ?? 3) * 60 * 1000 + (first?.seconds ?? 0) * 1000; console.log(`${EditSet.name}.timer:`, { milliseconds }); const canNotify = await check(PERMISSIONS.ANDROID.POST_NOTIFICATIONS); if (canNotify === RESULTS.DENIED) await request(PERMISSIONS.ANDROID.POST_NOTIFICATIONS); if (milliseconds) NativeModules.AlarmModule.timer(milliseconds, `${first.name}`); }, [settings] ); const notify = (value: Partial) => { if (!settings.notify) return navigate("History"); if ( value.weight > set.weight || (value.reps > set.reps && value.weight === set.weight) ) { toast("Great work King! That's a new record."); } }; const added = async (value: GymSet) => { console.log(`${EditSet.name}.added:`, value); startTimer(value.name); }; const handleSubmit = async () => { if (!name) return; let newWeight = Number(weight || 0); let newUnit = unit; if (settings.autoConvert && unit !== settings.autoConvert) { newUnit = settings.autoConvert; newWeight = convert(newWeight, unit, settings.autoConvert); } const newSet: Partial = { id: set.id, name, reps: Number(reps || 0), weight: newWeight, unit: newUnit, minutes: Number(set.minutes ?? 3), seconds: Number(set.seconds ?? 30), sets: set.sets ?? 3, hidden: false, }; newSet.image = newImage; if (!newImage && !removeImage) { newSet.image = await setRepo .findOne({ where: { name } }) .then((s) => s?.image); } if (createdDirty) newSet.created = created.toISOString(); if (typeof set.id !== "number") newSet.created = await getNow(); const saved = await setRepo.save(newSet); notify(newSet); if (typeof set.id !== "number") added(saved); navigate("History"); }; const changeImage = useCallback(async () => { const { fileCopyUri } = await DocumentPicker.pickSingle({ type: DocumentPicker.types.images, copyTo: "documentDirectory", }); if (fileCopyUri) setNewImage(fileCopyUri); }, []); const handleRemove = useCallback(async () => { setNewImage(""); setRemoveImage(true); setShowRemoveImage(false); }, []); const pickDate = useCallback(() => { DateTimePickerAndroid.open({ value: created, onChange: (event, date) => { if (event.type === 'dismissed') return; if (date === created) return; setCreated(date); setCreatedDirty(true); DateTimePickerAndroid.open({ value: date, onChange: (__, time) => setCreated(time), mode: "time", }); }, mode: "date", }); }, [created]); const remove = async () => { await setRepo.delete(set.id); navigate("History"); }; const openMenu = async () => { if (setOptions.length > 0) return setShowMenu(true); const latestSets = await setRepo .createQueryBuilder() .select() .addSelect("MAX(created) as created") .groupBy("name") .getMany(); setSets(latestSets); setShowMenu(true); }; const select = (setOption: GymSet) => { setName(setOption.name); setReps(setOption.reps.toString()); setWeight(setOption.weight.toString()); setNewImage(setOption.image); setUnit(setOption.unit); setSelection({ start: 0, end: setOption.reps.toString().length, }); setShowMenu(false); }; return ( <> {typeof set.id === "number" ? ( setShowDelete(true)} icon="delete" /> ) : null} repsRef.current?.focus()} /> setShowMenu(false)} anchor={} > {setOptions.map((setOption) => ( select(setOption)} /> ))} { const fixed = fixNumeric(newReps); setReps(fixed.replace(/-/g, '')) if (fixed.length !== newReps.length) toast("Reps must be a number"); else if (fixed.includes('-')) toast("Reps must be a positive value") }} onSubmitEditing={() => weightRef.current?.focus()} selection={selection} onSelectionChange={(e) => setSelection(e.nativeEvent.selection)} innerRef={repsRef} /> setReps((Number(reps) + 1).toString())} /> setReps((Number(reps) - 1).toString())} /> { const fixed = fixNumeric(newWeight); setWeight(fixed); if (fixed.length !== newWeight.length) toast("Weight must be a number"); }} onSubmitEditing={handleSubmit} innerRef={weightRef} /> setWeight((Number(weight) + 2.5).toString())} /> setWeight((Number(weight) - 2.5).toString())} /> {settings.showUnit && (