Remove semicolons from line endings

typeorm
Brandon Presley 7 months ago
parent 1bc145f60c
commit bc7aca03e8

@ -4,4 +4,5 @@ module.exports = {
bracketSpacing: false,
singleQuote: true,
trailingComma: 'all',
}
semi: false,
};

@ -2,22 +2,22 @@ import {
DarkTheme as NavigationDarkTheme,
DefaultTheme as NavigationDefaultTheme,
NavigationContainer,
} from '@react-navigation/native';
import {useEffect, useMemo, useState} from 'react';
import {useColorScheme} from 'react-native';
} from '@react-navigation/native'
import {useEffect, useMemo, useState} from 'react'
import {useColorScheme} from 'react-native'
import {
DarkTheme as PaperDarkTheme,
DefaultTheme as PaperDefaultTheme,
Provider as PaperProvider,
} from 'react-native-paper';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import {Color} from './color';
import {lightColors} from './colors';
import {runMigrations, settingsRepo} from './db';
import MassiveSnack from './MassiveSnack';
import Routes from './Routes';
import Settings from './settings';
import {SettingsContext} from './use-settings';
} from 'react-native-paper'
import MaterialIcon from 'react-native-vector-icons/MaterialIcons'
import {Color} from './color'
import {lightColors} from './colors'
import {runMigrations, settingsRepo} from './db'
import MassiveSnack from './MassiveSnack'
import Routes from './Routes'
import Settings from './settings'
import {SettingsContext} from './use-settings'
export const CombinedDefaultTheme = {
...NavigationDefaultTheme,
@ -26,7 +26,7 @@ export const CombinedDefaultTheme = {
...NavigationDefaultTheme.colors,
...PaperDefaultTheme.colors,
},
};
}
export const CombinedDarkTheme = {
...NavigationDarkTheme,
@ -37,40 +37,40 @@ export const CombinedDarkTheme = {
primary: lightColors[0].hex,
background: '#0E0E0E',
},
};
}
const App = () => {
const isDark = useColorScheme() === 'dark';
const [settings, setSettings] = useState<Settings>();
const isDark = useColorScheme() === 'dark'
const [settings, setSettings] = useState<Settings>()
const [color, setColor] = useState(
isDark
? CombinedDarkTheme.colors.primary.toUpperCase()
: CombinedDefaultTheme.colors.primary.toUpperCase(),
);
)
useEffect(() => {
runMigrations().then(async () => {
const gotSettings = await settingsRepo.findOne({where: {}});
console.log(`${App.name}.runMigrations:`, {gotSettings});
setSettings(gotSettings);
if (gotSettings.color) setColor(gotSettings.color);
});
}, [setColor]);
const gotSettings = await settingsRepo.findOne({where: {}})
console.log(`${App.name}.runMigrations:`, {gotSettings})
setSettings(gotSettings)
if (gotSettings.color) setColor(gotSettings.color)
})
}, [setColor])
const theme = useMemo(() => {
const darkTheme = {
...CombinedDarkTheme,
colors: {...CombinedDarkTheme.colors, primary: color},
};
}
const lightTheme = {
...CombinedDefaultTheme,
colors: {...CombinedDefaultTheme.colors, primary: color},
};
let value = isDark ? darkTheme : lightTheme;
if (settings?.theme === 'dark') value = darkTheme;
else if (settings?.theme === 'light') value = lightTheme;
return value;
}, [color, isDark, settings]);
}
let value = isDark ? darkTheme : lightTheme
if (settings?.theme === 'dark') value = darkTheme
else if (settings?.theme === 'light') value = lightTheme
return value
}, [color, isDark, settings])
return (
<Color.Provider value={{color, setColor}}>
@ -88,7 +88,7 @@ const App = () => {
</NavigationContainer>
</PaperProvider>
</Color.Provider>
);
};
)
}
export default App;
export default App

