diff --git a/App.tsx b/App.tsx index cae0f992..23b49cbb 100644 --- a/App.tsx +++ b/App.tsx @@ -2,21 +2,21 @@ import { DarkTheme as NavigationDarkTheme, DefaultTheme as NavigationDefaultTheme, NavigationContainer, -} from '@react-navigation/native' -import React, { useEffect, useMemo, useState } from 'react' -import { DeviceEventEmitter, useColorScheme } from 'react-native' +} from "@react-navigation/native"; +import React, { useEffect, useMemo, useState } from "react"; +import { DeviceEventEmitter, useColorScheme } from "react-native"; import { MD3DarkTheme as PaperDarkTheme, MD3LightTheme as PaperDefaultTheme, Provider as PaperProvider, Snackbar, -} from 'react-native-paper' -import MaterialIcon from 'react-native-vector-icons/MaterialIcons' -import { AppDataSource } from './data-source' -import { settingsRepo } from './db' -import Routes from './Routes' -import { TOAST } from './toast' -import { ThemeContext } from './use-theme' +} from "react-native-paper"; +import MaterialIcon from "react-native-vector-icons/MaterialIcons"; +import { AppDataSource } from "./data-source"; +import { settingsRepo } from "./db"; +import Routes from "./Routes"; +import { TOAST } from "./toast"; +import { ThemeContext } from "./use-theme"; export const CombinedDefaultTheme = { ...NavigationDefaultTheme, @@ -25,7 +25,7 @@ export const CombinedDefaultTheme = { ...NavigationDefaultTheme.colors, ...PaperDefaultTheme.colors, }, -} +}; export const CombinedDarkTheme = { ...NavigationDarkTheme, @@ -34,58 +34,58 @@ export const CombinedDarkTheme = { ...NavigationDarkTheme.colors, ...PaperDarkTheme.colors, }, -} +}; const App = () => { - const phoneTheme = useColorScheme() - const [initialized, setInitialized] = useState(false) - const [snackbar, setSnackbar] = useState('') - const [appTheme, setAppTheme] = useState('system') + const phoneTheme = useColorScheme(); + const [initialized, setInitialized] = useState(false); + const [snackbar, setSnackbar] = useState(""); + const [appTheme, setAppTheme] = useState("system"); const [lightColor, setLightColor] = useState( - CombinedDefaultTheme.colors.primary, - ) + CombinedDefaultTheme.colors.primary + ); const [darkColor, setDarkColor] = useState( - CombinedDarkTheme.colors.primary, - ) + CombinedDarkTheme.colors.primary + ); useEffect(() => { - ;(async () => { - if (!AppDataSource.isInitialized) await AppDataSource.initialize() - const settings = await settingsRepo.findOne({ where: {} }) - setAppTheme(settings.theme) - if (settings.lightColor) setLightColor(settings.lightColor) - if (settings.darkColor) setDarkColor(settings.darkColor) - setInitialized(true) - })() + (async () => { + if (!AppDataSource.isInitialized) await AppDataSource.initialize(); + const settings = await settingsRepo.findOne({ where: {} }); + setAppTheme(settings.theme); + if (settings.lightColor) setLightColor(settings.lightColor); + if (settings.darkColor) setDarkColor(settings.darkColor); + setInitialized(true); + })(); const description = DeviceEventEmitter.addListener( TOAST, ({ value }: { value: string }) => { - setSnackbar(value) - }, - ) - return description.remove - }, []) + setSnackbar(value); + } + ); + return description.remove; + }, []); const paperTheme = useMemo(() => { const darkTheme = lightColor ? { - ...CombinedDarkTheme, - colors: { ...CombinedDarkTheme.colors, primary: darkColor }, - } - : CombinedDarkTheme + ...CombinedDarkTheme, + colors: { ...CombinedDarkTheme.colors, primary: darkColor }, + } + : CombinedDarkTheme; const lightTheme = lightColor ? { - ...CombinedDefaultTheme, - colors: { ...CombinedDefaultTheme.colors, primary: lightColor }, - } - : CombinedDefaultTheme - let value = phoneTheme === 'dark' ? darkTheme : lightTheme - if (appTheme === 'dark') value = darkTheme - else if (appTheme === 'light') value = lightTheme - return value - }, [phoneTheme, appTheme, lightColor, darkColor]) + ...CombinedDefaultTheme, + colors: { ...CombinedDefaultTheme.colors, primary: lightColor }, + } + : CombinedDefaultTheme; + let value = phoneTheme === "dark" ? darkTheme : lightTheme; + if (appTheme === "dark") value = darkTheme; + else if (appTheme === "light") value = lightTheme; + return value; + }, [phoneTheme, appTheme, lightColor, darkColor]); return ( { setSnackbar('')} + onDismiss={() => setSnackbar("")} visible={!!snackbar} action={{ - label: 'Close', - onPress: () => setSnackbar(''), + label: "Close", + onPress: () => setSnackbar(""), textColor: paperTheme.colors.background, }} > {snackbar} - ) -} + ); +}; -export default App +export default App; diff --git a/AppFab.tsx b/AppFab.tsx index f5ec31d3..ef6d565f 100644 --- a/AppFab.tsx +++ b/AppFab.tsx @@ -1,31 +1,31 @@ -import { ComponentProps, useMemo } from 'react' -import { FAB, useTheme } from 'react-native-paper' -import { CombinedDarkTheme, CombinedDefaultTheme } from './App' -import { lightColors } from './colors' +import { ComponentProps, useMemo } from "react"; +import { FAB, useTheme } from "react-native-paper"; +import { CombinedDarkTheme, CombinedDefaultTheme } from "./App"; +import { lightColors } from "./colors"; export default function AppFab(props: Partial>) { - const { colors } = useTheme() + const { colors } = useTheme(); const fabColor = useMemo( () => lightColors.map((color) => color.hex).includes(colors.primary) ? CombinedDarkTheme.colors.background : CombinedDefaultTheme.colors.background, - [colors.primary], - ) + [colors.primary] + ); return ( - ) + ); } diff --git a/AppInput.tsx b/AppInput.tsx index 43f6cdf7..99a60f92 100644 --- a/AppInput.tsx +++ b/AppInput.tsx @@ -1,26 +1,26 @@ -import React, { ComponentProps, Ref } from 'react' -import { TextInput } from 'react-native-paper' -import { CombinedDefaultTheme } from './App' -import { MARGIN } from './constants' -import useDark from './use-dark' +import React, { ComponentProps, Ref } from "react"; +import { TextInput } from "react-native-paper"; +import { CombinedDefaultTheme } from "./App"; +import { MARGIN } from "./constants"; +import useDark from "./use-dark"; function AppInput( props: Partial> & { - innerRef?: Ref - }, + innerRef?: Ref; + } ) { - const dark = useDark() + const dark = useDark(); return ( - ) + ); } -export default React.memo(AppInput) +export default React.memo(AppInput); diff --git a/Chart.tsx b/Chart.tsx index 4b739e66..6588fd8f 100644 --- a/Chart.tsx +++ b/Chart.tsx @@ -1,11 +1,11 @@ -import { useTheme } from '@react-navigation/native' -import * as shape from 'd3-shape' -import { View } from 'react-native' -import { Grid, LineChart, XAxis, YAxis } from 'react-native-svg-charts' -import { CombinedDarkTheme, CombinedDefaultTheme } from './App' -import { MARGIN, PADDING } from './constants' -import GymSet from './gym-set' -import useDark from './use-dark' +import { useTheme } from "@react-navigation/native"; +import * as shape from "d3-shape"; +import { View } from "react-native"; +import { Grid, LineChart, XAxis, YAxis } from "react-native-svg-charts"; +import { CombinedDarkTheme, CombinedDefaultTheme } from "./App"; +import { MARGIN, PADDING } from "./constants"; +import GymSet from "./gym-set"; +import useDark from "./use-dark"; export default function Chart({ yData, @@ -13,21 +13,21 @@ export default function Chart({ xData, yFormat, }: { - yData: number[] - xData: GymSet[] - xFormat: (value: any, index: number) => string - yFormat: (value: any) => string + yData: number[]; + xData: GymSet[]; + xFormat: (value: any, index: number) => string; + yFormat: (value: any) => string; }) { - const { colors } = useTheme() - const dark = useDark() + const { colors } = useTheme(); + const dark = useDark(); const axesSvg = { fontSize: 10, fill: dark ? CombinedDarkTheme.colors.text : CombinedDefaultTheme.colors.text, - } - const verticalContentInset = { top: 10, bottom: 10 } - const xAxisHeight = 30 + }; + const verticalContentInset = { top: 10, bottom: 10 }; + const xAxisHeight = 30; return ( <> @@ -35,7 +35,7 @@ export default function Chart({ style={{ height: 300, padding: PADDING, - flexDirection: 'row', + flexDirection: "row", }} > - ) + ); } diff --git a/ConfirmDialog.tsx b/ConfirmDialog.tsx index 23bb2a22..4aa5d70b 100644 --- a/ConfirmDialog.tsx +++ b/ConfirmDialog.tsx @@ -1,4 +1,4 @@ -import { Button, Dialog, Portal, Text } from 'react-native-paper' +import { Button, Dialog, Portal, Text } from "react-native-paper"; export default function ConfirmDialog({ title, @@ -8,17 +8,17 @@ export default function ConfirmDialog({ setShow, onCancel, }: { - title: string - children: JSX.Element | JSX.Element[] | string - onOk: () => void - show: boolean - setShow: (show: boolean) => void - onCancel?: () => void + title: string; + children: JSX.Element | JSX.Element[] | string; + onOk: () => void; + show: boolean; + setShow: (show: boolean) => void; + onCancel?: () => void; }) { const cancel = () => { - setShow(false) - onCancel && onCancel() - } + setShow(false); + onCancel && onCancel(); + }; return ( @@ -33,5 +33,5 @@ export default function ConfirmDialog({ - ) + ); } diff --git a/DrawerHeader.tsx b/DrawerHeader.tsx index 45add78d..9acbe231 100644 --- a/DrawerHeader.tsx +++ b/DrawerHeader.tsx @@ -1,25 +1,22 @@ -import { DrawerNavigationProp } from '@react-navigation/drawer' -import { useNavigation } from '@react-navigation/native' -import { Appbar, IconButton } from 'react-native-paper' -import { DrawerParamList } from './drawer-param-list' +import { DrawerNavigationProp } from "@react-navigation/drawer"; +import { useNavigation } from "@react-navigation/native"; +import { Appbar, IconButton } from "react-native-paper"; +import { DrawerParamList } from "./drawer-param-list"; export default function DrawerHeader({ name, children, }: { - name: string - children?: JSX.Element | JSX.Element[] + name: string; + children?: JSX.Element | JSX.Element[]; }) { - const navigation = useNavigation>() + const navigation = useNavigation>(); return ( - + {children} - ) + ); } diff --git a/EditPlan.tsx b/EditPlan.tsx index 7190a133..8afb93e0 100644 --- a/EditPlan.tsx +++ b/EditPlan.tsx @@ -3,92 +3,94 @@ import { RouteProp, useNavigation, useRoute, -} from '@react-navigation/native' -import { useCallback, useEffect, useState } from 'react' -import { ScrollView, StyleSheet, View } from 'react-native' -import { Button, IconButton, Text } from 'react-native-paper' -import { MARGIN, PADDING } from './constants' -import { planRepo, setRepo } from './db' -import { defaultSet } from './gym-set' -import { PlanPageParams } from './plan-page-params' -import StackHeader from './StackHeader' -import Switch from './Switch' -import { DAYS } from './time' +} from "@react-navigation/native"; +import { useCallback, useEffect, useState } from "react"; +import { ScrollView, StyleSheet, View } from "react-native"; +import { Button, IconButton, Text } from "react-native-paper"; +import { MARGIN, PADDING } from "./constants"; +import { planRepo, setRepo } from "./db"; +import { defaultSet } from "./gym-set"; +import { PlanPageParams } from "./plan-page-params"; +import StackHeader from "./StackHeader"; +import Switch from "./Switch"; +import { DAYS } from "./time"; export default function EditPlan() { - const { params } = useRoute>() - const { plan } = params + const { params } = useRoute>(); + const { plan } = params; const [days, setDays] = useState( - plan.days ? plan.days.split(',') : [], - ) + plan.days ? plan.days.split(",") : [] + ); const [workouts, setWorkouts] = useState( - plan.workouts ? plan.workouts.split(',') : [], - ) - const [names, setNames] = useState([]) - const navigation = useNavigation>() + plan.workouts ? plan.workouts.split(",") : [] + ); + const [names, setNames] = useState([]); + const navigation = useNavigation>(); useEffect(() => { setRepo .createQueryBuilder() - .select('name') + .select("name") .distinct(true) - .orderBy('name') + .orderBy("name") .getRawMany() .then((values) => { - console.log(EditPlan.name, { values }) - setNames(values.map((value) => value.name)) - }) - }, []) + console.log(EditPlan.name, { values }); + setNames(values.map((value) => value.name)); + }); + }, []); const save = useCallback(async () => { - console.log(`${EditPlan.name}.save`, { days, workouts, plan }) - if (!days || !workouts) return - const newWorkouts = workouts.filter((workout) => workout).join(',') - const newDays = days.filter((day) => day).join(',') - await planRepo.save({ days: newDays, workouts: newWorkouts, id: plan.id }) - }, [days, workouts, plan]) + console.log(`${EditPlan.name}.save`, { days, workouts, plan }); + if (!days || !workouts) return; + const newWorkouts = workouts.filter((workout) => workout).join(","); + const newDays = days.filter((day) => day).join(","); + await planRepo.save({ days: newDays, workouts: newWorkouts, id: plan.id }); + }, [days, workouts, plan]); const toggleWorkout = useCallback( (on: boolean, name: string) => { if (on) { - setWorkouts([...workouts, name]) + setWorkouts([...workouts, name]); } else { - setWorkouts(workouts.filter((workout) => workout !== name)) + setWorkouts(workouts.filter((workout) => workout !== name)); } }, - [setWorkouts, workouts], - ) + [setWorkouts, workouts] + ); const toggleDay = useCallback( (on: boolean, day: string) => { if (on) { - setDays([...days, day]) + setDays([...days, day]); } else { - setDays(days.filter((d) => d !== day)) + setDays(days.filter((d) => d !== day)); } }, - [setDays, days], - ) + [setDays, days] + ); return ( <> - {typeof plan.id === 'number' && ( + {typeof plan.id === "number" && ( { - await save() - const newPlan = await planRepo.findOne({ where: { id: plan.id } }) + await save(); + const newPlan = await planRepo.findOne({ + where: { id: plan.id }, + }); let first = await setRepo.findOne({ where: { name: workouts[0] }, - order: { created: 'desc' }, - }) - if (!first) first = { ...defaultSet, name: workouts[0] } - delete first.id - navigation.navigate('StartPlan', { plan: newPlan, first }) + order: { created: "desc" }, + }); + if (!first) first = { ...defaultSet, name: workouts[0] }; + delete first.id; + navigation.navigate("StartPlan", { plan: newPlan, first }); }} - icon='play-arrow' + icon="play-arrow" /> )} @@ -104,39 +106,37 @@ export default function EditPlan() { /> ))} Workouts - {names.length === 0 - ? ( - - No workouts found. - - ) - : ( - names.map((name) => ( - toggleWorkout(value, name)} - value={workouts.includes(name)} - title={name} - /> - )) - )} + {names.length === 0 ? ( + + No workouts found. + + ) : ( + names.map((name) => ( + toggleWorkout(value, name)} + value={workouts.includes(name)} + title={name} + /> + )) + )} - ) + ); } const styles = StyleSheet.create({ @@ -145,4 +145,4 @@ const styles = StyleSheet.create({ marginBottom: MARGIN, }, button: {}, -}) +}); diff --git a/EditSets.tsx b/EditSets.tsx index 3201c422..c6766687 100644 --- a/EditSets.tsx +++ b/EditSets.tsx @@ -3,78 +3,78 @@ import { useFocusEffect, useNavigation, useRoute, -} from '@react-navigation/native' -import { useCallback, useState } from 'react' -import { View } from 'react-native' -import DocumentPicker from 'react-native-document-picker' -import { Button, Card, TouchableRipple } from 'react-native-paper' -import { In } from 'typeorm' -import AppInput from './AppInput' -import ConfirmDialog from './ConfirmDialog' -import { MARGIN, PADDING } from './constants' -import { setRepo, settingsRepo } from './db' -import GymSet from './gym-set' -import { HomePageParams } from './home-page-params' -import Settings from './settings' -import StackHeader from './StackHeader' +} from "@react-navigation/native"; +import { useCallback, useState } from "react"; +import { View } from "react-native"; +import DocumentPicker from "react-native-document-picker"; +import { Button, Card, TouchableRipple } from "react-native-paper"; +import { In } from "typeorm"; +import AppInput from "./AppInput"; +import ConfirmDialog from "./ConfirmDialog"; +import { MARGIN, PADDING } from "./constants"; +import { setRepo, settingsRepo } from "./db"; +import GymSet from "./gym-set"; +import { HomePageParams } from "./home-page-params"; +import Settings from "./settings"; +import StackHeader from "./StackHeader"; export default function EditSets() { - const { params } = useRoute>() - const { ids } = params - const navigation = useNavigation() - const [settings, setSettings] = useState({} as Settings) - const [name, setName] = useState('') - const [reps, setReps] = useState('') - const [weight, setWeight] = useState('') - const [newImage, setNewImage] = useState('') - const [unit, setUnit] = useState('') - const [showRemove, setShowRemove] = useState(false) - const [names, setNames] = useState('') - const [oldReps, setOldReps] = useState('') - const [weights, setWeights] = useState('') - const [units, setUnits] = useState('') + const { params } = useRoute>(); + const { ids } = params; + const navigation = useNavigation(); + const [settings, setSettings] = useState({} as Settings); + const [name, setName] = useState(""); + const [reps, setReps] = useState(""); + const [weight, setWeight] = useState(""); + const [newImage, setNewImage] = useState(""); + const [unit, setUnit] = useState(""); + const [showRemove, setShowRemove] = useState(false); + const [names, setNames] = useState(""); + const [oldReps, setOldReps] = useState(""); + const [weights, setWeights] = useState(""); + const [units, setUnits] = useState(""); const [selection, setSelection] = useState({ start: 0, end: 1, - }) + }); useFocusEffect( useCallback(() => { - settingsRepo.findOne({ where: {} }).then(setSettings) + settingsRepo.findOne({ where: {} }).then(setSettings); setRepo.find({ where: { id: In(ids) } }).then((sets) => { - setNames(sets.map((set) => set.name).join(', ')) - setOldReps(sets.map((set) => set.reps).join(', ')) - setWeights(sets.map((set) => set.weight).join(', ')) - setUnits(sets.map((set) => set.unit).join(', ')) - }) - }, [ids]), - ) + setNames(sets.map((set) => set.name).join(", ")); + setOldReps(sets.map((set) => set.reps).join(", ")); + setWeights(sets.map((set) => set.weight).join(", ")); + setUnits(sets.map((set) => set.unit).join(", ")); + }); + }, [ids]) + ); const handleSubmit = async () => { - console.log(`${EditSets.name}.handleSubmit:`, { uri: newImage, name }) - const update: Partial = {} - if (name) update.name = name - if (reps) update.reps = Number(reps) - if (weight) update.weight = Number(weight) - if (unit) update.unit = unit - if (newImage) update.image = newImage - if (Object.keys(update).length > 0) await setRepo.update(ids, update) - navigation.goBack() - } + console.log(`${EditSets.name}.handleSubmit:`, { uri: newImage, name }); + const update: Partial = {}; + if (name) update.name = name; + if (reps) update.reps = Number(reps); + if (weight) update.weight = Number(weight); + if (unit) update.unit = unit; + if (newImage) update.image = newImage; + if (Object.keys(update).length > 0) await setRepo.update(ids, update); + navigation.goBack(); + }; const changeImage = useCallback(async () => { const { fileCopyUri } = await DocumentPicker.pickSingle({ type: DocumentPicker.types.images, - copyTo: 'documentDirectory', - }) - if (fileCopyUri) setNewImage(fileCopyUri) - }, []) + copyTo: "documentDirectory", + }); + if (fileCopyUri) setNewImage(fileCopyUri); + }, []); const handleRemove = useCallback(async () => { - setNewImage('') - setShowRemove(false) - }, []) + setNewImage(""); + setShowRemove(false); + }, []); return ( <> @@ -91,7 +91,7 @@ export default function EditSets() { )} Image @@ -146,13 +146,13 @@ export default function EditSets() { - ) + ); } diff --git a/EditWorkout.tsx b/EditWorkout.tsx index 5b11710f..33f8c5a2 100644 --- a/EditWorkout.tsx +++ b/EditWorkout.tsx @@ -3,46 +3,46 @@ import { useFocusEffect, useNavigation, useRoute, -} from '@react-navigation/native' -import { useCallback, useRef, useState } from 'react' -import { ScrollView, TextInput, View } from 'react-native' -import DocumentPicker from 'react-native-document-picker' -import { Button, Card, TouchableRipple } from 'react-native-paper' -import AppInput from './AppInput' -import ConfirmDialog from './ConfirmDialog' -import { MARGIN, PADDING } from './constants' -import { getNow, planRepo, setRepo, settingsRepo } from './db' -import { defaultSet } from './gym-set' -import Settings from './settings' -import StackHeader from './StackHeader' -import { WorkoutsPageParams } from './WorkoutsPage' +} from "@react-navigation/native"; +import { useCallback, useRef, useState } from "react"; +import { ScrollView, TextInput, View } from "react-native"; +import DocumentPicker from "react-native-document-picker"; +import { Button, Card, TouchableRipple } from "react-native-paper"; +import AppInput from "./AppInput"; +import ConfirmDialog from "./ConfirmDialog"; +import { MARGIN, PADDING } from "./constants"; +import { getNow, planRepo, setRepo, settingsRepo } from "./db"; +import { defaultSet } from "./gym-set"; +import Settings from "./settings"; +import StackHeader from "./StackHeader"; +import { WorkoutsPageParams } from "./WorkoutsPage"; export default function EditWorkout() { - const { params } = useRoute>() - const [removeImage, setRemoveImage] = useState(false) - const [showRemove, setShowRemove] = useState(false) - const [name, setName] = useState(params.value.name) - const [steps, setSteps] = useState(params.value.steps) - const [uri, setUri] = useState(params.value.image) + const { params } = useRoute>(); + const [removeImage, setRemoveImage] = useState(false); + const [showRemove, setShowRemove] = useState(false); + const [name, setName] = useState(params.value.name); + const [steps, setSteps] = useState(params.value.steps); + const [uri, setUri] = useState(params.value.image); const [minutes, setMinutes] = useState( - params.value.minutes?.toString() ?? '3', - ) + params.value.minutes?.toString() ?? "3" + ); const [seconds, setSeconds] = useState( - params.value.seconds?.toString() ?? '30', - ) - const [sets, setSets] = useState(params.value.sets?.toString() ?? '3') - const navigation = useNavigation() - const setsRef = useRef(null) - const stepsRef = useRef(null) - const minutesRef = useRef(null) - const secondsRef = useRef(null) - const [settings, setSettings] = useState() + params.value.seconds?.toString() ?? "30" + ); + const [sets, setSets] = useState(params.value.sets?.toString() ?? "3"); + const navigation = useNavigation(); + const setsRef = useRef(null); + const stepsRef = useRef(null); + const minutesRef = useRef(null); + const secondsRef = useRef(null); + const [settings, setSettings] = useState(); useFocusEffect( useCallback(() => { - settingsRepo.findOne({ where: {} }).then(setSettings) - }, []), - ) + settingsRepo.findOne({ where: {} }).then(setSettings); + }, []) + ); const update = async () => { await setRepo.update( @@ -53,20 +53,20 @@ export default function EditWorkout() { minutes: +minutes, seconds: +seconds, steps, - image: removeImage ? '' : uri, - }, - ) + image: removeImage ? "" : uri, + } + ); await planRepo.query( `UPDATE plans SET workouts = REPLACE(workouts, $1, $2) WHERE workouts LIKE $3`, - [params.value.name, name, `%${params.value.name}%`], - ) - navigation.goBack() - } + [params.value.name, name, `%${params.value.name}%`] + ); + navigation.goBack(); + }; const add = async () => { - const now = await getNow() + const now = await getNow(); await setRepo.save({ ...defaultSet, name, @@ -77,42 +77,42 @@ export default function EditWorkout() { sets: sets ? +sets : 3, steps, created: now, - }) - navigation.goBack() - } + }); + navigation.goBack(); + }; const save = async () => { - if (params.value.name) return update() - return add() - } + if (params.value.name) return update(); + return add(); + }; const changeImage = useCallback(async () => { const { fileCopyUri } = await DocumentPicker.pickSingle({ type: DocumentPicker.types.images, - copyTo: 'documentDirectory', - }) - if (fileCopyUri) setUri(fileCopyUri) - }, []) + copyTo: "documentDirectory", + }); + if (fileCopyUri) setUri(fileCopyUri); + }, []); const handleRemove = useCallback(async () => { - setUri('') - setRemoveImage(true) - setShowRemove(false) - }, []) + setUri(""); + setRemoveImage(true); + setShowRemove(false); + }, []); const submitName = () => { - if (settings.steps) stepsRef.current?.focus() - else setsRef.current?.focus() - } + if (settings.steps) stepsRef.current?.focus(); + else setsRef.current?.focus(); + }; return ( <> - + setsRef.current?.focus()} /> @@ -132,8 +132,8 @@ export default function EditWorkout() { innerRef={setsRef} value={sets} onChangeText={setSets} - label='Sets per workout' - keyboardType='numeric' + label="Sets per workout" + keyboardType="numeric" onSubmitEditing={() => minutesRef.current?.focus()} /> {settings?.alarm && ( @@ -143,15 +143,15 @@ export default function EditWorkout() { onSubmitEditing={() => secondsRef.current?.focus()} value={minutes} onChangeText={setMinutes} - label='Rest minutes' - keyboardType='numeric' + label="Rest minutes" + keyboardType="numeric" /> @@ -169,17 +169,17 @@ export default function EditWorkout() { )} - - ) + ); } diff --git a/GraphsPage.tsx b/GraphsPage.tsx index 4f5af6fd..cdbe4bb2 100644 --- a/GraphsPage.tsx +++ b/GraphsPage.tsx @@ -1,23 +1,23 @@ -import { createStackNavigator } from '@react-navigation/stack' -import GraphsList from './GraphsList' -import GymSet from './gym-set' -import ViewGraph from './ViewGraph' +import { createStackNavigator } from "@react-navigation/stack"; +import GraphsList from "./GraphsList"; +import GymSet from "./gym-set"; +import ViewGraph from "./ViewGraph"; -const Stack = createStackNavigator() +const Stack = createStackNavigator(); export type GraphsPageParams = { - GraphsList: {} + GraphsList: {}; ViewGraph: { - best: GymSet - } -} + best: GymSet; + }; +}; export default function GraphsPage() { return ( - - + + - ) + ); } diff --git a/HomePage.tsx b/HomePage.tsx index b89b3a44..1732e148 100644 --- a/HomePage.tsx +++ b/HomePage.tsx @@ -1,19 +1,19 @@ -import { createStackNavigator } from '@react-navigation/stack' -import EditSet from './EditSet' -import EditSets from './EditSets' -import { HomePageParams } from './home-page-params' -import SetList from './SetList' +import { createStackNavigator } from "@react-navigation/stack"; +import EditSet from "./EditSet"; +import EditSets from "./EditSets"; +import { HomePageParams } from "./home-page-params"; +import SetList from "./SetList"; -const Stack = createStackNavigator() +const Stack = createStackNavigator(); export default function HomePage() { return ( - - - + + + - ) + ); } diff --git a/ListMenu.tsx b/ListMenu.tsx index cf28e610..5c22841b 100644 --- a/ListMenu.tsx +++ b/ListMenu.tsx @@ -1,6 +1,6 @@ -import { useState } from 'react' -import { Divider, IconButton, Menu } from 'react-native-paper' -import ConfirmDialog from './ConfirmDialog' +import { useState } from "react"; +import { Divider, IconButton, Menu } from "react-native-paper"; +import ConfirmDialog from "./ConfirmDialog"; export default function ListMenu({ onEdit, @@ -10,88 +10,85 @@ export default function ListMenu({ onSelect, ids, }: { - onEdit: () => void - onCopy: () => void - onClear: () => void - onDelete: () => void - onSelect: () => void - ids?: number[] + onEdit: () => void; + onCopy: () => void; + onClear: () => void; + onDelete: () => void; + onSelect: () => void; + ids?: number[]; }) { - const [showMenu, setShowMenu] = useState(false) - const [showRemove, setShowRemove] = useState(false) + const [showMenu, setShowMenu] = useState(false); + const [showRemove, setShowRemove] = useState(false); const edit = () => { - setShowMenu(false) - onEdit() - } + setShowMenu(false); + onEdit(); + }; const copy = () => { - setShowMenu(false) - onCopy() - } + setShowMenu(false); + onCopy(); + }; const clear = () => { - setShowMenu(false) - onClear() - } + setShowMenu(false); + onClear(); + }; const remove = () => { - setShowMenu(false) - setShowRemove(false) - onDelete() - } + setShowMenu(false); + setShowRemove(false); + onDelete(); + }; const select = () => { - onSelect() - } + onSelect(); + }; return ( setShowMenu(false)} - anchor={ - setShowMenu(true)} - icon='more-vert' - /> - } + anchor={ setShowMenu(true)} icon="more-vert" />} > - + setShowRemove(true)} - title='Delete' + title="Delete" /> setShowMenu(false)} > - {ids?.length === 0 - ? <>This irreversibly deletes records from the app. Are you sure? - : <>This will delete {ids?.length} record(s). Are you sure?} + {ids?.length === 0 ? ( + <>This irreversibly deletes records from the app. Are you sure? + ) : ( + <>This will delete {ids?.length} record(s). Are you sure? + )} - ) + ); } diff --git a/Page.tsx b/Page.tsx index c46372f3..9f53dc6d 100644 --- a/Page.tsx +++ b/Page.tsx @@ -1,7 +1,7 @@ -import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native' -import { Searchbar } from 'react-native-paper' -import AppFab from './AppFab' -import { PADDING } from './constants' +import { StyleProp, StyleSheet, View, ViewStyle } from "react-native"; +import { Searchbar } from "react-native-paper"; +import AppFab from "./AppFab"; +import { PADDING } from "./constants"; export default function Page({ onAdd, @@ -10,25 +10,25 @@ export default function Page({ search, style, }: { - children: JSX.Element | JSX.Element[] - onAdd?: () => void - term: string - search: (value: string) => void - style?: StyleProp + children: JSX.Element | JSX.Element[]; + onAdd?: () => void; + term: string; + search: (value: string) => void; + style?: StyleProp; }) { return ( {children} {onAdd && } - ) + ); } const styles = StyleSheet.create({ @@ -36,4 +36,4 @@ const styles = StyleSheet.create({ padding: PADDING, flexGrow: 1, }, -}) +}); diff --git a/PlanItem.tsx b/PlanItem.tsx index 067a9eee..85a6705e 100644 --- a/PlanItem.tsx +++ b/PlanItem.tsx @@ -2,91 +2,89 @@ import { NavigationProp, useFocusEffect, useNavigation, -} from '@react-navigation/native' -import { useCallback, useMemo, useState } from 'react' -import { Text } from 'react-native' -import { List } from 'react-native-paper' -import { DARK_RIPPLE, LIGHT_RIPPLE } from './constants' -import { setRepo } from './db' -import { defaultSet } from './gym-set' -import { Plan } from './plan' -import { PlanPageParams } from './plan-page-params' -import { DAYS } from './time' -import useDark from './use-dark' +} from "@react-navigation/native"; +import { useCallback, useMemo, useState } from "react"; +import { Text } from "react-native"; +import { List } from "react-native-paper"; +import { DARK_RIPPLE, LIGHT_RIPPLE } from "./constants"; +import { setRepo } from "./db"; +import { defaultSet } from "./gym-set"; +import { Plan } from "./plan"; +import { PlanPageParams } from "./plan-page-params"; +import { DAYS } from "./time"; +import useDark from "./use-dark"; export default function PlanItem({ item, setIds, ids, }: { - item: Plan - ids: number[] - setIds: (value: number[]) => void + item: Plan; + ids: number[]; + setIds: (value: number[]) => void; }) { - const [today, setToday] = useState() - const dark = useDark() - const days = useMemo(() => item.days.split(','), [item.days]) - const navigation = useNavigation>() + const [today, setToday] = useState(); + const dark = useDark(); + const days = useMemo(() => item.days.split(","), [item.days]); + const navigation = useNavigation>(); useFocusEffect( useCallback(() => { - const newToday = DAYS[new Date().getDay()] - setToday(newToday) - }, []), - ) + const newToday = DAYS[new Date().getDay()]; + setToday(newToday); + }, []) + ); const start = useCallback(async () => { - const workout = item.workouts.split(',')[0] + const workout = item.workouts.split(",")[0]; let first = await setRepo.findOne({ where: { name: workout }, - order: { created: 'desc' }, - }) - if (!first) first = { ...defaultSet, name: workout } - delete first.id + order: { created: "desc" }, + }); + if (!first) first = { ...defaultSet, name: workout }; + delete first.id; if (ids.length === 0) { - return navigation.navigate('StartPlan', { plan: item, first }) + return navigation.navigate("StartPlan", { plan: item, first }); } - const removing = ids.find((id) => id === item.id) - if (removing) setIds(ids.filter((id) => id !== item.id)) - else setIds([...ids, item.id]) - }, [ids, setIds, item, navigation]) + const removing = ids.find((id) => id === item.id); + if (removing) setIds(ids.filter((id) => id !== item.id)); + else setIds([...ids, item.id]); + }, [ids, setIds, item, navigation]); const longPress = useCallback(() => { - if (ids.length > 0) return - setIds([item.id]) - }, [ids.length, item.id, setIds]) + if (ids.length > 0) return; + setIds([item.id]); + }, [ids.length, item.id, setIds]); const title = useMemo( () => days.map((day, index) => ( - {day === today - ? ( - - {day} - - ) - : ( - day - )} - {index === days.length - 1 ? '' : ', '} + {day === today ? ( + + {day} + + ) : ( + day + )} + {index === days.length - 1 ? "" : ", "} )), - [days, today], - ) + [days, today] + ); const description = useMemo( - () => item.workouts.replace(/,/g, ', '), - [item.workouts], - ) + () => item.workouts.replace(/,/g, ", "), + [item.workouts] + ); const backgroundColor = useMemo(() => { - if (!ids.includes(item.id)) return - if (dark) return DARK_RIPPLE - return LIGHT_RIPPLE - }, [dark, ids, item.id]) + if (!ids.includes(item.id)) return; + if (dark) return DARK_RIPPLE; + return LIGHT_RIPPLE; + }, [dark, ids, item.id]); return ( - ) + ); } diff --git a/PlanList.tsx b/PlanList.tsx index 82b55ce0..4cc5cca6 100644 --- a/PlanList.tsx +++ b/PlanList.tsx @@ -2,24 +2,24 @@ import { NavigationProp, useFocusEffect, useNavigation, -} from '@react-navigation/native' -import { useCallback, useState } from 'react' -import { FlatList } from 'react-native' -import { List } from 'react-native-paper' -import { Like } from 'typeorm' -import { planRepo } from './db' -import DrawerHeader from './DrawerHeader' -import ListMenu from './ListMenu' -import Page from './Page' -import { Plan } from './plan' -import { PlanPageParams } from './plan-page-params' -import PlanItem from './PlanItem' +} from "@react-navigation/native"; +import { useCallback, useState } from "react"; +import { FlatList } from "react-native"; +import { List } from "react-native-paper"; +import { Like } from "typeorm"; +import { planRepo } from "./db"; +import DrawerHeader from "./DrawerHeader"; +import ListMenu from "./ListMenu"; +import Page from "./Page"; +import { Plan } from "./plan"; +import { PlanPageParams } from "./plan-page-params"; +import PlanItem from "./PlanItem"; export default function PlanList() { - const [term, setTerm] = useState('') - const [plans, setPlans] = useState() - const [ids, setIds] = useState([]) - const navigation = useNavigation>() + const [term, setTerm] = useState(""); + const [plans, setPlans] = useState(); + const [ids, setIds] = useState([]); + const navigation = useNavigation>(); const refresh = useCallback(async (value: string) => { planRepo @@ -29,65 +29,65 @@ export default function PlanList() { { workouts: Like(`%${value.trim()}%`) }, ], }) - .then(setPlans) - }, []) + .then(setPlans); + }, []); useFocusEffect( useCallback(() => { - refresh(term) - }, [refresh, term]), - ) + refresh(term); + }, [refresh, term]) + ); const search = useCallback( (value: string) => { - setTerm(value) - refresh(value) + setTerm(value); + refresh(value); }, - [refresh], - ) + [refresh] + ); const renderItem = useCallback( ({ item }: { item: Plan }) => ( ), - [ids], - ) + [ids] + ); const onAdd = () => - navigation.navigate('EditPlan', { plan: { days: '', workouts: '' } }) + navigation.navigate("EditPlan", { plan: { days: "", workouts: "" } }); const edit = useCallback(async () => { - const plan = await planRepo.findOne({ where: { id: ids.pop() } }) - navigation.navigate('EditPlan', { plan }) - setIds([]) - }, [ids, navigation]) + const plan = await planRepo.findOne({ where: { id: ids.pop() } }); + navigation.navigate("EditPlan", { plan }); + setIds([]); + }, [ids, navigation]); const copy = useCallback(async () => { const plan = await planRepo.findOne({ where: { id: ids.pop() }, - }) - delete plan.id - navigation.navigate('EditPlan', { plan }) - setIds([]) - }, [ids, navigation]) + }); + delete plan.id; + navigation.navigate("EditPlan", { plan }); + setIds([]); + }, [ids, navigation]); const clear = useCallback(() => { - setIds([]) - }, []) + setIds([]); + }, []); const remove = useCallback(async () => { - await planRepo.delete(ids.length > 0 ? ids : {}) - await refresh(term) - setIds([]) - }, [ids, refresh, term]) + await planRepo.delete(ids.length > 0 ? ids : {}); + await refresh(term); + setIds([]); + }, [ids, refresh, term]); const select = useCallback(() => { - setIds(plans.map((plan) => plan.id)) - }, [plans]) + setIds(plans.map((plan) => plan.id)); + }, [plans]); return ( <> - 0 ? `${ids.length} selected` : 'Plans'}> + 0 ? `${ids.length} selected` : "Plans"}> - {plans?.length === 0 - ? ( - - ) - : ( - set.id?.toString() || ''} - /> - )} + {plans?.length === 0 ? ( + + ) : ( + set.id?.toString() || ""} + /> + )} - ) + ); } diff --git a/PlanPage.tsx b/PlanPage.tsx index 3cc4c2b8..a0dfabd5 100644 --- a/PlanPage.tsx +++ b/PlanPage.tsx @@ -1,21 +1,21 @@ -import { createStackNavigator } from '@react-navigation/stack' -import EditPlan from './EditPlan' -import EditSet from './EditSet' -import { PlanPageParams } from './plan-page-params' -import PlanList from './PlanList' -import StartPlan from './StartPlan' +import { createStackNavigator } from "@react-navigation/stack"; +import EditPlan from "./EditPlan"; +import EditSet from "./EditSet"; +import { PlanPageParams } from "./plan-page-params"; +import PlanList from "./PlanList"; +import StartPlan from "./StartPlan"; -const Stack = createStackNavigator() +const Stack = createStackNavigator(); export default function PlanPage() { return ( - - - - + + + + - ) + ); } diff --git a/Routes.tsx b/Routes.tsx index 14984960..e51b5c6e 100644 --- a/Routes.tsx +++ b/Routes.tsx @@ -1,57 +1,57 @@ -import { createDrawerNavigator } from '@react-navigation/drawer' -import { IconButton } from 'react-native-paper' -import GraphsPage from './GraphsPage' -import { DrawerParamList } from './drawer-param-list' -import HomePage from './HomePage' -import PlanPage from './PlanPage' -import SettingsPage from './SettingsPage' -import TimerPage from './TimerPage' -import useDark from './use-dark' -import WorkoutsPage from './WorkoutsPage' +import { createDrawerNavigator } from "@react-navigation/drawer"; +import { IconButton } from "react-native-paper"; +import GraphsPage from "./GraphsPage"; +import { DrawerParamList } from "./drawer-param-list"; +import HomePage from "./HomePage"; +import PlanPage from "./PlanPage"; +import SettingsPage from "./SettingsPage"; +import TimerPage from "./TimerPage"; +import useDark from "./use-dark"; +import WorkoutsPage from "./WorkoutsPage"; -const Drawer = createDrawerNavigator() +const Drawer = createDrawerNavigator(); export default function Routes() { - const dark = useDark() + const dark = useDark(); return ( }} + options={{ drawerIcon: () => }} /> }} + options={{ drawerIcon: () => }} /> }} + options={{ drawerIcon: () => }} /> }} + options={{ drawerIcon: () => }} /> }} + options={{ drawerIcon: () => }} /> }} + options={{ drawerIcon: () => }} /> - ) + ); } diff --git a/Select.tsx b/Select.tsx index 5a6dc669..87aacad7 100644 --- a/Select.tsx +++ b/Select.tsx @@ -1,12 +1,12 @@ -import React, { useCallback, useMemo, useState } from 'react' -import { View } from 'react-native' -import { Button, Menu, Subheading } from 'react-native-paper' -import { ITEM_PADDING } from './constants' +import React, { useCallback, useMemo, useState } from "react"; +import { View } from "react-native"; +import { Button, Menu, Subheading } from "react-native-paper"; +import { ITEM_PADDING } from "./constants"; export interface Item { - value: string - label: string - color?: string + value: string; + label: string; + color?: string; } function Select({ @@ -15,31 +15,31 @@ function Select({ items, label, }: { - value: string - onChange: (value: string) => void - items: Item[] - label?: string + value: string; + onChange: (value: string) => void; + items: Item[]; + label?: string; }) { - const [show, setShow] = useState(false) + const [show, setShow] = useState(false); const selected = useMemo( () => items.find((item) => item.value === value) || items[0], - [items, value], - ) + [items, value] + ); const handlePress = useCallback( (newValue: string) => { - onChange(newValue) - setShow(false) + onChange(newValue); + setShow(false); }, - [onChange], - ) + [onChange] + ); return ( @@ -51,7 +51,7 @@ function Select({ - ) + ); } return ( - - ) + ); } diff --git a/SettingsPage.tsx b/SettingsPage.tsx index 3fd8d647..eca3aae9 100644 --- a/SettingsPage.tsx +++ b/SettingsPage.tsx @@ -1,57 +1,57 @@ -import { NavigationProp, useNavigation } from '@react-navigation/native' -import { format } from 'date-fns' -import { useCallback, useEffect, useMemo, useState } from 'react' -import { useForm } from 'react-hook-form' -import { NativeModules, ScrollView } from 'react-native' -import DocumentPicker from 'react-native-document-picker' -import { Dirs, FileSystem } from 'react-native-file-access' -import ConfirmDialog from './ConfirmDialog' -import { MARGIN } from './constants' -import { AppDataSource } from './data-source' -import { setRepo, settingsRepo } from './db' -import { DrawerParamList } from './drawer-param-list' -import DrawerHeader from './DrawerHeader' -import Input from './input' -import { darkOptions, lightOptions, themeOptions } from './options' -import Page from './Page' -import Select from './Select' -import SettingButton from './SettingButton' -import Settings from './settings' -import Switch from './Switch' -import { toast } from './toast' -import { useTheme } from './use-theme' +import { NavigationProp, useNavigation } from "@react-navigation/native"; +import { format } from "date-fns"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { useForm } from "react-hook-form"; +import { NativeModules, ScrollView } from "react-native"; +import DocumentPicker from "react-native-document-picker"; +import { Dirs, FileSystem } from "react-native-file-access"; +import ConfirmDialog from "./ConfirmDialog"; +import { MARGIN } from "./constants"; +import { AppDataSource } from "./data-source"; +import { setRepo, settingsRepo } from "./db"; +import { DrawerParamList } from "./drawer-param-list"; +import DrawerHeader from "./DrawerHeader"; +import Input from "./input"; +import { darkOptions, lightOptions, themeOptions } from "./options"; +import Page from "./Page"; +import Select from "./Select"; +import SettingButton from "./SettingButton"; +import Settings from "./settings"; +import Switch from "./Switch"; +import { toast } from "./toast"; +import { useTheme } from "./use-theme"; const twelveHours = [ - 'dd/LL/yyyy', - 'dd/LL/yyyy, p', - 'ccc p', - 'p', - 'yyyy-MM-d', - 'yyyy-MM-d, p', - 'yyyy.MM.d', -] + "dd/LL/yyyy", + "dd/LL/yyyy, p", + "ccc p", + "p", + "yyyy-MM-d", + "yyyy-MM-d, p", + "yyyy.MM.d", +]; const twentyFours = [ - 'dd/LL/yyyy', - 'dd/LL/yyyy, k:m', - 'ccc k:m', - 'k:m', - 'yyyy-MM-d', - 'yyyy-MM-d, k:m', - 'yyyy.MM.d', -] + "dd/LL/yyyy", + "dd/LL/yyyy, k:m", + "ccc k:m", + "k:m", + "yyyy-MM-d", + "yyyy-MM-d, k:m", + "yyyy.MM.d", +]; export default function SettingsPage() { - const [ignoring, setIgnoring] = useState(false) - const [term, setTerm] = useState('') - const [formatOptions, setFormatOptions] = useState(twelveHours) - const [importing, setImporting] = useState(false) - const [deleting, setDeleting] = useState(false) - const { reset } = useNavigation>() + const [ignoring, setIgnoring] = useState(false); + const [term, setTerm] = useState(""); + const [formatOptions, setFormatOptions] = useState(twelveHours); + const [importing, setImporting] = useState(false); + const [deleting, setDeleting] = useState(false); + const { reset } = useNavigation>(); const { watch, setValue } = useForm({ defaultValues: () => settingsRepo.findOne({ where: {} }), - }) - const settings = watch() + }); + const settings = watch(); const { theme, @@ -60,16 +60,16 @@ export default function SettingsPage() { setLightColor, darkColor, setDarkColor, - } = useTheme() + } = useTheme(); useEffect(() => { - NativeModules.SettingsModule.ignoringBattery(setIgnoring) + NativeModules.SettingsModule.ignoringBattery(setIgnoring); NativeModules.SettingsModule.is24().then((is24: boolean) => { - console.log(`${SettingsPage.name}.focus:`, { is24 }) - if (is24) setFormatOptions(twentyFours) - else setFormatOptions(twelveHours) - }) - }, []) + console.log(`${SettingsPage.name}.focus:`, { is24 }); + if (is24) setFormatOptions(twentyFours); + else setFormatOptions(twelveHours); + }); + }, []); const update = useCallback((key: keyof Settings, value: unknown) => { return settingsRepo @@ -77,98 +77,98 @@ export default function SettingsPage() { .update() .set({ [key]: value }) .printSql() - .execute() - }, []) + .execute(); + }, []); const soundString = useMemo(() => { - if (!settings.sound) return null - const split = settings.sound.split('/') - return split.pop() - }, [settings.sound]) + if (!settings.sound) return null; + const split = settings.sound.split("/"); + return split.pop(); + }, [settings.sound]); const changeSound = useCallback(async () => { const { fileCopyUri } = await DocumentPicker.pickSingle({ type: DocumentPicker.types.audio, - copyTo: 'documentDirectory', - }) - if (!fileCopyUri) return - setValue('sound', fileCopyUri) - await update('sound', fileCopyUri) - toast('Sound will play after rest timers.') - }, [setValue, update]) + copyTo: "documentDirectory", + }); + if (!fileCopyUri) return; + setValue("sound", fileCopyUri); + await update("sound", fileCopyUri); + toast("Sound will play after rest timers."); + }, [setValue, update]); const switches: Input[] = useMemo( () => [ - { name: 'Rest timers', value: settings.alarm, key: 'alarm' }, - { name: 'Vibrate', value: settings.vibrate, key: 'vibrate' }, - { name: 'Disable sound', value: settings.noSound, key: 'noSound' }, - { name: 'Notifications', value: settings.notify, key: 'notify' }, - { name: 'Show images', value: settings.images, key: 'images' }, - { name: 'Show unit', value: settings.showUnit, key: 'showUnit' }, - { name: 'Show steps', value: settings.steps, key: 'steps' }, - { name: 'Show date', value: settings.showDate, key: 'showDate' }, - { name: 'Automatic backup', value: settings.backup, key: 'backup' }, + { name: "Rest timers", value: settings.alarm, key: "alarm" }, + { name: "Vibrate", value: settings.vibrate, key: "vibrate" }, + { name: "Disable sound", value: settings.noSound, key: "noSound" }, + { name: "Notifications", value: settings.notify, key: "notify" }, + { name: "Show images", value: settings.images, key: "images" }, + { name: "Show unit", value: settings.showUnit, key: "showUnit" }, + { name: "Show steps", value: settings.steps, key: "steps" }, + { name: "Show date", value: settings.showDate, key: "showDate" }, + { name: "Automatic backup", value: settings.backup, key: "backup" }, ], - [settings], - ) + [settings] + ); const filter = useCallback( ({ name }) => name.toLowerCase().includes(term.toLowerCase()), - [term], - ) + [term] + ); const changeBoolean = useCallback( async (key: keyof Settings, value: boolean) => { - setValue(key, value) - await update(key, value) + setValue(key, value); + await update(key, value); switch (key) { - case 'alarm': - if (value) toast('Timers will now run after each set.') - else toast('Stopped timers running after each set.') - if (value && !ignoring) NativeModules.SettingsModule.ignoreBattery() - return - case 'vibrate': - if (value) toast('Alarms will now vibrate.') - else toast('Alarms will no longer vibrate.') - return - case 'notify': - if (value) toast('Show notifications for new records.') - else toast('Stopped notifications for new records.') - return - case 'images': - if (value) toast('Show images for sets.') - else toast('Hid images for sets.') - return - case 'showUnit': - if (value) toast('Show option to select unit for sets.') - else toast('Hid unit option for sets.') - return - case 'steps': - if (value) toast('Show steps for a workout.') - else toast('Hid steps for workouts.') - return - case 'showDate': - if (value) toast('Show date for sets.') - else toast('Hid date on sets.') - return - case 'noSound': - if (value) toast('Disable sound on rest timer alarms.') - else toast('Enabled sound for rest timer alarms.') - return - case 'backup': + case "alarm": + if (value) toast("Timers will now run after each set."); + else toast("Stopped timers running after each set."); + if (value && !ignoring) NativeModules.SettingsModule.ignoreBattery(); + return; + case "vibrate": + if (value) toast("Alarms will now vibrate."); + else toast("Alarms will no longer vibrate."); + return; + case "notify": + if (value) toast("Show notifications for new records."); + else toast("Stopped notifications for new records."); + return; + case "images": + if (value) toast("Show images for sets."); + else toast("Hid images for sets."); + return; + case "showUnit": + if (value) toast("Show option to select unit for sets."); + else toast("Hid unit option for sets."); + return; + case "steps": + if (value) toast("Show steps for a workout."); + else toast("Hid steps for workouts."); + return; + case "showDate": + if (value) toast("Show date for sets."); + else toast("Hid date on sets."); + return; + case "noSound": + if (value) toast("Disable sound on rest timer alarms."); + else toast("Enabled sound for rest timer alarms."); + return; + case "backup": if (value) { - const result = await DocumentPicker.pickDirectory() - toast('Backup database daily.') - NativeModules.BackupModule.start(result.uri) + const result = await DocumentPicker.pickDirectory(); + toast("Backup database daily."); + NativeModules.BackupModule.start(result.uri); } else { - toast('Stopped backing up daily') - NativeModules.BackupModule.stop() + toast("Stopped backing up daily"); + NativeModules.BackupModule.stop(); } - return + return; } }, - [ignoring, setValue, update], - ) + [ignoring, setValue, update] + ); const renderSwitch = useCallback( (item: Input) => ( @@ -179,69 +179,69 @@ export default function SettingsPage() { title={item.name} /> ), - [changeBoolean], - ) + [changeBoolean] + ); const switchesMarkup = useMemo( () => switches.filter(filter).map((s) => renderSwitch(s)), - [filter, switches, renderSwitch], - ) + [filter, switches, renderSwitch] + ); const changeString = useCallback( async (key: keyof Settings, value: string) => { - setValue(key, value) - await update(key, value) + setValue(key, value); + await update(key, value); switch (key) { - case 'date': - return toast('Changed date format') - case 'darkColor': - setDarkColor(value) - return toast('Set primary color for dark mode.') - case 'lightColor': - setLightColor(value) - return toast('Set primary color for light mode.') - case 'vibrate': - return toast('Set primary color for light mode.') - case 'sound': - return toast('Sound will play after rest timers.') - case 'theme': - setTheme(value as string) - if (value === 'dark') toast('Theme will always be dark.') - else if (value === 'light') toast('Theme will always be light.') - else if (value === 'system') toast('Theme will follow system.') - return + case "date": + return toast("Changed date format"); + case "darkColor": + setDarkColor(value); + return toast("Set primary color for dark mode."); + case "lightColor": + setLightColor(value); + return toast("Set primary color for light mode."); + case "vibrate": + return toast("Set primary color for light mode."); + case "sound": + return toast("Sound will play after rest timers."); + case "theme": + setTheme(value as string); + if (value === "dark") toast("Theme will always be dark."); + else if (value === "light") toast("Theme will always be light."); + else if (value === "system") toast("Theme will follow system."); + return; } }, - [update, setTheme, setDarkColor, setLightColor, setValue], - ) + [update, setTheme, setDarkColor, setLightColor, setValue] + ); const selects: Input[] = useMemo(() => { - const today = new Date() + const today = new Date(); return [ - { name: 'Theme', value: theme, items: themeOptions, key: 'theme' }, + { name: "Theme", value: theme, items: themeOptions, key: "theme" }, { - name: 'Dark color', + name: "Dark color", value: darkColor, items: lightOptions, - key: 'darkColor', + key: "darkColor", }, { - name: 'Light color', + name: "Light color", value: lightColor, items: darkOptions, - key: 'lightColor', + key: "lightColor", }, { - name: 'Date format', + name: "Date format", value: settings.date, items: formatOptions.map((option) => ({ label: format(today, option), value: option, })), - key: 'date', + key: "date", }, - ] - }, [settings, darkColor, formatOptions, theme, lightColor]) + ]; + }, [settings, darkColor, formatOptions, theme, lightColor]); const renderSelect = useCallback( (item: Input) => ( @@ -253,74 +253,72 @@ export default function SettingsPage() { items={item.items} /> ), - [changeString], - ) + [changeString] + ); const selectsMarkup = useMemo( () => selects.filter(filter).map(renderSelect), - [filter, selects, renderSelect], - ) + [filter, selects, renderSelect] + ); const confirmDelete = useCallback(async () => { - setDeleting(false) - await AppDataSource.dropDatabase() - await AppDataSource.destroy() - await AppDataSource.initialize() - toast('Database deleted.') - }, []) + setDeleting(false); + await AppDataSource.dropDatabase(); + await AppDataSource.destroy(); + await AppDataSource.initialize(); + toast("Database deleted."); + }, []); const confirmImport = useCallback(async () => { - setImporting(false) - await AppDataSource.destroy() - const file = await DocumentPicker.pickSingle() - await FileSystem.cp(file.uri, Dirs.DatabaseDir + '/massive.db') - await AppDataSource.initialize() - await setRepo.createQueryBuilder().update().set({ image: null }).execute() - await update('sound', null) - const { alarm, backup } = await settingsRepo.findOne({ where: {} }) - console.log({ backup }) - const directory = await DocumentPicker.pickDirectory() - if (backup) NativeModules.BackupModule.start(directory.uri) - else NativeModules.BackupModule.stop() - NativeModules.SettingsModule.ignoringBattery( - (isIgnoring: boolean) => { - if (alarm && !isIgnoring) NativeModules.SettingsModule.ignoreBattery() - reset({ index: 0, routes: [{ name: 'Settings' }] }) - }, - ) - }, [reset, update]) + setImporting(false); + await AppDataSource.destroy(); + const file = await DocumentPicker.pickSingle(); + await FileSystem.cp(file.uri, Dirs.DatabaseDir + "/massive.db"); + await AppDataSource.initialize(); + await setRepo.createQueryBuilder().update().set({ image: null }).execute(); + await update("sound", null); + const { alarm, backup } = await settingsRepo.findOne({ where: {} }); + console.log({ backup }); + const directory = await DocumentPicker.pickDirectory(); + if (backup) NativeModules.BackupModule.start(directory.uri); + else NativeModules.BackupModule.stop(); + NativeModules.SettingsModule.ignoringBattery((isIgnoring: boolean) => { + if (alarm && !isIgnoring) NativeModules.SettingsModule.ignoreBattery(); + reset({ index: 0, routes: [{ name: "Settings" }] }); + }); + }, [reset, update]); const exportDatabase = useCallback(async () => { - const path = Dirs.DatabaseDir + '/massive.db' - await FileSystem.cpExternal(path, 'massive.db', 'downloads') - toast('Database exported. Check downloads.') - }, []) + const path = Dirs.DatabaseDir + "/massive.db"; + await FileSystem.cpExternal(path, "massive.db", "downloads"); + toast("Database exported. Check downloads."); + }, []); const buttons = useMemo( () => [ { - name: soundString || 'Default', + name: soundString || "Default", onPress: changeSound, - label: 'Alarm sound', + label: "Alarm sound", }, - { name: 'Export database', onPress: exportDatabase }, - { name: 'Import database', onPress: () => setImporting(true) }, - { name: 'Delete database', onPress: () => setDeleting(true) }, + { name: "Export database", onPress: exportDatabase }, + { name: "Import database", onPress: () => setImporting(true) }, + { name: "Delete database", onPress: () => setDeleting(true) }, ], - [changeSound, exportDatabase, soundString], - ) + [changeSound, exportDatabase, soundString] + ); const buttonsMarkup = useMemo( () => - buttons.filter(filter).map((button) => ( - - )), - [buttons, filter], - ) + buttons + .filter(filter) + .map((button) => ), + [buttons, filter] + ); return ( <> - + @@ -331,7 +329,7 @@ export default function SettingsPage() { - ) + ); } diff --git a/StackHeader.tsx b/StackHeader.tsx index 31ab389a..fe057768 100644 --- a/StackHeader.tsx +++ b/StackHeader.tsx @@ -1,23 +1,20 @@ -import { useNavigation } from '@react-navigation/native' -import { Appbar, IconButton } from 'react-native-paper' +import { useNavigation } from "@react-navigation/native"; +import { Appbar, IconButton } from "react-native-paper"; export default function StackHeader({ title, children, }: { - title: string - children?: JSX.Element | JSX.Element[] + title: string; + children?: JSX.Element | JSX.Element[]; }) { - const navigation = useNavigation() + const navigation = useNavigation(); return ( - + {children} - ) + ); } diff --git a/StartPlan.tsx b/StartPlan.tsx index 1323ed4a..e4c69acd 100644 --- a/StartPlan.tsx +++ b/StartPlan.tsx @@ -4,46 +4,46 @@ import { useFocusEffect, useNavigation, useRoute, -} from '@react-navigation/native' -import { useCallback, useMemo, useRef, useState } from 'react' -import { FlatList, NativeModules, TextInput, View } from 'react-native' -import { Button, IconButton, ProgressBar } from 'react-native-paper' -import AppInput from './AppInput' -import { getBestSet } from './best.service' -import { PADDING } from './constants' -import CountMany from './count-many' -import { AppDataSource } from './data-source' -import { getNow, setRepo, settingsRepo } from './db' -import GymSet from './gym-set' -import { PlanPageParams } from './plan-page-params' -import Settings from './settings' -import StackHeader from './StackHeader' -import StartPlanItem from './StartPlanItem' -import { toast } from './toast' +} from "@react-navigation/native"; +import { useCallback, useMemo, useRef, useState } from "react"; +import { FlatList, NativeModules, TextInput, View } from "react-native"; +import { Button, IconButton, ProgressBar } from "react-native-paper"; +import AppInput from "./AppInput"; +import { getBestSet } from "./best.service"; +import { PADDING } from "./constants"; +import CountMany from "./count-many"; +import { AppDataSource } from "./data-source"; +import { getNow, setRepo, settingsRepo } from "./db"; +import GymSet from "./gym-set"; +import { PlanPageParams } from "./plan-page-params"; +import Settings from "./settings"; +import StackHeader from "./StackHeader"; +import StartPlanItem from "./StartPlanItem"; +import { toast } from "./toast"; export default function StartPlan() { - const { params } = useRoute>() - const [reps, setReps] = useState(params.first?.reps.toString() || '0') - const [weight, setWeight] = useState(params.first?.weight.toString() || '0') - const [unit, setUnit] = useState(params.first?.unit || 'kg') - const [selected, setSelected] = useState(0) - const [settings, setSettings] = useState() - const [counts, setCounts] = useState() - const weightRef = useRef(null) - const repsRef = useRef(null) - const unitRef = useRef(null) - const workouts = useMemo(() => params.plan.workouts.split(','), [params]) - const navigation = useNavigation>() + const { params } = useRoute>(); + const [reps, setReps] = useState(params.first?.reps.toString() || "0"); + const [weight, setWeight] = useState(params.first?.weight.toString() || "0"); + const [unit, setUnit] = useState(params.first?.unit || "kg"); + const [selected, setSelected] = useState(0); + const [settings, setSettings] = useState(); + const [counts, setCounts] = useState(); + const weightRef = useRef(null); + const repsRef = useRef(null); + const unitRef = useRef(null); + const workouts = useMemo(() => params.plan.workouts.split(","), [params]); + const navigation = useNavigation>(); const [selection, setSelection] = useState({ start: 0, end: 0, - }) + }); const refresh = useCallback(async () => { const questions = workouts .map((workout, index) => `('${workout}',${index})`) - .join(',') + .join(","); const select = ` SELECT workouts.name, COUNT(sets.id) as total, sets.sets FROM (select 0 as name, 0 as sequence union values ${questions}) as workouts @@ -54,45 +54,45 @@ export default function StartPlan() { ORDER BY workouts.sequence LIMIT -1 OFFSET 1 - ` - const newCounts = await AppDataSource.manager.query(select) - console.log(`${StartPlan.name}.focus:`, { newCounts }) - setCounts(newCounts) - }, [workouts]) + `; + const newCounts = await AppDataSource.manager.query(select); + console.log(`${StartPlan.name}.focus:`, { newCounts }); + setCounts(newCounts); + }, [workouts]); const select = useCallback( async (index: number, newCounts?: CountMany[]) => { - setSelected(index) - if (!counts && !newCounts) return - const workout = counts ? counts[index] : newCounts[index] - console.log(`${StartPlan.name}.next:`, { workout }) + setSelected(index); + if (!counts && !newCounts) return; + const workout = counts ? counts[index] : newCounts[index]; + console.log(`${StartPlan.name}.next:`, { workout }); const last = await setRepo.findOne({ where: { name: workout.name }, - order: { created: 'desc' }, - }) - console.log({ last }) - if (!last) return - delete last.id - console.log(`${StartPlan.name}.select:`, { last }) - setReps(last.reps.toString()) - setWeight(last.weight.toString()) - setUnit(last.unit) + order: { created: "desc" }, + }); + console.log({ last }); + if (!last) return; + delete last.id; + console.log(`${StartPlan.name}.select:`, { last }); + setReps(last.reps.toString()); + setWeight(last.weight.toString()); + setUnit(last.unit); }, - [counts], - ) + [counts] + ); useFocusEffect( useCallback(() => { - settingsRepo.findOne({ where: {} }).then(setSettings) - refresh() - }, [refresh]), - ) + settingsRepo.findOne({ where: {} }).then(setSettings); + refresh(); + }, [refresh]) + ); const handleSubmit = async () => { - const now = await getNow() - const workout = counts[selected] - const best = await getBestSet(workout.name) - delete best.id + const now = await getNow(); + const workout = counts[selected]; + const best = await getBestSet(workout.name); + delete best.id; const newSet: GymSet = { ...best, weight: +weight, @@ -100,34 +100,34 @@ export default function StartPlan() { unit, created: now, hidden: false, - } - await setRepo.save(newSet) - await refresh() + }; + await setRepo.save(newSet); + await refresh(); if ( settings.notify && (+weight > best.weight || (+reps > best.reps && +weight === best.weight)) ) { - toast("Great work King! That's a new record.") + toast("Great work King! That's a new record."); } - if (!settings.alarm) return - const milliseconds = Number(best.minutes) * 60 * 1000 + - Number(best.seconds) * 1000 - NativeModules.AlarmModule.timer(milliseconds) - } + if (!settings.alarm) return; + const milliseconds = + Number(best.minutes) * 60 * 1000 + Number(best.seconds) * 1000; + NativeModules.AlarmModule.timer(milliseconds); + }; return ( <> - + navigation.navigate('EditPlan', { plan: params.plan })} - icon='edit' + onPress={() => navigation.navigate("EditPlan", { plan: params.plan })} + icon="edit" /> - + weightRef.current?.focus()} @@ -136,8 +136,8 @@ export default function StartPlan() { innerRef={repsRef} /> {settings?.showUnit && ( )} - - ) + ); } diff --git a/StartPlanItem.tsx b/StartPlanItem.tsx index 3bf1533c..edcc1298 100644 --- a/StartPlanItem.tsx +++ b/StartPlanItem.tsx @@ -1,109 +1,112 @@ -import { NavigationProp, useNavigation } from '@react-navigation/native' -import React, { useCallback, useState } from 'react' -import { GestureResponderEvent, ListRenderItemInfo, View } from 'react-native' -import { List, Menu, RadioButton, useTheme } from 'react-native-paper' -import { Like } from 'typeorm' -import CountMany from './count-many' -import { getNow, setRepo } from './db' -import { PlanPageParams } from './plan-page-params' -import { toast } from './toast' +import { NavigationProp, useNavigation } from "@react-navigation/native"; +import React, { useCallback, useState } from "react"; +import { GestureResponderEvent, ListRenderItemInfo, View } from "react-native"; +import { List, Menu, RadioButton, useTheme } from "react-native-paper"; +import { Like } from "typeorm"; +import CountMany from "./count-many"; +import { getNow, setRepo } from "./db"; +import { PlanPageParams } from "./plan-page-params"; +import { toast } from "./toast"; interface Props extends ListRenderItemInfo { - onSelect: (index: number) => void - selected: number - onUndo: () => void + onSelect: (index: number) => void; + selected: number; + onUndo: () => void; } export default function StartPlanItem(props: Props) { - const { index, item, onSelect, selected, onUndo } = props - const { colors } = useTheme() - const [anchor, setAnchor] = useState({ x: 0, y: 0 }) - const [showMenu, setShowMenu] = useState(false) - const { navigate } = useNavigation>() + const { index, item, onSelect, selected, onUndo } = props; + const { colors } = useTheme(); + const [anchor, setAnchor] = useState({ x: 0, y: 0 }); + const [showMenu, setShowMenu] = useState(false); + const { navigate } = useNavigation>(); const undo = useCallback(async () => { - const now = await getNow() - const created = now.split('T')[0] + const now = await getNow(); + const created = now.split("T")[0]; const first = await setRepo.findOne({ where: { name: item.name, hidden: 0 as any, created: Like(`${created}%`), }, - order: { created: 'desc' }, - }) - setShowMenu(false) - if (!first) return toast('Nothing to undo.') - await setRepo.delete(first.id) - onUndo() - }, [setShowMenu, onUndo, item.name]) + order: { created: "desc" }, + }); + setShowMenu(false); + if (!first) return toast("Nothing to undo."); + await setRepo.delete(first.id); + onUndo(); + }, [setShowMenu, onUndo, item.name]); const longPress = useCallback( (e: GestureResponderEvent) => { - setAnchor({ x: e.nativeEvent.pageX, y: e.nativeEvent.pageY }) - setShowMenu(true) + setAnchor({ x: e.nativeEvent.pageX, y: e.nativeEvent.pageY }); + setShowMenu(true); }, - [setShowMenu, setAnchor], - ) + [setShowMenu, setAnchor] + ); const edit = useCallback(async () => { - const now = await getNow() - const created = now.split('T')[0] + const now = await getNow(); + const created = now.split("T")[0]; const first = await setRepo.findOne({ where: { name: item.name, hidden: 0 as any, created: Like(`${created}%`), }, - order: { created: 'desc' }, - }) - setShowMenu(false) - if (!first) return toast('Nothing to edit.') - navigate('EditSet', { set: first }) - }, [item.name, navigate]) + order: { created: "desc" }, + }); + setShowMenu(false); + if (!first) return toast("Nothing to edit."); + navigate("EditSet", { set: first }); + }, [item.name, navigate]); const left = useCallback( () => ( - + onSelect(index)} value={index.toString()} - status={selected === index ? 'checked' : 'unchecked'} + status={selected === index ? "checked" : "unchecked"} color={colors.primary} /> ), - [index, selected, colors.primary, onSelect], - ) + [index, selected, colors.primary, onSelect] + ); - const right = useCallback(() => ( - - setShowMenu(false)} + const right = useCallback( + () => ( + - - - - - ), [anchor, showMenu, edit, undo]) + setShowMenu(false)} + > + + + + + ), + [anchor, showMenu, edit, undo] + ); return ( onSelect(index)} left={left} right={right} /> - ) + ); } diff --git a/Switch.tsx b/Switch.tsx index 4fcfda3c..3cbf73d7 100644 --- a/Switch.tsx +++ b/Switch.tsx @@ -1,27 +1,27 @@ -import React from 'react' -import { Platform, Pressable } from 'react-native' -import { Switch as PaperSwitch, Text, useTheme } from 'react-native-paper' -import { MARGIN } from './constants' +import React from "react"; +import { Platform, Pressable } from "react-native"; +import { Switch as PaperSwitch, Text, useTheme } from "react-native-paper"; +import { MARGIN } from "./constants"; function Switch({ value, onChange, title, }: { - value?: boolean - onChange: (value: boolean) => void - title: string + value?: boolean; + onChange: (value: boolean) => void; + title: string; }) { - const { colors } = useTheme() + const { colors } = useTheme(); return ( onChange(!value)} style={{ - flexDirection: 'row', - flexWrap: 'wrap', - alignItems: 'center', - marginBottom: Platform.OS === 'ios' ? MARGIN : null, + flexDirection: "row", + flexWrap: "wrap", + alignItems: "center", + marginBottom: Platform.OS === "ios" ? MARGIN : null, }} > {title} - ) + ); } -export default React.memo(Switch) +export default React.memo(Switch); diff --git a/TimerPage.tsx b/TimerPage.tsx index 2879cba2..bd96cd94 100644 --- a/TimerPage.tsx +++ b/TimerPage.tsx @@ -1,60 +1,60 @@ -import { useFocusEffect } from '@react-navigation/native' -import React, { useCallback, useMemo, useState } from 'react' -import { Dimensions, NativeModules, View } from 'react-native' -import { Button, Text, useTheme } from 'react-native-paper' -import { ProgressCircle } from 'react-native-svg-charts' -import AppFab from './AppFab' -import { MARGIN, PADDING } from './constants' -import { settingsRepo } from './db' -import DrawerHeader from './DrawerHeader' -import Settings from './settings' -import useTimer from './use-timer' +import { useFocusEffect } from "@react-navigation/native"; +import React, { useCallback, useMemo, useState } from "react"; +import { Dimensions, NativeModules, View } from "react-native"; +import { Button, Text, useTheme } from "react-native-paper"; +import { ProgressCircle } from "react-native-svg-charts"; +import AppFab from "./AppFab"; +import { MARGIN, PADDING } from "./constants"; +import { settingsRepo } from "./db"; +import DrawerHeader from "./DrawerHeader"; +import Settings from "./settings"; +import useTimer from "./use-timer"; export interface TickEvent { - minutes: string - seconds: string + minutes: string; + seconds: string; } export default function TimerPage() { - const { minutes, seconds } = useTimer() - const [settings, setSettings] = useState() - const { colors } = useTheme() + const { minutes, seconds } = useTimer(); + const [settings, setSettings] = useState(); + const { colors } = useTheme(); useFocusEffect( useCallback(() => { - settingsRepo.findOne({ where: {} }).then(setSettings) - }, []), - ) + settingsRepo.findOne({ where: {} }).then(setSettings); + }, []) + ); const stop = () => { - NativeModules.AlarmModule.stop() - } + NativeModules.AlarmModule.stop(); + }; const add = async () => { - console.log(`${TimerPage.name}.add:`, settings) - NativeModules.AlarmModule.add() - } + console.log(`${TimerPage.name}.add:`, settings); + NativeModules.AlarmModule.add(); + }; const progress = useMemo(() => { - return (Number(minutes) * 60 + Number(seconds)) / 210 - }, [minutes, seconds]) + return (Number(minutes) * 60 + Number(seconds)) / 210; + }, [minutes, seconds]); const left = useMemo(() => { - return Dimensions.get('screen').width * 0.5 - 60 - }, []) + return Dimensions.get("screen").width * 0.5 - 60; + }, []); return ( <> - + - + {minutes}:{seconds} - - + - ) + ); } diff --git a/ViewGraph.tsx b/ViewGraph.tsx index fcdb82c8..fe07e0d4 100644 --- a/ViewGraph.tsx +++ b/ViewGraph.tsx @@ -1,73 +1,73 @@ -import { RouteProp, useRoute } from '@react-navigation/native' -import { format } from 'date-fns' -import { useEffect, useMemo, useState } from 'react' -import { View } from 'react-native' -import { FileSystem } from 'react-native-file-access' -import { IconButton, List } from 'react-native-paper' -import Share from 'react-native-share' -import { captureScreen } from 'react-native-view-shot' -import Chart from './Chart' -import { GraphsPageParams } from './GraphsPage' -import Select from './Select' -import StackHeader from './StackHeader' -import { PADDING } from './constants' -import { setRepo } from './db' -import GymSet from './gym-set' -import { Metrics } from './metrics' -import { Periods } from './periods' -import Volume from './volume' +import { RouteProp, useRoute } from "@react-navigation/native"; +import { format } from "date-fns"; +import { useEffect, useMemo, useState } from "react"; +import { View } from "react-native"; +import { FileSystem } from "react-native-file-access"; +import { IconButton, List } from "react-native-paper"; +import Share from "react-native-share"; +import { captureScreen } from "react-native-view-shot"; +import Chart from "./Chart"; +import { GraphsPageParams } from "./GraphsPage"; +import Select from "./Select"; +import StackHeader from "./StackHeader"; +import { PADDING } from "./constants"; +import { setRepo } from "./db"; +import GymSet from "./gym-set"; +import { Metrics } from "./metrics"; +import { Periods } from "./periods"; +import Volume from "./volume"; export default function ViewGraph() { - const { params } = useRoute>() - const [weights, setWeights] = useState() - const [volumes, setVolumes] = useState() - const [metric, setMetric] = useState(Metrics.Weight) - const [period, setPeriod] = useState(Periods.Monthly) + const { params } = useRoute>(); + const [weights, setWeights] = useState(); + const [volumes, setVolumes] = useState(); + const [metric, setMetric] = useState(Metrics.Weight); + const [period, setPeriod] = useState(Periods.Monthly); useEffect(() => { - let difference = '-7 days' - if (period === Periods.Monthly) difference = '-1 months' - else if (period === Periods.Yearly) difference = '-1 years' - let group = '%Y-%m-%d' - if (period === Periods.Yearly) group = '%Y-%m' + let difference = "-7 days"; + if (period === Periods.Monthly) difference = "-1 months"; + else if (period === Periods.Yearly) difference = "-1 years"; + let group = "%Y-%m-%d"; + if (period === Periods.Yearly) group = "%Y-%m"; const builder = setRepo .createQueryBuilder() - .select("STRFTIME('%Y-%m-%d', created)", 'created') - .addSelect('unit') - .where('name = :name', { name: params.best.name }) - .andWhere('NOT hidden') + .select("STRFTIME('%Y-%m-%d', created)", "created") + .addSelect("unit") + .where("name = :name", { name: params.best.name }) + .andWhere("NOT hidden") .andWhere("DATE(created) >= DATE('now', 'weekday 0', :difference)", { difference, }) - .groupBy('name') - .addGroupBy(`STRFTIME('${group}', created)`) + .groupBy("name") + .addGroupBy(`STRFTIME('${group}', created)`); switch (metric) { case Metrics.Weight: builder - .addSelect('ROUND(MAX(weight), 2)', 'weight') + .addSelect("ROUND(MAX(weight), 2)", "weight") .getRawMany() - .then(setWeights) - break + .then(setWeights); + break; case Metrics.Volume: builder - .addSelect('ROUND(SUM(weight * reps), 2)', 'value') + .addSelect("ROUND(SUM(weight * reps), 2)", "value") .getRawMany() - .then(setVolumes) - break + .then(setVolumes); + break; default: // Brzycki formula https://en.wikipedia.org/wiki/One-repetition_maximum#Brzycki builder .addSelect( - 'ROUND(MAX(weight / (1.0278 - 0.0278 * reps)), 2)', - 'weight', + "ROUND(MAX(weight / (1.0278 - 0.0278 * reps)), 2)", + "weight" ) .getRawMany() .then((newWeights) => { - console.log({ weights: newWeights }) - setWeights(newWeights) - }) + console.log({ weights: newWeights }); + setWeights(newWeights); + }); } - }, [params.best.name, metric, period]) + }, [params.best.name, metric, period]); const charts = useMemo(() => { if ( @@ -75,21 +75,23 @@ export default function ViewGraph() { (metric === Metrics.Weight && weights?.length === 0) || (metric === Metrics.OneRepMax && weights?.length === 0) ) { - return + return ; } if (metric === Metrics.Volume && volumes?.length && weights?.length) { return ( v.value)} yFormat={(value: number) => - `${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}${ - volumes[0].unit || 'kg' - }`} + `${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}${ + volumes[0].unit || "kg" + }` + } xData={weights} xFormat={(_value, index) => - format(new Date(weights[index].created), 'd/M')} + format(new Date(weights[index].created), "d/M") + } /> - ) + ); } return ( @@ -98,10 +100,11 @@ export default function ViewGraph() { yFormat={(value) => `${value}${weights?.[0].unit}`} xData={weights || []} xFormat={(_value, index) => - format(new Date(weights?.[index].created), 'd/M')} + format(new Date(weights?.[index].created), "d/M") + } /> - ) - }, [volumes, weights, metric]) + ); + }, [volumes, weights, metric]); return ( <> @@ -109,19 +112,20 @@ export default function ViewGraph() { captureScreen().then(async (uri) => { - const base64 = await FileSystem.readFile(uri, 'base64') - const url = `data:image/jpeg;base64,${base64}` + const base64 = await FileSystem.readFile(uri, "base64"); + const url = `data:image/jpeg;base64,${base64}`; Share.open({ - type: 'image/jpeg', + type: "image/jpeg", url, - }) - })} - icon='share' + }); + }) + } + icon="share" /> - ) + ); } diff --git a/WorkoutItem.tsx b/WorkoutItem.tsx index 30c6491d..891c2fc4 100644 --- a/WorkoutItem.tsx +++ b/WorkoutItem.tsx @@ -1,60 +1,57 @@ -import { NavigationProp, useNavigation } from '@react-navigation/native' -import { useCallback, useMemo, useState } from 'react' -import { GestureResponderEvent, Image } from 'react-native' -import { List, Menu, Text } from 'react-native-paper' -import ConfirmDialog from './ConfirmDialog' -import { setRepo } from './db' -import GymSet from './gym-set' -import { WorkoutsPageParams } from './WorkoutsPage' +import { NavigationProp, useNavigation } from "@react-navigation/native"; +import { useCallback, useMemo, useState } from "react"; +import { GestureResponderEvent, Image } from "react-native"; +import { List, Menu, Text } from "react-native-paper"; +import ConfirmDialog from "./ConfirmDialog"; +import { setRepo } from "./db"; +import GymSet from "./gym-set"; +import { WorkoutsPageParams } from "./WorkoutsPage"; export default function WorkoutItem({ item, onRemove, images, }: { - item: GymSet - onRemove: () => void - images: boolean + item: GymSet; + onRemove: () => void; + images: boolean; }) { - const [showMenu, setShowMenu] = useState(false) - const [anchor, setAnchor] = useState({ x: 0, y: 0 }) - const [showRemove, setShowRemove] = useState('') - const navigation = useNavigation>() + const [showMenu, setShowMenu] = useState(false); + const [anchor, setAnchor] = useState({ x: 0, y: 0 }); + const [showRemove, setShowRemove] = useState(""); + const navigation = useNavigation>(); const remove = useCallback(async () => { - await setRepo.delete({ name: item.name }) - setShowMenu(false) - onRemove() - }, [setShowMenu, onRemove, item.name]) + await setRepo.delete({ name: item.name }); + setShowMenu(false); + onRemove(); + }, [setShowMenu, onRemove, item.name]); const longPress = useCallback( (e: GestureResponderEvent) => { - setAnchor({ x: e.nativeEvent.pageX, y: e.nativeEvent.pageY }) - setShowMenu(true) + setAnchor({ x: e.nativeEvent.pageX, y: e.nativeEvent.pageY }); + setShowMenu(true); }, - [setShowMenu, setAnchor], - ) + [setShowMenu, setAnchor] + ); const description = useMemo(() => { - const seconds = item.seconds?.toString().padStart(2, '0') - return `${item.sets} x ${item.minutes || 0}:${seconds}` - }, [item]) + const seconds = item.seconds?.toString().padStart(2, "0"); + return `${item.sets} x ${item.minutes || 0}:${seconds}`; + }, [item]); const left = useCallback(() => { - if (!images || !item.image) return null + if (!images || !item.image) return null; return ( - - ) - }, [item.image, images]) + + ); + }, [item.image, images]); const right = useCallback(() => { return ( setShowMenu(false)} > { - setShowRemove(item.name) - setShowMenu(false) + setShowRemove(item.name); + setShowMenu(false); }} - title='Delete' + title="Delete" /> - ) - }, [anchor, showMenu, item.name]) + ); + }, [anchor, showMenu, item.name]); return ( <> navigation.navigate('EditWorkout', { value: item })} + onPress={() => navigation.navigate("EditWorkout", { value: item })} title={item.name} description={description} onLongPress={longPress} @@ -88,12 +85,12 @@ export default function WorkoutItem({ (show ? null : setShowRemove(''))} + setShow={(show) => (show ? null : setShowRemove(""))} onOk={remove} > This irreversibly deletes ALL sets related to this workout. Are you sure? - ) + ); } diff --git a/WorkoutList.tsx b/WorkoutList.tsx index 89b8f43b..30ec890a 100644 --- a/WorkoutList.tsx +++ b/WorkoutList.tsx @@ -2,50 +2,50 @@ import { NavigationProp, useFocusEffect, useNavigation, -} from '@react-navigation/native' -import { useCallback, useState } from 'react' -import { FlatList } from 'react-native' -import { List } from 'react-native-paper' -import { setRepo, settingsRepo } from './db' -import DrawerHeader from './DrawerHeader' -import GymSet from './gym-set' -import Page from './Page' -import SetList from './SetList' -import Settings from './settings' -import WorkoutItem from './WorkoutItem' -import { WorkoutsPageParams } from './WorkoutsPage' +} from "@react-navigation/native"; +import { useCallback, useState } from "react"; +import { FlatList } from "react-native"; +import { List } from "react-native-paper"; +import { setRepo, settingsRepo } from "./db"; +import DrawerHeader from "./DrawerHeader"; +import GymSet from "./gym-set"; +import Page from "./Page"; +import SetList from "./SetList"; +import Settings from "./settings"; +import WorkoutItem from "./WorkoutItem"; +import { WorkoutsPageParams } from "./WorkoutsPage"; -const limit = 15 +const limit = 15; export default function WorkoutList() { - const [workouts, setWorkouts] = useState() - const [offset, setOffset] = useState(0) - const [term, setTerm] = useState('') - const [end, setEnd] = useState(false) - const [settings, setSettings] = useState() - const navigation = useNavigation>() + const [workouts, setWorkouts] = useState(); + const [offset, setOffset] = useState(0); + const [term, setTerm] = useState(""); + const [end, setEnd] = useState(false); + const [settings, setSettings] = useState(); + const navigation = useNavigation>(); const refresh = useCallback(async (value: string) => { const newWorkouts = await setRepo .createQueryBuilder() .select() - .where('name LIKE :name', { name: `%${value.trim()}%` }) - .groupBy('name') - .orderBy('name') + .where("name LIKE :name", { name: `%${value.trim()}%` }) + .groupBy("name") + .orderBy("name") .limit(limit) - .getMany() - console.log(`${WorkoutList.name}`, { newWorkout: newWorkouts[0] }) - setWorkouts(newWorkouts) - setOffset(0) - setEnd(false) - }, []) + .getMany(); + console.log(`${WorkoutList.name}`, { newWorkout: newWorkouts[0] }); + setWorkouts(newWorkouts); + setOffset(0); + setEnd(false); + }, []); useFocusEffect( useCallback(() => { - refresh(term) - settingsRepo.findOne({ where: {} }).then(setSettings) - }, [refresh, term]), - ) + refresh(term); + settingsRepo.findOne({ where: {} }).then(setSettings); + }, [refresh, term]) + ); const renderItem = useCallback( ({ item }: { item: GymSet }) => ( @@ -56,69 +56,67 @@ export default function WorkoutList() { onRemove={() => refresh(term)} /> ), - [refresh, term, settings?.images], - ) + [refresh, term, settings?.images] + ); const next = useCallback(async () => { - if (end) return - const newOffset = offset + limit + if (end) return; + const newOffset = offset + limit; console.log(`${SetList.name}.next:`, { offset, limit, newOffset, term, - }) + }); const newWorkouts = await setRepo .createQueryBuilder() .select() - .where('name LIKE :name', { name: `%${term.trim()}%` }) - .groupBy('name') - .orderBy('name') + .where("name LIKE :name", { name: `%${term.trim()}%` }) + .groupBy("name") + .orderBy("name") .limit(limit) .offset(newOffset) - .getMany() - if (newWorkouts.length === 0) return setEnd(true) - if (!workouts) return - setWorkouts([...workouts, ...newWorkouts]) - if (newWorkouts.length < limit) return setEnd(true) - setOffset(newOffset) - }, [term, end, offset, workouts]) + .getMany(); + if (newWorkouts.length === 0) return setEnd(true); + if (!workouts) return; + setWorkouts([...workouts, ...newWorkouts]); + if (newWorkouts.length < limit) return setEnd(true); + setOffset(newOffset); + }, [term, end, offset, workouts]); const onAdd = useCallback(async () => { - navigation.navigate('EditWorkout', { + navigation.navigate("EditWorkout", { value: new GymSet(), - }) - }, [navigation]) + }); + }, [navigation]); const search = useCallback( (value: string) => { - setTerm(value) - refresh(value) + setTerm(value); + refresh(value); }, - [refresh], - ) + [refresh] + ); return ( <> - + - {workouts?.length === 0 - ? ( - - ) - : ( - w.name} - onEndReached={next} - /> - )} + {workouts?.length === 0 ? ( + + ) : ( + w.name} + onEndReached={next} + /> + )} - ) + ); } diff --git a/WorkoutsPage.tsx b/WorkoutsPage.tsx index 0ce31e9c..df4da550 100644 --- a/WorkoutsPage.tsx +++ b/WorkoutsPage.tsx @@ -1,24 +1,24 @@ -import { createStackNavigator } from '@react-navigation/stack' -import EditWorkout from './EditWorkout' -import GymSet from './gym-set' -import WorkoutList from './WorkoutList' +import { createStackNavigator } from "@react-navigation/stack"; +import EditWorkout from "./EditWorkout"; +import GymSet from "./gym-set"; +import WorkoutList from "./WorkoutList"; export type WorkoutsPageParams = { - WorkoutList: {} + WorkoutList: {}; EditWorkout: { - value: GymSet - } -} + value: GymSet; + }; +}; -const Stack = createStackNavigator() +const Stack = createStackNavigator(); export default function WorkoutsPage() { return ( - - + + - ) + ); } diff --git a/best.service.ts b/best.service.ts index 457a9d22..181ec0a0 100644 --- a/best.service.ts +++ b/best.service.ts @@ -1,15 +1,15 @@ -import { setRepo } from './db' -import GymSet from './gym-set' +import { setRepo } from "./db"; +import GymSet from "./gym-set"; export const getBestSet = async (name: string): Promise => { return setRepo .createQueryBuilder() .select() - .addSelect('MAX(weight)', 'weight') - .where('name = :name', { name }) - .groupBy('name') - .addGroupBy('reps') - .orderBy('weight', 'DESC') - .addOrderBy('reps', 'DESC') - .getOne() -} + .addSelect("MAX(weight)", "weight") + .where("name = :name", { name }) + .groupBy("name") + .addGroupBy("reps") + .orderBy("weight", "DESC") + .addOrderBy("reps", "DESC") + .getOne(); +}; diff --git a/colors.ts b/colors.ts index 24726fb4..2b3b9495 100644 --- a/colors.ts +++ b/colors.ts @@ -1,41 +1,41 @@ -import { DefaultTheme, MD3DarkTheme } from 'react-native-paper' +import { DefaultTheme, MD3DarkTheme } from "react-native-paper"; export const lightColors = [ - { hex: MD3DarkTheme.colors.primary, name: 'Purple' }, - { hex: '#B3E5FC', name: 'Blue' }, - { hex: '#FA8072', name: 'Salmon' }, - { hex: '#FFC0CB', name: 'Pink' }, - { hex: '#E9DCC9', name: 'Linen' }, -] + { hex: MD3DarkTheme.colors.primary, name: "Purple" }, + { hex: "#B3E5FC", name: "Blue" }, + { hex: "#FA8072", name: "Salmon" }, + { hex: "#FFC0CB", name: "Pink" }, + { hex: "#E9DCC9", name: "Linen" }, +]; export const darkColors = [ - { hex: DefaultTheme.colors.primary, name: 'Purple' }, - { hex: '#0051a9', name: 'Blue' }, - { hex: '#000000', name: 'Black' }, - { hex: '#863c3c', name: 'Red' }, - { hex: '#1c6000', name: 'Kermit' }, -] + { hex: DefaultTheme.colors.primary, name: "Purple" }, + { hex: "#0051a9", name: "Blue" }, + { hex: "#000000", name: "Black" }, + { hex: "#863c3c", name: "Red" }, + { hex: "#1c6000", name: "Kermit" }, +]; export const colorShade = (color: any, amount: number) => { - color = color.replace(/^#/, '') + color = color.replace(/^#/, ""); if (color.length === 3) { - color = color[0] + color[0] + color[1] + color[1] + color[2] + color[2] + color = color[0] + color[0] + color[1] + color[1] + color[2] + color[2]; } - let [r, g, b] = color.match(/.{2}/g) - ;[r, g, b] = [ + let [r, g, b] = color.match(/.{2}/g); + [r, g, b] = [ parseInt(r, 16) + amount, parseInt(g, 16) + amount, parseInt(b, 16) + amount, - ] + ]; - r = Math.max(Math.min(255, r), 0).toString(16) - g = Math.max(Math.min(255, g), 0).toString(16) - b = Math.max(Math.min(255, b), 0).toString(16) + r = Math.max(Math.min(255, r), 0).toString(16); + g = Math.max(Math.min(255, g), 0).toString(16); + b = Math.max(Math.min(255, b), 0).toString(16); - const rr = (r.length < 2 ? '0' : '') + r - const gg = (g.length < 2 ? '0' : '') + g - const bb = (b.length < 2 ? '0' : '') + b + const rr = (r.length < 2 ? "0" : "") + r; + const gg = (g.length < 2 ? "0" : "") + g; + const bb = (b.length < 2 ? "0" : "") + b; - return `#${rr}${gg}${bb}` -} + return `#${rr}${gg}${bb}`; +}; diff --git a/constants.ts b/constants.ts index 7471ca1d..283e378d 100644 --- a/constants.ts +++ b/constants.ts @@ -1,5 +1,5 @@ -export const MARGIN = 10 -export const PADDING = 10 -export const ITEM_PADDING = 8 -export const DARK_RIPPLE = '#444444' -export const LIGHT_RIPPLE = '#c2c2c2' +export const MARGIN = 10; +export const PADDING = 10; +export const ITEM_PADDING = 8; +export const DARK_RIPPLE = "#444444"; +export const LIGHT_RIPPLE = "#c2c2c2"; diff --git a/count-many.ts b/count-many.ts index cf823976..0fbcafd8 100644 --- a/count-many.ts +++ b/count-many.ts @@ -1,5 +1,5 @@ export default interface CountMany { - name: string - total: number - sets?: number + name: string; + total: number; + sets?: number; } diff --git a/data-source.ts b/data-source.ts index f17fdf8b..52a96892 100644 --- a/data-source.ts +++ b/data-source.ts @@ -1,40 +1,40 @@ -import { DataSource } from 'typeorm' -import GymSet from './gym-set' -import { Sets1667185586014 as sets1667185586014 } from './migrations/1667185586014-sets' -import { plans1667186124792 } from './migrations/1667186124792-plans' -import { settings1667186130041 } from './migrations/1667186130041-settings' -import { addSound1667186139844 } from './migrations/1667186139844-add-sound' -import { addHidden1667186159379 } from './migrations/1667186159379-add-hidden' -import { addNotify1667186166140 } from './migrations/1667186166140-add-notify' -import { addImage1667186171548 } from './migrations/1667186171548-add-image' -import { addImages1667186179488 } from './migrations/1667186179488-add-images' -import { insertSettings1667186203827 } from './migrations/1667186203827-insert-settings' -import { addSteps1667186211251 } from './migrations/1667186211251-add-steps' -import { addSets1667186250618 } from './migrations/1667186250618-add-sets' -import { addMinutes1667186255650 } from './migrations/1667186255650-add-minutes' -import { addSeconds1667186259174 } from './migrations/1667186259174-add-seconds' -import { addShowUnit1667186265588 } from './migrations/1667186265588-add-show-unit' -import { addColor1667186320954 } from './migrations/1667186320954-add-color' -import { addSteps1667186348425 } from './migrations/1667186348425-add-steps' -import { addDate1667186431804 } from './migrations/1667186431804-add-date' -import { addShowDate1667186435051 } from './migrations/1667186435051-add-show-date' -import { addTheme1667186439366 } from './migrations/1667186439366-add-theme' -import { addShowSets1667186443614 } from './migrations/1667186443614-add-show-sets' -import { addSetsCreated1667186451005 } from './migrations/1667186451005-add-sets-created' -import { addNoSound1667186456118 } from './migrations/1667186456118-add-no-sound' -import { dropMigrations1667190214743 } from './migrations/1667190214743-drop-migrations' -import { splitColor1669420187764 } from './migrations/1669420187764-split-color' -import { addBackup1678334268359 } from './migrations/1678334268359-add-backup' -import { Plan } from './plan' -import Settings from './settings' +import { DataSource } from "typeorm"; +import GymSet from "./gym-set"; +import { Sets1667185586014 as sets1667185586014 } from "./migrations/1667185586014-sets"; +import { plans1667186124792 } from "./migrations/1667186124792-plans"; +import { settings1667186130041 } from "./migrations/1667186130041-settings"; +import { addSound1667186139844 } from "./migrations/1667186139844-add-sound"; +import { addHidden1667186159379 } from "./migrations/1667186159379-add-hidden"; +import { addNotify1667186166140 } from "./migrations/1667186166140-add-notify"; +import { addImage1667186171548 } from "./migrations/1667186171548-add-image"; +import { addImages1667186179488 } from "./migrations/1667186179488-add-images"; +import { insertSettings1667186203827 } from "./migrations/1667186203827-insert-settings"; +import { addSteps1667186211251 } from "./migrations/1667186211251-add-steps"; +import { addSets1667186250618 } from "./migrations/1667186250618-add-sets"; +import { addMinutes1667186255650 } from "./migrations/1667186255650-add-minutes"; +import { addSeconds1667186259174 } from "./migrations/1667186259174-add-seconds"; +import { addShowUnit1667186265588 } from "./migrations/1667186265588-add-show-unit"; +import { addColor1667186320954 } from "./migrations/1667186320954-add-color"; +import { addSteps1667186348425 } from "./migrations/1667186348425-add-steps"; +import { addDate1667186431804 } from "./migrations/1667186431804-add-date"; +import { addShowDate1667186435051 } from "./migrations/1667186435051-add-show-date"; +import { addTheme1667186439366 } from "./migrations/1667186439366-add-theme"; +import { addShowSets1667186443614 } from "./migrations/1667186443614-add-show-sets"; +import { addSetsCreated1667186451005 } from "./migrations/1667186451005-add-sets-created"; +import { addNoSound1667186456118 } from "./migrations/1667186456118-add-no-sound"; +import { dropMigrations1667190214743 } from "./migrations/1667190214743-drop-migrations"; +import { splitColor1669420187764 } from "./migrations/1669420187764-split-color"; +import { addBackup1678334268359 } from "./migrations/1678334268359-add-backup"; +import { Plan } from "./plan"; +import Settings from "./settings"; export const AppDataSource = new DataSource({ - type: 'react-native', - database: 'massive.db', - location: 'default', + type: "react-native", + database: "massive.db", + location: "default", entities: [GymSet, Plan, Settings], migrationsRun: true, - migrationsTableName: 'typeorm_migrations', + migrationsTableName: "typeorm_migrations", migrations: [ sets1667185586014, plans1667186124792, @@ -62,4 +62,4 @@ export const AppDataSource = new DataSource({ splitColor1669420187764, addBackup1678334268359, ], -}) +}); diff --git a/db.ts b/db.ts index 75628baf..3b8dacda 100644 --- a/db.ts +++ b/db.ts @@ -1,15 +1,15 @@ -import { AppDataSource } from './data-source' -import GymSet from './gym-set' -import { Plan } from './plan' -import Settings from './settings' +import { AppDataSource } from "./data-source"; +import GymSet from "./gym-set"; +import { Plan } from "./plan"; +import Settings from "./settings"; -export const setRepo = AppDataSource.manager.getRepository(GymSet) -export const planRepo = AppDataSource.manager.getRepository(Plan) -export const settingsRepo = AppDataSource.manager.getRepository(Settings) +export const setRepo = AppDataSource.manager.getRepository(GymSet); +export const planRepo = AppDataSource.manager.getRepository(Plan); +export const settingsRepo = AppDataSource.manager.getRepository(Settings); export const getNow = async (): Promise => { const query = await AppDataSource.manager.query( - "SELECT STRFTIME('%Y-%m-%dT%H:%M:%S','now','localtime') AS now", - ) - return query[0].now -} + "SELECT STRFTIME('%Y-%m-%dT%H:%M:%S','now','localtime') AS now" + ); + return query[0].now; +}; diff --git a/drawer-param-list.ts b/drawer-param-list.ts index 4247f546..9b1b3d0f 100644 --- a/drawer-param-list.ts +++ b/drawer-param-list.ts @@ -1,8 +1,8 @@ export type DrawerParamList = { - Home: {} - Settings: {} - Graphs: {} - Plans: {} - Workouts: {} - Timer: {} -} + Home: {}; + Settings: {}; + Graphs: {}; + Plans: {}; + Workouts: {}; + Timer: {}; +}; diff --git a/gym-set.ts b/gym-set.ts index 4afb27b7..235c2fb1 100644 --- a/gym-set.ts +++ b/gym-set.ts @@ -1,53 +1,53 @@ -import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm' +import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; -@Entity('sets') +@Entity("sets") export default class GymSet { @PrimaryGeneratedColumn() - id?: number + id?: number; - @Column('text') - name: string + @Column("text") + name: string; - @Column('int') - reps: number + @Column("int") + reps: number; - @Column('int') - weight: number + @Column("int") + weight: number; - @Column('int') - sets = 3 + @Column("int") + sets = 3; - @Column('int') - minutes = 3 + @Column("int") + minutes = 3; - @Column('int') - seconds = 30 + @Column("int") + seconds = 30; - @Column('boolean') - hidden = false + @Column("boolean") + hidden = false; - @Column('text') - created: string + @Column("text") + created: string; - @Column('text') - unit: string + @Column("text") + unit: string; - @Column('text') - image: string + @Column("text") + image: string; - @Column('text') - steps?: string + @Column("text") + steps?: string; } export const defaultSet: GymSet = { - created: '', - name: '', - image: '', + created: "", + name: "", + image: "", hidden: false, minutes: 3, seconds: 30, reps: 0, sets: 0, - unit: 'kg', + unit: "kg", weight: 0, -} +}; diff --git a/home-page-params.ts b/home-page-params.ts index bd9b9a02..7d2fd626 100644 --- a/home-page-params.ts +++ b/home-page-params.ts @@ -1,11 +1,11 @@ -import GymSet from './gym-set' +import GymSet from "./gym-set"; export type HomePageParams = { - Sets: {} + Sets: {}; EditSet: { - set: GymSet - } + set: GymSet; + }; EditSets: { - ids: number[] - } -} + ids: number[]; + }; +}; diff --git a/input.ts b/input.ts index 16423e57..8a32a13e 100644 --- a/input.ts +++ b/input.ts @@ -1,9 +1,9 @@ -import { Item } from './Select' -import Settings from './settings' +import { Item } from "./Select"; +import Settings from "./settings"; export default interface Input { - name: string - key: keyof Settings - value?: T - items?: Item[] + name: string; + key: keyof Settings; + value?: T; + items?: Item[]; } diff --git a/jestSetup.ts b/jestSetup.ts index 5877a3a7..213adb39 100644 --- a/jestSetup.ts +++ b/jestSetup.ts @@ -1,21 +1,21 @@ -import { NativeModules } from 'react-native' -import 'react-native-gesture-handler/jestSetup' +import { NativeModules } from "react-native"; +import "react-native-gesture-handler/jestSetup"; NativeModules.RNViewShot = NativeModules.RNViewShot || { captureScreen: jest.fn(), -} +}; NativeModules.SettingsModule = NativeModules.SettingsModule || { ignoringBattery: jest.fn(), is24: jest.fn(() => Promise.resolve(true)), -} +}; -jest.mock('react-native-file-access', () => jest.fn()) -jest.mock('react-native-share', () => jest.fn()) -jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper') -jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter') +jest.mock("react-native-file-access", () => jest.fn()); +jest.mock("react-native-share", () => jest.fn()); +jest.mock("react-native/Libraries/Animated/NativeAnimatedHelper"); +jest.mock("react-native/Libraries/EventEmitter/NativeEventEmitter"); -jest.mock('react-native-reanimated', () => { - const Reanimated = require('react-native-reanimated/mock') - Reanimated.default.call = () => {} - return Reanimated -}) +jest.mock("react-native-reanimated", () => { + const Reanimated = require("react-native-reanimated/mock"); + Reanimated.default.call = () => {}; + return Reanimated; +}); diff --git a/metrics.ts b/metrics.ts index 81a9ed3d..75136d70 100644 --- a/metrics.ts +++ b/metrics.ts @@ -1,5 +1,5 @@ export enum Metrics { - Weight = 'Best weight', - Volume = 'Volume', - OneRepMax = 'One rep max', + Weight = "Best weight", + Volume = "Volume", + OneRepMax = "One rep max", } diff --git a/mock-providers.tsx b/mock-providers.tsx index d051ae80..2b434a4c 100644 --- a/mock-providers.tsx +++ b/mock-providers.tsx @@ -1,22 +1,22 @@ -import { NavigationContainer } from '@react-navigation/native' -import React from 'react' +import { NavigationContainer } from "@react-navigation/native"; +import React from "react"; import { DefaultTheme, MD3DarkTheme, Provider as PaperProvider, -} from 'react-native-paper' -import MaterialIcon from 'react-native-vector-icons/MaterialIcons' -import { ThemeContext } from './use-theme' +} from "react-native-paper"; +import MaterialIcon from "react-native-vector-icons/MaterialIcons"; +import { ThemeContext } from "./use-theme"; export const MockProviders = ({ children, }: { - children: JSX.Element | JSX.Element[] + children: JSX.Element | JSX.Element[]; }) => ( }}> {children} -) +); diff --git a/options.ts b/options.ts index 7589af6b..53e745ac 100644 --- a/options.ts +++ b/options.ts @@ -1,19 +1,19 @@ -import { darkColors, lightColors } from './colors' +import { darkColors, lightColors } from "./colors"; export const themeOptions = [ - { label: 'System', value: 'system' }, - { label: 'Dark', value: 'dark' }, - { label: 'Light', value: 'light' }, -] + { label: "System", value: "system" }, + { label: "Dark", value: "dark" }, + { label: "Light", value: "light" }, +]; export const lightOptions = lightColors.map((color) => ({ label: color.name, value: color.hex, color: color.hex, -})) +})); export const darkOptions = darkColors.map((color) => ({ label: color.name, value: color.hex, color: color.hex, -})) +})); diff --git a/periods.ts b/periods.ts index 6f87e33d..86d9d184 100644 --- a/periods.ts +++ b/periods.ts @@ -1,5 +1,5 @@ export enum Periods { - Weekly = 'This week', - Monthly = 'This month', - Yearly = 'This year', + Weekly = "This week", + Monthly = "This month", + Yearly = "This year", } diff --git a/plan-page-params.ts b/plan-page-params.ts index 9111298f..a1f55af2 100644 --- a/plan-page-params.ts +++ b/plan-page-params.ts @@ -1,16 +1,16 @@ -import GymSet from './gym-set' -import { Plan } from './plan' +import GymSet from "./gym-set"; +import { Plan } from "./plan"; export type PlanPageParams = { - PlanList: {} + PlanList: {}; EditPlan: { - plan: Plan - } + plan: Plan; + }; StartPlan: { - plan: Plan - first?: GymSet - } + plan: Plan; + first?: GymSet; + }; EditSet: { - set: GymSet - } -} + set: GymSet; + }; +}; diff --git a/plan.ts b/plan.ts index 936fc832..1b747b86 100644 --- a/plan.ts +++ b/plan.ts @@ -1,13 +1,13 @@ -import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm' +import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; -@Entity('plans') +@Entity("plans") export class Plan { @PrimaryGeneratedColumn() - id?: number + id?: number; - @Column('text') - days: string + @Column("text") + days: string; - @Column('text') - workouts: string + @Column("text") + workouts: string; } diff --git a/route.ts b/route.ts index 154fc409..8cf58d4c 100644 --- a/route.ts +++ b/route.ts @@ -1,7 +1,7 @@ -import { DrawerParamList } from './drawer-param-list' +import { DrawerParamList } from "./drawer-param-list"; export default interface Route { - name: keyof DrawerParamList - component: React.ComponentType - icon: string + name: keyof DrawerParamList; + component: React.ComponentType; + icon: string; } diff --git a/settings.ts b/settings.ts index 7a9376a1..af72f50c 100644 --- a/settings.ts +++ b/settings.ts @@ -1,49 +1,49 @@ -import { Column, Entity, PrimaryColumn } from 'typeorm' +import { Column, Entity, PrimaryColumn } from "typeorm"; @Entity() export default class Settings { - @PrimaryColumn('boolean') - alarm: boolean + @PrimaryColumn("boolean") + alarm: boolean; - @Column('boolean') - vibrate: boolean + @Column("boolean") + vibrate: boolean; - @Column('text') - sound: string + @Column("text") + sound: string; - @Column('boolean') - notify: boolean + @Column("boolean") + notify: boolean; - @Column('boolean') - images: boolean + @Column("boolean") + images: boolean; - @Column('boolean') - showUnit: boolean + @Column("boolean") + showUnit: boolean; - @Column('text') - lightColor?: string + @Column("text") + lightColor?: string; - @Column('text') - darkColor?: string + @Column("text") + darkColor?: string; - @Column('boolean') - steps: boolean + @Column("boolean") + steps: boolean; - @Column('text') - date: string + @Column("text") + date: string; - @Column('boolean') - showDate: boolean + @Column("boolean") + showDate: boolean; - @Column('text') - theme: string + @Column("text") + theme: string; - @Column('boolean') - showSets: boolean + @Column("boolean") + showSets: boolean; - @Column('boolean') - noSound: boolean + @Column("boolean") + noSound: boolean; - @Column('boolean') - backup: boolean + @Column("boolean") + backup: boolean; } diff --git a/time.ts b/time.ts index 0a6a15ad..6c529c9a 100644 --- a/time.ts +++ b/time.ts @@ -1,9 +1,9 @@ export const DAYS = [ - 'Sunday', - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday', -] + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", +]; diff --git a/toast.ts b/toast.ts index d426184b..64e97e96 100644 --- a/toast.ts +++ b/toast.ts @@ -1,7 +1,7 @@ -import { DeviceEventEmitter } from 'react-native' +import { DeviceEventEmitter } from "react-native"; -export const TOAST = 'toast' +export const TOAST = "toast"; export function toast(value: string) { - DeviceEventEmitter.emit(TOAST, { value }) + DeviceEventEmitter.emit(TOAST, { value }); } diff --git a/use-dark.ts b/use-dark.ts index a3e24a44..c5f6b450 100644 --- a/use-dark.ts +++ b/use-dark.ts @@ -1,11 +1,11 @@ -import { useColorScheme } from 'react-native' -import { useTheme } from './use-theme' +import { useColorScheme } from "react-native"; +import { useTheme } from "./use-theme"; export default function useDark() { - const dark = useColorScheme() === 'dark' - const { theme } = useTheme() + const dark = useColorScheme() === "dark"; + const { theme } = useTheme(); - if (theme === 'dark') return true - if (theme === 'light') return false - return dark + if (theme === "dark") return true; + if (theme === "light") return false; + return dark; } diff --git a/use-theme.ts b/use-theme.ts index 1996519d..448e9233 100644 --- a/use-theme.ts +++ b/use-theme.ts @@ -1,22 +1,22 @@ -import { createContext, useContext } from 'react' -import { MD3DarkTheme, MD3LightTheme } from 'react-native-paper' +import { createContext, useContext } from "react"; +import { MD3DarkTheme, MD3LightTheme } from "react-native-paper"; export const ThemeContext = createContext<{ - theme: string - lightColor: string - setTheme: (value: string) => void - setLightColor: (value: string) => void - darkColor: string - setDarkColor: (value: string) => void + theme: string; + lightColor: string; + setTheme: (value: string) => void; + setLightColor: (value: string) => void; + darkColor: string; + setDarkColor: (value: string) => void; }>({ - theme: 'system', + theme: "system", lightColor: MD3DarkTheme.colors.primary, setTheme: () => null, setLightColor: () => null, darkColor: MD3LightTheme.colors.primary, setDarkColor: () => null, -}) +}); export function useTheme() { - return useContext(ThemeContext) + return useContext(ThemeContext); } diff --git a/use-timer.ts b/use-timer.ts index 81fc8ca5..a133d5c3 100644 --- a/use-timer.ts +++ b/use-timer.ts @@ -1,25 +1,25 @@ -import { useFocusEffect } from '@react-navigation/native' -import { useCallback, useState } from 'react' -import { NativeEventEmitter } from 'react-native' -import { TickEvent } from './TimerPage' +import { useFocusEffect } from "@react-navigation/native"; +import { useCallback, useState } from "react"; +import { NativeEventEmitter } from "react-native"; +import { TickEvent } from "./TimerPage"; export default function useTimer() { - const [minutes, setMinutes] = useState('00') - const [seconds, setSeconds] = useState('00') + const [minutes, setMinutes] = useState("00"); + const [seconds, setSeconds] = useState("00"); useFocusEffect( useCallback(() => { - setMinutes('00') - setSeconds('00') - const emitter = new NativeEventEmitter() - const listener = emitter.addListener('tick', (event: TickEvent) => { - console.log(`${useTimer.name}.tick:`, { event }) - setMinutes(event.minutes) - setSeconds(event.seconds) - }) - return listener.remove - }, []), - ) + setMinutes("00"); + setSeconds("00"); + const emitter = new NativeEventEmitter(); + const listener = emitter.addListener("tick", (event: TickEvent) => { + console.log(`${useTimer.name}.tick:`, { event }); + setMinutes(event.minutes); + setSeconds(event.seconds); + }); + return listener.remove; + }, []) + ); - return { minutes, seconds } + return { minutes, seconds }; } diff --git a/volume.ts b/volume.ts index d019f363..786b73ec 100644 --- a/volume.ts +++ b/volume.ts @@ -1,6 +1,6 @@ export default interface Volume { - name: string - created: string - value: number - unit: string + name: string; + created: string; + value: number; + unit: string; } diff --git a/write.ts b/write.ts index 1b550f24..b8f92513 100644 --- a/write.ts +++ b/write.ts @@ -1,21 +1,21 @@ -import { PermissionsAndroid, Platform } from 'react-native' -import { Dirs, FileSystem } from 'react-native-file-access' -import { toast } from './toast' +import { PermissionsAndroid, Platform } from "react-native"; +import { Dirs, FileSystem } from "react-native-file-access"; +import { toast } from "./toast"; export const write = async (name: string, data: string) => { - const filePath = `${Dirs.DocumentDir}/${name}` + const filePath = `${Dirs.DocumentDir}/${name}`; const permission = async () => { - if (Platform.OS !== 'android') return true + if (Platform.OS !== "android") return true; const granted = await PermissionsAndroid.request( - PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, - ) - return granted === PermissionsAndroid.RESULTS.GRANTED + PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE + ); + return granted === PermissionsAndroid.RESULTS.GRANTED; + }; + const granted = await permission(); + if (!granted) return; + await FileSystem.writeFile(filePath, data); + if (Platform.OS === "android") { + await FileSystem.cpExternal(filePath, name, "downloads"); } - const granted = await permission() - if (!granted) return - await FileSystem.writeFile(filePath, data) - if (Platform.OS === 'android') { - await FileSystem.cpExternal(filePath, name, 'downloads') - } - toast(`Downloaded ${name}`) -} + toast(`Downloaded ${name}`); +};