Remove csv import/export

This is replaced with the backup/restore feature in Settings page.

- Not sure anybody is using this besides me for testing purposes
- Backing up the entire SQLite database is faster than CSV conversion
- This prevents missing data and will work nicely with future plan
  changes

Closes #128
This commit is contained in:
Brandon Presley 2022-12-08 14:50:10 +13:00
parent 0b2d4d52e1
commit 533b21a907
4 changed files with 7 additions and 158 deletions

View File

@ -1,21 +1,11 @@
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 {IconButton, Menu} from 'react-native-paper'
import ConfirmDialog from './ConfirmDialog'
import {AppDataSource} from './data-source'
import {planRepo} from './db'
import {planRepo, setRepo} from './db'
import {DrawerParamList} from './drawer-param-list'
import GymSet from './gym-set'
import {Plan} from './plan'
import {toast} from './toast'
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)
export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
const [showMenu, setShowMenu] = useState(false)
@ -23,113 +13,6 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
const {reset} = useNavigation<NavigationProp<DrawerParamList>>()
const dark = useDark()
const exportSets = useCallback(async () => {
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]
})
.join(','),
),
)
.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 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)
}, [])
const download = useCallback(async () => {
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')
if (!setFields.includes(lines[0])) return toast('Invalid csv.')
const values = lines
.slice(1)
.filter(line => line)
.map(line => {
let [
,
setName,
reps,
weight,
created,
unit,
hidden,
sets,
minutes,
seconds,
] = line.split(',')
const set: GymSet = {
name: setName,
reps: +reps,
weight: +weight,
created,
unit: unit ?? 'kg',
hidden: !!Number(hidden),
sets: +sets,
minutes: +minutes,
seconds: +seconds,
image: '',
}
return set
})
await setRepo.insert(values)
toast('Data imported.')
reset({index: 0, routes: [{name}]})
}, [reset, name])
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.')
const values = file
.split('\n')
.slice(1)
.filter(line => line)
.map(set => {
const [, days, workouts] = set
.split('","')
.map(cell => cell.replace(/"/g, ''))
const plan: Plan = {
days,
workouts,
}
return plan
})
await planRepo.insert(values)
toast('Data imported.')
}, [])
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])
const remove = useCallback(async () => {
setShowMenu(false)
setShowRemove(false)
@ -151,9 +34,6 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
icon="more-vert"
/>
}>
<Menu.Item icon="arrow-downward" onPress={download} title="Download" />
<Menu.Item icon="arrow-upward" onPress={upload} title="Upload" />
<Divider />
<Menu.Item
icon="delete"
onPress={() => setShowRemove(true)}

View File

@ -99,18 +99,6 @@ export default function EditSet() {
navigation.goBack()
}
const handleName = useCallback((value: string) => {
setName(value.replace(/,|'/g, ''))
if (value.match(/,|'/))
toast('Commas and single quotes would break CSV exports')
}, [])
const handleUnit = useCallback((value: string) => {
setUnit(value.replace(/,|'/g, ''))
if (value.match(/,|'/))
toast('Commas and single quotes would break CSV exports')
}, [])
const changeImage = useCallback(async () => {
const {fileCopyUri} = await DocumentPicker.pickSingle({
type: DocumentPicker.types.images,
@ -133,7 +121,7 @@ export default function EditSet() {
<MassiveInput
label="Name"
value={name}
onChangeText={handleName}
onChangeText={setName}
autoCorrect={false}
autoFocus={!name}
onSubmitEditing={() => repsRef.current?.focus()}
@ -165,7 +153,7 @@ export default function EditSet() {
autoCapitalize="none"
label="Unit"
value={unit}
onChangeText={handleUnit}
onChangeText={setUnit}
innerRef={unitRef}
/>
)}

View File

@ -15,7 +15,6 @@ import {defaultSet} from './gym-set'
import MassiveInput from './MassiveInput'
import Settings from './settings'
import StackHeader from './StackHeader'
import {toast} from './toast'
import {WorkoutsPageParams} from './WorkoutsPage'
export default function EditWorkout() {
@ -101,18 +100,6 @@ export default function EditWorkout() {
setShowRemove(false)
}, [])
const handleName = (value: string) => {
setName(value.replace(/,|'/g, ''))
if (value.match(/,|'/))
toast('Commas and single quotes would break CSV exports')
}
const handleSteps = (value: string) => {
setSteps(value.replace(/,|'/g, ''))
if (value.match(/,|'/))
toast('Commas and single quotes would break CSV exports')
}
const submitName = () => {
if (settings.steps) stepsRef.current?.focus()
else setsRef.current?.focus()
@ -127,7 +114,7 @@ export default function EditWorkout() {
autoFocus
label="Name"
value={name}
onChangeText={handleName}
onChangeText={setName}
onSubmitEditing={submitName}
/>
{settings?.steps && (
@ -135,7 +122,7 @@ export default function EditWorkout() {
innerRef={stepsRef}
selectTextOnFocus={false}
value={steps}
onChangeText={handleSteps}
onChangeText={setSteps}
label="Steps"
multiline
onSubmitEditing={() => setsRef.current?.focus()}

View File

@ -111,12 +111,6 @@ export default function StartPlan() {
NativeModules.AlarmModule.timer(...args)
}
const handleUnit = useCallback((value: string) => {
setUnit(value.replace(/,|'/g, ''))
if (value.match(/,|'/))
toast('Commas and single quotes would break CSV exports')
}, [])
return (
<>
<StackHeader title={params.plan.days.replace(/,/g, ', ')} />
@ -146,7 +140,7 @@ export default function StartPlan() {
autoCapitalize="none"
label="Unit"
value={unit}
onChangeText={handleUnit}
onChangeText={setUnit}
innerRef={unitRef}
/>
)}