@ -2,22 +2,22 @@ import {
NavigationProp,
useFocusEffect,
useNavigation,
} from '@react-navigation/native';
import {useCallback, useState} from 'react';
import {FlatList, Image} from 'react-native';
import {List} from 'react-native-paper';
import {BestPageParams} from './BestPage';
import {setRepo} from './db';
import DrawerHeader from './DrawerHeader';
import GymSet from './gym-set';
import Page from './Page';
import {useSettings} from './use-settings';
} from '@react-navigation/native'
import {useCallback, useState} from 'react'
import {FlatList, Image} from 'react-native'
import {List} from 'react-native-paper'
import {BestPageParams} from './BestPage'
import {setRepo} from './db'
import DrawerHeader from './DrawerHeader'
import GymSet from './gym-set'
import Page from './Page'
import {useSettings} from './use-settings'
export default function BestList() {
const [bests, setBests] = useState<GymSet[]>();
const [term, setTerm] = useState('');
const navigation = useNavigation<NavigationProp<BestPageParams>>();
const {settings} = useSettings();
const [bests, setBests] = useState<GymSet[]>()
const [term, setTerm] = useState('')
const navigation = useNavigation<NavigationProp<BestPageParams>>()
const {settings} = useSettings()
const refresh = useCallback(async (value: string) => {
const weights = await setRepo
@ -27,9 +27,9 @@ export default function BestList() {
.where('name LIKE :name', {name: `%${value}%`})
.andWhere('NOT hidden')
.groupBy('name')
.getMany();
console.log(`${BestList.name}.refresh:`, {length: weights.length});
let newBest: GymSet[] = [];
.getMany()
console.log(`${BestList.name}.refresh:`, {length: weights.length})
let newBest: GymSet[] = []
for (const set of weights) {
const reps = await setRepo
.createQueryBuilder()
@ -39,25 +39,25 @@ export default function BestList() {
.andWhere('weight = :weight', {weight: set.weight})
.andWhere('NOT hidden')
.groupBy('name')
.getMany();
newBest.push(...reps);
.getMany()
newBest.push(...reps)
}
setBests(newBest);
}, []);
setBests(newBest)
}, [])
useFocusEffect(
useCallback(() => {
refresh(term);
refresh(term)
}, [refresh, term]),
);
)
const search = useCallback(
(value: string) => {
setTerm(value);
refresh(value);
setTerm(value)
refresh(value)
},
[refresh],
);
)
const renderItem = ({item}: {item: GymSet}) => (
<List.Item
@ -72,7 +72,7 @@ export default function BestList() {
null
}
/>
);
)
return (
<>
@ -88,5 +88,5 @@ export default function BestList() {
)}
</Page>
</>
);
)
}

@ -1,15 +1,15 @@
import {createStackNavigator} from '@react-navigation/stack';
import BestList from './BestList';
import GymSet from './gym-set';
import ViewBest from './ViewBest';
import {createStackNavigator} from '@react-navigation/stack'
import BestList from './BestList'
import GymSet from './gym-set'
import ViewBest from './ViewBest'
const Stack = createStackNavigator<BestPageParams>();
const Stack = createStackNavigator<BestPageParams>()
export type BestPageParams = {
BestList: {};
BestList: {}
ViewBest: {
best: GymSet;
};
};
best: GymSet
}
}
export default function BestPage() {
return (
@ -18,5 +18,5 @@ export default function BestPage() {
<Stack.Screen name="BestList" component={BestList} />
<Stack.Screen name="ViewBest" component={ViewBest} />
</Stack.Navigator>
);
)
}

@ -1,11 +1,11 @@
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 {useColor} from './color';
import {MARGIN, PADDING} from './constants';
import GymSet from './gym-set';
import useDark from './use-dark';
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 {useColor} from './color'
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 {color} = useColor();
const dark = useDark();
const {color} = useColor()
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 (
<>
@ -60,5 +60,5 @@ export default function Chart({
</View>
</View>
</>
);
)
}

