diff --git a/ConfirmDialog.tsx b/ConfirmDialog.tsx
index 7b68b97f..f1d97815 100644
--- a/ConfirmDialog.tsx
+++ b/ConfirmDialog.tsx
@@ -6,13 +6,20 @@ export default function ConfirmDialog({
onOk,
show,
setShow,
+ onCancel,
}: {
title: string
children: JSX.Element | JSX.Element[] | string
onOk: () => void
show: boolean
setShow: (show: boolean) => void
+ onCancel?: () => void
}) {
+ const cancel = () => {
+ setShow(false)
+ onCancel && onCancel()
+ }
+
return (
diff --git a/DrawerHeader.tsx b/DrawerHeader.tsx
index 3f41d3af..238e671b 100644
--- a/DrawerHeader.tsx
+++ b/DrawerHeader.tsx
@@ -5,7 +5,13 @@ import {DrawerParamList} from './drawer-param-list'
import DrawerMenu from './DrawerMenu'
import useDark from './use-dark'
-export default function DrawerHeader({name}: {name: keyof DrawerParamList}) {
+export default function DrawerHeader({
+ name,
+ ids,
+}: {
+ name: keyof DrawerParamList
+ ids: number[]
+}) {
const navigation = useNavigation>()
const dark = useDark()
@@ -17,7 +23,7 @@ export default function DrawerHeader({name}: {name: keyof DrawerParamList}) {
onPress={navigation.openDrawer}
/>
-
+
)
}
diff --git a/DrawerMenu.tsx b/DrawerMenu.tsx
index 8a11afb5..82039001 100644
--- a/DrawerMenu.tsx
+++ b/DrawerMenu.tsx
@@ -4,23 +4,34 @@ import {IconButton, Menu} from 'react-native-paper'
import ConfirmDialog from './ConfirmDialog'
import {planRepo, setRepo} from './db'
import {DrawerParamList} from './drawer-param-list'
-import {toast} from './toast'
+import {HomePageParams} from './home-page-params'
import useDark from './use-dark'
-export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
+export default function DrawerMenu({
+ name,
+ ids,
+}: {
+ name: keyof DrawerParamList
+ ids: number[]
+}) {
const [showMenu, setShowMenu] = useState(false)
const [showRemove, setShowRemove] = useState(false)
const {reset} = useNavigation>()
+ const {navigate} = useNavigation>()
const dark = useDark()
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.')
+ if (name === 'Home') await setRepo.delete(ids.length > 0 ? ids : {})
+ else if (name === 'Plans') await planRepo.delete(ids.length > 0 ? ids : {})
reset({index: 0, routes: [{name}]})
- }, [reset, name])
+ }, [reset, name, ids])
+
+ const edit = useCallback(() => {
+ navigate('EditSets', {ids})
+ setShowMenu(false)
+ }, [ids, navigate])
if (name === 'Home' || name === 'Plans')
return (
@@ -39,12 +50,22 @@ export default function DrawerMenu({name}: {name: keyof DrawerParamList}) {
onPress={() => setShowRemove(true)}
title="Delete"
/>
+
+ {ids.length > 0 && name === 'Home' && (
+
+ )}
+
- This irreversibly deletes all data from the app. Are you sure?
+ onOk={remove}
+ onCancel={() => setShowMenu(false)}>
+ {ids.length === 0 ? (
+ <>This irreversibly deletes all data from the app. Are you sure?>
+ ) : (
+ <>This will delete {ids.length} records. Are you sure?>
+ )}
)
diff --git a/EditSets.tsx b/EditSets.tsx
new file mode 100644
index 00000000..8e14db52
--- /dev/null
+++ b/EditSets.tsx
@@ -0,0 +1,151 @@
+import {
+ RouteProp,
+ useFocusEffect,
+ useNavigation,
+ useRoute,
+} from '@react-navigation/native'
+import {useCallback, useRef, useState} from 'react'
+import {TextInput, View} from 'react-native'
+import DocumentPicker from 'react-native-document-picker'
+import {Button, Card, TouchableRipple} from 'react-native-paper'
+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 MassiveInput from './MassiveInput'
+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 weightRef = useRef(null)
+ const repsRef = useRef(null)
+ const unitRef = useRef(null)
+
+ const [selection, setSelection] = useState({
+ start: 0,
+ end: 1,
+ })
+
+ useFocusEffect(
+ useCallback(() => {
+ settingsRepo.findOne({where: {}}).then(setSettings)
+ }, []),
+ )
+
+ 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
+ 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)
+ }, [])
+
+ const handleRemove = useCallback(async () => {
+ setNewImage('')
+ setShowRemove(false)
+ }, [])
+
+ return (
+ <>
+
+
+
+ repsRef.current?.focus()}
+ />
+
+ weightRef.current?.focus()}
+ selection={selection}
+ onSelectionChange={e => setSelection(e.nativeEvent.selection)}
+ autoFocus={!!name}
+ innerRef={repsRef}
+ />
+
+
+
+ {settings.showUnit && (
+
+ )}
+
+ {settings.images && newImage && (
+ setShowRemove(true)}>
+
+
+ )}
+
+ Are you sure you want to remove the image?
+
+
+ {settings.images && !newImage && (
+
+ )}
+
+
+
+ >
+ )
+}
diff --git a/HomePage.tsx b/HomePage.tsx
index 891eaac4..580fc7fd 100644
--- a/HomePage.tsx
+++ b/HomePage.tsx
@@ -1,5 +1,6 @@
import {createStackNavigator} from '@react-navigation/stack'
import EditSet from './EditSet'
+import EditSets from './EditSets'
import {HomePageParams} from './home-page-params'
import SetList from './SetList'
@@ -11,6 +12,7 @@ export default function HomePage() {
screenOptions={{headerShown: false, animationEnabled: false}}>
+
)
}
diff --git a/PlanItem.tsx b/PlanItem.tsx
index 4b0c77ae..4e35d617 100644
--- a/PlanItem.tsx
+++ b/PlanItem.tsx
@@ -4,25 +4,26 @@ import {
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 {Text} from 'react-native'
+import {List} from 'react-native-paper'
import {getBestSet} from './best.service'
-import {planRepo} 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,
- onRemove,
+ setIds,
+ ids,
}: {
item: Plan
- onRemove: () => void
+ ids: number[]
+ setIds: (value: number[]) => void
}) {
- const [show, setShow] = useState(false)
- const [anchor, setAnchor] = useState({x: 0, y: 0})
const [today, setToday] = useState()
+ const dark = useDark()
const days = useMemo(() => item.days.split(','), [item.days])
const navigation = useNavigation>()
@@ -33,34 +34,22 @@ export default function PlanItem({
}, []),
)
- const remove = useCallback(async () => {
- 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)
const workout = item.workouts.split(',')[0]
let first = await getBestSet(workout)
if (!first) first = {...defaultSet, name: workout}
delete first.id
- navigation.navigate('StartPlan', {plan: item, first})
- }, [item, navigation])
+ if (ids.length === 0)
+ 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 longPress = useCallback(
- (e: GestureResponderEvent) => {
- 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])
+ const longPress = useCallback(() => {
+ if (ids.length > 0) return
+ setIds([item.id])
+ }, [ids.length, item.id, setIds])
const title = useMemo(
() =>
@@ -84,12 +73,11 @@ export default function PlanItem({
[item.workouts],
)
- const copy = useCallback(() => {
- const plan: Plan = {...item}
- delete plan.id
- setShow(false)
- navigation.navigate('EditPlan', {plan})
- }, [navigation, item])
+ const backgroundColor = useMemo(() => {
+ if (!ids.includes(item.id)) return
+ if (dark) return '#c2c2c2'
+ return '#c2c2c2'
+ }, [dark, ids, item.id])
return (
(
-
- )}
+ style={{backgroundColor}}
/>
)
}
diff --git a/PlanList.tsx b/PlanList.tsx
index b20fd387..eb7c04cd 100644
--- a/PlanList.tsx
+++ b/PlanList.tsx
@@ -17,6 +17,7 @@ import PlanItem from './PlanItem'
export default function PlanList() {
const [term, setTerm] = useState('')
const [plans, setPlans] = useState()
+ const [ids, setIds] = useState([])
const navigation = useNavigation>()
const refresh = useCallback(async (value: string) => {
@@ -43,9 +44,9 @@ export default function PlanList() {
const renderItem = useCallback(
({item}: {item: Plan}) => (
- refresh(term)} />
+
),
- [refresh, term],
+ [ids],
)
const onAdd = () =>
@@ -53,7 +54,7 @@ export default function PlanList() {
return (
<>
-
+
{plans?.length === 0 ? (
void
settings: Settings
+ ids: number[]
+ setIds: (value: number[]) => void
}) {
- const [showMenu, setShowMenu] = useState(false)
- const [anchor, setAnchor] = useState({x: 0, y: 0})
const dark = useDark()
const navigation = useNavigation>()
- const remove = useCallback(async () => {
- console.log(`${SetItem.name}.remove:`, {id: item.id})
- if (typeof item.id === 'number') await setRepo.delete(item.id)
- setShowMenu(false)
- onRemove()
- }, [setShowMenu, onRemove, item.id])
+ const longPress = useCallback(() => {
+ if (ids.length > 0) return
+ setIds([item.id])
+ }, [ids.length, item.id, setIds])
- const copy = useCallback(() => {
- const set: GymSet = {...item}
- delete set.id
- setShowMenu(false)
- navigation.navigate('EditSet', {set})
- }, [navigation, item])
+ const press = useCallback(() => {
+ if (ids.length === 0) return navigation.navigate('EditSet', {set: item})
+ const removing = ids.find(id => id === item.id)
+ if (removing) setIds(ids.filter(id => id !== item.id))
+ else setIds([...ids, item.id])
+ }, [ids, item, navigation, setIds])
- const longPress = useCallback(
- (e: GestureResponderEvent) => {
- setAnchor({x: e.nativeEvent.pageX, y: e.nativeEvent.pageY})
- setShowMenu(true)
- },
- [setShowMenu, setAnchor],
- )
+ const backgroundColor = useMemo(() => {
+ if (!ids.includes(item.id)) return
+ if (dark) return '#c2c2c2'
+ return '#c2c2c2'
+ }, [dark, ids, item.id])
return (
<>
navigation.navigate('EditSet', {set: item})}
+ onPress={press}
title={item.name}
description={`${item.reps} x ${item.weight}${item.unit || 'kg'}`}
onLongPress={longPress}
+ style={{backgroundColor}}
left={() =>
settings.images &&
item.image && (
@@ -69,14 +66,6 @@ export default function SetItem({
{format(new Date(item.created), settings.date || 'P')}
)}
-
>
)}
/>
diff --git a/SetList.tsx b/SetList.tsx
index eb67bbce..0955f27c 100644
--- a/SetList.tsx
+++ b/SetList.tsx
@@ -24,6 +24,7 @@ export default function SetList() {
const [term, setTerm] = useState('')
const [end, setEnd] = useState(false)
const [settings, setSettings] = useState()
+ const [ids, setIds] = useState([])
const navigation = useNavigation>()
const refresh = useCallback(async (value: string) => {
@@ -58,9 +59,11 @@ export default function SetList() {
item={item}
key={item.id}
onRemove={() => refresh(term)}
+ ids={ids}
+ setIds={setIds}
/>
),
- [refresh, term, settings],
+ [refresh, term, settings, ids],
)
const next = useCallback(async () => {
@@ -101,7 +104,7 @@ export default function SetList() {
return (
<>
-
+
{sets?.length === 0 ? (