@ -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,
@ -7,11 +7,11 @@ export default function ConfirmDialog({
show,
setShow,
}: {
title: string;
children: JSX.Element | JSX.Element[] | string;
onOk: () => void;
show: boolean;
setShow: (show: boolean) => void;
title: string
children: JSX.Element | JSX.Element[] | string
onOk: () => void
show: boolean
setShow: (show: boolean) => void
}) {
return (
<Portal>
@ -26,5 +26,5 @@ export default function ConfirmDialog({
</Dialog.Actions>
</Dialog>
</Portal>
);
)
}

@ -1,13 +1,13 @@
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 DrawerMenu from './DrawerMenu';
import useDark from './use-dark';
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 DrawerMenu from './DrawerMenu'
import useDark from './use-dark'
export default function DrawerHeader({name}: {name: keyof DrawerParamList}) {
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
const dark = useDark();
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>()
const dark = useDark()
return (
<Appbar.Header>
@ -19,5 +19,5 @@ export default function DrawerHeader({name}: {name: keyof DrawerParamList}) {
<Appbar.Content title={name} />
<DrawerMenu name={name} />
</Appbar.Header>
);
)
}

@ -1,72 +1,71 @@
import {NavigationProp, useNavigation} from '@react-navigation/native';
import {useCallback, useState} from 'react';
import DocumentPicker from 'react-native-document-picker';
import {FileSystem} from 'react-native-file-access';
import {Divider, IconButton, Menu} from 'react-native-paper';
import ConfirmDialog from './ConfirmDialog';
import {AppDataSource} from './data-source';
import {planRepo} from './db';
import {DrawerParamList} from './drawer-param-list';
import GymSet from './gym-set';
import {useSnackbar} from './MassiveSnack';
import {Plan} from './plan';
import useDark from './use-dark';
import {write} from './write';
import {NavigationProp, useNavigation} from '@react-navigation/native'
import {useCallback, useState} from 'react'
import DocumentPicker from 'react-native-document-picker'
import {FileSystem} from 'react-native-file-access'
import {Divider, IconButton, Menu} from 'react-native-paper'
import ConfirmDialog from './ConfirmDialog'
import {AppDataSource} from './data-source'
import {planRepo} from './db'
import {DrawerParamList} from './drawer-param-list'
import GymSet from './gym-set'
import {useSnackbar} from './MassiveSnack'
import {Plan} from './plan'
import useDark from './use-dark'
import {write} from './write'
const setFields =
'id,name,reps,weight,created,unit,hidden,sets,minutes,seconds';
const planFields = 'id,days,workouts';
const setRepo = AppDataSource.manager.getRepository(GymSet);
const setFields = 'id,name,reps,weight,created,unit,hidden,sets,minutes,seconds'
const planFields = 'id,days,workouts'
const setRepo = AppDataSource.manager.getRepository(GymSet)
export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
const [showMenu, setShowMenu] = useState(false);
const [showRemove, setShowRemove] = useState(false);
const {toast} = useSnackbar();
const {reset} = useNavigation<NavigationProp<DrawerParamList>>();
const dark = useDark();
const [showMenu, setShowMenu] = useState(false)
const [showRemove, setShowRemove] = useState(false)
const {toast} = useSnackbar()
const {reset} = useNavigation<NavigationProp<DrawerParamList>>()
const dark = useDark()
const exportSets = useCallback(async () => {
const sets = await setRepo.find({});
const sets = await setRepo.find({})
const data = [setFields]
.concat(
sets.map(set =>
setFields
.split(',')
.map(fieldString => {
const field = fieldString as keyof GymSet;
if (field === 'unit') return set[field] || 'kg';
return set[field];
const field = fieldString as keyof GymSet
if (field === 'unit') return set[field] || 'kg'
return set[field]
})
.join(','),
),
)
.join('\n');
console.log(`${DrawerMenu.name}.exportSets`, {length: sets.length});
await write('sets.csv', data);
}, []);
.join('\n')
console.log(`${DrawerMenu.name}.exportSets`, {length: sets.length})
await write('sets.csv', data)
}, [])
const exportPlans = useCallback(async () => {
const plans = await planRepo.find({});
const plans = await planRepo.find({})
const data = [planFields]
.concat(plans.map(set => `"${set.id}","${set.days}","${set.workouts}"`))
.join('\n');
console.log(`${DrawerMenu.name}.exportPlans`, {length: plans.length});
await write('plans.csv', data);
}, []);
.join('\n')
console.log(`${DrawerMenu.name}.exportPlans`, {length: plans.length})
await write('plans.csv', data)
}, [])
const download = useCallback(async () => {
setShowMenu(false);
if (name === 'Home') exportSets();
else if (name === 'Plans') exportPlans();
}, [name, exportSets, exportPlans]);
setShowMenu(false)
if (name === 'Home') exportSets()
else if (name === 'Plans') exportPlans()
}, [name, exportSets, exportPlans])
const uploadSets = useCallback(async () => {
const result = await DocumentPicker.pickSingle();
const file = await FileSystem.readFile(result.uri);
console.log(`${DrawerMenu.name}.uploadSets:`, file.length);
const lines = file.split('\n');
console.log(lines[0]);
if (!setFields.includes(lines[0])) return toast('Invalid csv.', 3000);
const result = await DocumentPicker.pickSingle()
const file = await FileSystem.readFile(result.uri)
console.log(`${DrawerMenu.name}.uploadSets:`, file.length)
const lines = file.split('\n')
console.log(lines[0])
if (!setFields.includes(lines[0])) return toast('Invalid csv.', 3000)
const values = lines
.slice(1)
.filter(line => line)
@ -82,7 +81,7 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
sets,
minutes,
seconds,
] = line.split(',');
] = line.split(',')
const set: GymSet = {
name: setName,
reps: +reps,
@ -93,21 +92,21 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
sets: +sets,
minutes: +minutes,
seconds: +seconds,
};
return set;
});
console.log(`${DrawerMenu.name}.uploadSets:`, {values});
await setRepo.insert(values);
toast('Data imported.', 3000);
reset({index: 0, routes: [{name}]});
}, [reset, name, toast]);
}
return set
})
console.log(`${DrawerMenu.name}.uploadSets:`, {values})
await setRepo.insert(values)
toast('Data imported.', 3000)
reset({index: 0, routes: [{name}]})
}, [reset, name, toast])
const uploadPlans = useCallback(async () => {
const result = await DocumentPicker.pickSingle();
const file = await FileSystem.readFile(result.uri);
console.log(`${DrawerMenu.name}.uploadPlans:`, file.length);
const lines = file.split('\n');
if (lines[0] != planFields) return toast('Invalid csv.', 3000);
const result = await DocumentPicker.pickSingle()
const file = await FileSystem.readFile(result.uri)
console.log(`${DrawerMenu.name}.uploadPlans:`, file.length)
const lines = file.split('\n')
if (lines[0] != planFields) return toast('Invalid csv.', 3000)
const values = file
.split('\n')
.slice(1)
@ -115,32 +114,32 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
.map(set => {
const [, days, workouts] = set
.split('","')
.map(cell => cell.replace(/"/g, ''));
.map(cell => cell.replace(/"/g, ''))
const plan: Plan = {
days,
workouts,
};
return plan;
});
await planRepo.insert(values);
toast('Data imported.', 3000);
}, [toast]);
}
return plan
})
await planRepo.insert(values)
toast('Data imported.', 3000)
}, [toast])
const upload = useCallback(async () => {
setShowMenu(false);
if (name === 'Home') await uploadSets();
else if (name === 'Plans') await uploadPlans();
reset({index: 0, routes: [{name}]});
}, [name, uploadPlans, uploadSets, reset]);
setShowMenu(false)
if (name === 'Home') await uploadSets()
else if (name === 'Plans') await uploadPlans()
reset({index: 0, routes: [{name}]})
}, [name, uploadPlans, uploadSets, reset])
const remove = useCallback(async () => {
setShowMenu(false);
setShowRemove(false);
if (name === 'Home') await setRepo.delete({});
else if (name === 'Plans') await planRepo.delete({});
toast('All data has been deleted.', 4000);
reset({index: 0, routes: [{name}]});
}, [reset, name, toast]);
setShowMenu(false)
setShowRemove(false)
if (name === 'Home') await setRepo.delete({})
else if (name === 'Plans') await planRepo.delete({})
toast('All data has been deleted.', 4000)
reset({index: 0, routes: [{name}]})
}, [reset, name, toast])
if (name === 'Home' || name === 'Plans')
return (
@ -170,7 +169,7 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
This irreversibly deletes all data from the app. Are you sure?
</ConfirmDialog>
</Menu>
);
)
return null;
return null
}

@ -3,29 +3,29 @@ import {
RouteProp,
useNavigation,
useRoute,
} from '@react-navigation/native';
import {useCallback, useEffect, useState} from 'react';
import {ScrollView, StyleSheet, View} from 'react-native';
import {Button, Text} from 'react-native-paper';
import {MARGIN, PADDING} from './constants';
import {planRepo, setRepo} from './db';
import {DrawerParamList} from './drawer-param-list';
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, Text} from 'react-native-paper'
import {MARGIN, PADDING} from './constants'
import {planRepo, setRepo} from './db'
import {DrawerParamList} from './drawer-param-list'
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<RouteProp<PlanPageParams, 'EditPlan'>>();
const {plan} = params;
const {params} = useRoute<RouteProp<PlanPageParams, 'EditPlan'>>()
const {plan} = params
const [days, setDays] = useState<string[]>(
plan.days ? plan.days.split(',') : [],
);
)
const [workouts, setWorkouts] = useState<string[]>(
plan.workouts ? plan.workouts.split(',') : [],
);
const [names, setNames] = useState<string[]>([]);
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
)
const [names, setNames] = useState<string[]>([])
const navigation = useNavigation<NavigationProp<DrawerParamList>>()
useEffect(() => {
setRepo
@ -34,41 +34,41 @@ export default function EditPlan() {
.distinct(true)
.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});
navigation.goBack();
}, [days, workouts, plan, navigation]);
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})
navigation.goBack()
}, [days, workouts, plan, navigation])
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],
);
)
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],
);
)
return (
<>
@ -107,11 +107,11 @@ export default function EditPlan() {
disabled={workouts.length === 0 && days.length === 0}
mode="contained"
onPress={() => {
navigation.goBack();
navigation.goBack()
navigation.navigate('Workouts', {
screen: 'EditWorkout',
params: {value: {name: ''}},
});
})
}}>
Add workout
</Button>
@ -127,7 +127,7 @@ export default function EditPlan() {
)}
</View>
</>
);
)
}
const styles = StyleSheet.create({
@ -135,4 +135,4 @@ const styles = StyleSheet.create({
fontSize: 20,
marginBottom: MARGIN,
},
});
})

@ -1,64 +1,64 @@
import {RouteProp, useNavigation, useRoute} from '@react-navigation/native';
import {useCallback} from 'react';
import {NativeModules, View} from 'react-native';
import {PADDING} from './constants';
import {getNow, setRepo} from './db';
import GymSet from './gym-set';
import {HomePageParams} from './home-page-params';
import {useSnackbar} from './MassiveSnack';
import SetForm from './SetForm';
import StackHeader from './StackHeader';
import {useSettings} from './use-settings';
import {RouteProp, useNavigation, useRoute} from '@react-navigation/native'
import {useCallback} from 'react'
import {NativeModules, View} from 'react-native'
import {PADDING} from './constants'
import {getNow, setRepo} from './db'
import GymSet from './gym-set'
import {HomePageParams} from './home-page-params'
import {useSnackbar} from './MassiveSnack'
import SetForm from './SetForm'
import StackHeader from './StackHeader'
import {useSettings} from './use-settings'
export default function EditSet() {
const {params} = useRoute<RouteProp<HomePageParams, 'EditSet'>>();
const {set} = params;
const navigation = useNavigation();
const {toast} = useSnackbar();
const {settings} = useSettings();
const {params} = useRoute<RouteProp<HomePageParams, 'EditSet'>>()
const {set} = params
const navigation = useNavigation()
const {toast} = useSnackbar()
const {settings} = useSettings()
const startTimer = useCallback(
async (name: string) => {
if (!settings.alarm) return;
const {minutes, seconds} = await setRepo.findOne({where: {name}});
const milliseconds = (minutes ?? 3) * 60 * 1000 + (seconds ?? 0) * 1000;
if (!settings.alarm) return
const {minutes, seconds} = await setRepo.findOne({where: {name}})
const milliseconds = (minutes ?? 3) * 60 * 1000 + (seconds ?? 0) * 1000
NativeModules.AlarmModule.timer(
milliseconds,
!!settings.vibrate,
settings.sound,
!!settings.noSound,
);
)
},
[settings],
);
)
const add = useCallback(
async (value: GymSet) => {
startTimer(value.name);
const [{now}] = await getNow();
value.created = now;
value.hidden = false;
console.log(`${EditSet.name}.add`, {set: value});
const result = await setRepo.save(value);
console.log({result});
if (!settings.notify) return;
startTimer(value.name)
const [{now}] = await getNow()
value.created = now
value.hidden = false
console.log(`${EditSet.name}.add`, {set: value})
const result = await setRepo.save(value)
console.log({result})
if (!settings.notify) return
if (
value.weight > set.weight ||
(value.reps > set.reps && value.weight === set.weight)
)
toast("Great work King! That's a new record.", 3000);
toast("Great work King! That's a new record.", 3000)
},
[startTimer, set, toast, settings],
);
)
const save = useCallback(
async (value: GymSet) => {
if (typeof set.id === 'number') await setRepo.save(value);
else await add(value);
navigation.goBack();
if (typeof set.id === 'number') await setRepo.save(value)
else await add(value)
navigation.goBack()
},
[add, set.id, navigation],
);
)
return (
<>
@ -67,5 +67,5 @@ export default function EditSet() {
<SetForm save={save} set={set} />
</View>
</>
);
)
}

@ -1,39 +1,39 @@
import {RouteProp, 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 {Like} from 'typeorm';
import ConfirmDialog from './ConfirmDialog';
import {MARGIN, PADDING} from './constants';
import {getNow, planRepo, setRepo} from './db';
import MassiveInput from './MassiveInput';
import {useSnackbar} from './MassiveSnack';
import StackHeader from './StackHeader';
import {useSettings} from './use-settings';
import {WorkoutsPageParams} from './WorkoutsPage';
import {RouteProp, 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 {Like} from 'typeorm'
import ConfirmDialog from './ConfirmDialog'
import {MARGIN, PADDING} from './constants'
import {getNow, planRepo, setRepo} from './db'
import MassiveInput from './MassiveInput'
import {useSnackbar} from './MassiveSnack'
import StackHeader from './StackHeader'
import {useSettings} from './use-settings'
import {WorkoutsPageParams} from './WorkoutsPage'
export default function EditWorkout() {
const {params} = useRoute<RouteProp<WorkoutsPageParams, 'EditWorkout'>>();
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<RouteProp<WorkoutsPageParams, 'EditWorkout'>>()
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',
);
)
const [seconds, setSeconds] = useState(
params.value.seconds?.toString() ?? '30',
);
const [sets, setSets] = useState(params.value.sets?.toString() ?? '3');
const {toast} = useSnackbar();
const navigation = useNavigation();
const setsRef = useRef<TextInput>(null);
const stepsRef = useRef<TextInput>(null);
const minutesRef = useRef<TextInput>(null);
const secondsRef = useRef<TextInput>(null);
const {settings} = useSettings();
)
const [sets, setSets] = useState(params.value.sets?.toString() ?? '3')
const {toast} = useSnackbar()
const navigation = useNavigation()
const setsRef = useRef<TextInput>(null)
const stepsRef = useRef<TextInput>(null)
const minutesRef = useRef<TextInput>(null)
const secondsRef = useRef<TextInput>(null)
const {settings} = useSettings()
const update = async () => {
await setRepo.update(
@ -46,18 +46,18 @@ export default function EditWorkout() {
steps,
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();
};
)
navigation.goBack()
}
const add = async () => {
const [{now}] = await getNow();
const [{now}] = await getNow()
await setRepo.save({
name,
reps: 0,
@ -69,45 +69,45 @@ 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: 'image/*',
copyTo: 'documentDirectory',
});
if (fileCopyUri) setUri(fileCopyUri);
}, []);
})
if (fileCopyUri) setUri(fileCopyUri)
}, [])
const handleRemove = useCallback(async () => {
setUri('');
setRemoveImage(true);
setShowRemove(false);
}, []);
setUri('')
setRemoveImage(true)
setShowRemove(false)
}, [])
const handleName = (value: string) => {
setName(value.replace(/,|'/g, ''));
setName(value.replace(/,|'/g, ''))
if (value.match(/,|'/))
toast('Commas and single quotes would break CSV exports', 6000);
};
toast('Commas and single quotes would break CSV exports', 6000)
}
const handleSteps = (value: string) => {
setSteps(value.replace(/,|'/g, ''));
setSteps(value.replace(/,|'/g, ''))
if (value.match(/,|'/))
toast('Commas and single quotes would break CSV exports', 6000);
};
toast('Commas and single quotes would break CSV exports', 6000)
}
const submitName = () => {
if (settings.steps) stepsRef.current?.focus();
else setsRef.current?.focus();
};
if (settings.steps) stepsRef.current?.focus()
else setsRef.current?.focus()
}
return (
<>
@ -191,5 +191,5 @@ export default function EditWorkout() {
</ConfirmDialog>
</View>
</>
);
)
}

@ -1,9 +1,9 @@
import {createStackNavigator} from '@react-navigation/stack';
import EditSet from './EditSet';
import {HomePageParams} from './home-page-params';
import SetList from './SetList';
import {createStackNavigator} from '@react-navigation/stack'
import EditSet from './EditSet'
import {HomePageParams} from './home-page-params'
import SetList from './SetList'
const Stack = createStackNavigator<HomePageParams>();
const Stack = createStackNavigator<HomePageParams>()
export default function HomePage() {
return (
@ -12,5 +12,5 @@ export default function HomePage() {
<Stack.Screen name="Sets" component={SetList} />
<Stack.Screen name="EditSet" component={EditSet} />
</Stack.Navigator>
);
)
}

@ -1,13 +1,13 @@
import {ComponentProps} from 'react';
import {FAB} from 'react-native-paper';
import {useColor} from './color';
import {lightColors} from './colors';
import {ComponentProps} from 'react'
import {FAB} from 'react-native-paper'
import {useColor} from './color'
import {lightColors} from './colors'
export default function MassiveFab(props: Partial<ComponentProps<typeof FAB>>) {
const {color} = useColor();
const {color} = useColor()
const fabColor = lightColors.map(lightColor => lightColor.hex).includes(color)
? 'black'
: undefined;
: undefined
return (
<FAB
@ -21,5 +21,5 @@ export default function MassiveFab(props: Partial<ComponentProps<typeof FAB>>) {
}}
{...props}
/>
);
)
}

@ -1,15 +1,15 @@
import {ComponentProps, Ref} from 'react';
import {TextInput} from 'react-native-paper';
import {CombinedDefaultTheme} from './App';
import {MARGIN} from './constants';
import useDark from './use-dark';
import {ComponentProps, Ref} from 'react'
import {TextInput} from 'react-native-paper'
import {CombinedDefaultTheme} from './App'
import {MARGIN} from './constants'
import useDark from './use-dark'
export default function MassiveInput(
props: Partial<ComponentProps<typeof TextInput>> & {
innerRef?: Ref<any>;
innerRef?: Ref<any>
},
) {
const dark = useDark();
const dark = useDark()
return (
<TextInput
@ -21,5 +21,5 @@ export default function MassiveInput(
blurOnSubmit={false}
{...props}
/>
);
)
}

@ -1,31 +1,31 @@
import {createContext, useContext, useState} from 'react';
import {Snackbar} from 'react-native-paper';
import {CombinedDarkTheme, CombinedDefaultTheme} from './App';
import useDark from './use-dark';
import {createContext, useContext, useState} from 'react'
import {Snackbar} from 'react-native-paper'
import {CombinedDarkTheme, CombinedDefaultTheme} from './App'
import useDark from './use-dark'
export const SnackbarContext = createContext<{
toast: (value: string, timeout: number) => void;
}>({toast: () => null});
toast: (value: string, timeout: number) => void
}>({toast: () => null})
export const useSnackbar = () => {
return useContext(SnackbarContext);
};
return useContext(SnackbarContext)
}
export default function MassiveSnack({
children,
}: {
children?: JSX.Element[] | JSX.Element;
children?: JSX.Element[] | JSX.Element
}) {
const [snackbar, setSnackbar] = useState('');
const [timeoutId, setTimeoutId] = useState(0);
const dark = useDark();
const [snackbar, setSnackbar] = useState('')
const [timeoutId, setTimeoutId] = useState(0)
const dark = useDark()
const toast = (value: string, timeout: number) => {
setSnackbar(value);
clearTimeout(timeoutId);
const id = setTimeout(() => setSnackbar(''), timeout);
setTimeoutId(id);
};
setSnackbar(value)
clearTimeout(timeoutId)
const id = setTimeout(() => setSnackbar(''), timeout)
setTimeoutId(id)
}
return (
<>
@ -45,5 +45,5 @@ export default function MassiveSnack({
{snackbar}
</Snackbar>
</>
);
)
}

@ -1,7 +1,7 @@
import {StyleSheet, View} from 'react-native';
import {Searchbar} from 'react-native-paper';
import {PADDING} from './constants';
import MassiveFab from './MassiveFab';
import {StyleSheet, View} from 'react-native'
import {Searchbar} from 'react-native-paper'
import {PADDING} from './constants'
import MassiveFab from './MassiveFab'
export default function Page({
onAdd,
@ -9,10 +9,10 @@ export default function Page({
term,
search,
}: {
children: JSX.Element | JSX.Element[];
onAdd?: () => void;
term: string;
search: (value: string) => void;
children: JSX.Element | JSX.Element[]
onAdd?: () => void
term: string
search: (value: string) => void
}) {
return (
<View style={styles.container}>
@ -26,7 +26,7 @@ export default function Page({
{children}
{onAdd && <MassiveFab onPress={onAdd} />}
</View>
);
)
}
const styles = StyleSheet.create({
@ -34,4 +34,4 @@ const styles = StyleSheet.create({
flexGrow: 1,
padding: PADDING,
},
});
})

@ -2,60 +2,60 @@ import {
NavigationProp,
useFocusEffect,
useNavigation,
} from '@react-navigation/native';
import {useCallback, useMemo, useState} from 'react';
import {GestureResponderEvent, Text} from 'react-native';
import {Divider, List, Menu} from 'react-native-paper';
import {getBestSet} from './best.service';
import {planRepo} from './db';
import {Plan} from './plan';
import {PlanPageParams} from './plan-page-params';
import {DAYS} from './time';
} from '@react-navigation/native'
import {useCallback, useMemo, useState} from 'react'
import {GestureResponderEvent, Text} from 'react-native'
import {Divider, List, Menu} from 'react-native-paper'
import {getBestSet} from './best.service'
import {planRepo} from './db'
import {Plan} from './plan'
import {PlanPageParams} from './plan-page-params'
import {DAYS} from './time'
export default function PlanItem({
item,
onRemove,
}: {
item: Plan;
onRemove: () => void;
item: Plan
onRemove: () => void
}) {
const [show, setShow] = useState(false);
const [anchor, setAnchor] = useState({x: 0, y: 0});
const [today, setToday] = useState<string>();
const days = useMemo(() => item.days.split(','), [item.days]);
const navigation = useNavigation<NavigationProp<PlanPageParams>>();
const [show, setShow] = useState(false)
const [anchor, setAnchor] = useState({x: 0, y: 0})
const [today, setToday] = useState<string>()
const days = useMemo(() => item.days.split(','), [item.days])
const navigation = useNavigation<NavigationProp<PlanPageParams>>()
useFocusEffect(
useCallback(() => {
const newToday = DAYS[new Date().getDay()];
setToday(newToday);
const newToday = DAYS[new Date().getDay()]
setToday(newToday)
}, []),
);
)
const remove = useCallback(async () => {
if (typeof item.id === 'number') await planRepo.delete(item.id);
setShow(false);
onRemove();
}, [setShow, item.id, onRemove]);
if (typeof item.id === 'number') await planRepo.delete(item.id)
setShow(false)
onRemove()
}, [setShow, item.id, onRemove])
const start = useCallback(async () => {
console.log(`${PlanItem.name}.start:`, {item});
setShow(false);
navigation.navigate('StartPlan', {plan: item});
}, [item, navigation]);
console.log(`${PlanItem.name}.start:`, {item})
setShow(false)
navigation.navigate('StartPlan', {plan: item})
}, [item, navigation])
const longPress = useCallback(
(e: GestureResponderEvent) => {
setAnchor({x: e.nativeEvent.pageX, y: e.nativeEvent.pageY});
setShow(true);
setAnchor({x: e.nativeEvent.pageX, y: e.nativeEvent.pageY})
setShow(true)
},
[setAnchor, setShow],
);
)
const edit = useCallback(() => {
setShow(false);
navigation.navigate('EditPlan', {plan: item});
}, [navigation, item]);
setShow(false)
navigation.navigate('EditPlan', {plan: item})
}, [navigation, item])
const title = useMemo(
() =>
@ -72,12 +72,12 @@ export default function PlanItem({
</Text>
)),
[days, today],
);
)
const description = useMemo(
() => item.workouts.replace(/,/g, ', '),
[item.workouts],
);
)
return (
<>
@ -95,5 +95,5 @@ export default function PlanItem({
)}
/>
</>
);
)
}

@ -2,54 +2,54 @@ 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 Page from './Page';