Add images to sets

This commit is contained in:
Brandon Presley 2022-08-28 20:55:12 +12:00
parent 9b8fb95559
commit f6dec0c3b2
8 changed files with 98 additions and 25 deletions

View File

@ -16,6 +16,7 @@ import {SQLiteDatabase} from 'react-native-sqlite-storage';
import Ionicon from 'react-native-vector-icons/Ionicons'; import Ionicon from 'react-native-vector-icons/Ionicons';
import { import {
addHidden, addHidden,
addImage,
addNotify, addNotify,
addSound, addSound,
createPlans, createPlans,
@ -75,6 +76,7 @@ const App = () => {
await _db.executeSql(createWorkouts); await _db.executeSql(createWorkouts);
await _db.executeSql(addHidden).catch(() => null); await _db.executeSql(addHidden).catch(() => null);
await _db.executeSql(addNotify).catch(() => null); await _db.executeSql(addNotify).catch(() => null);
await _db.executeSql(addImage).catch(() => null);
const [result] = await _db.executeSql(`SELECT * FROM settings LIMIT 1`); const [result] = await _db.executeSql(`SELECT * FROM settings LIMIT 1`);
if (result.rows.length === 0) if (result.rows.length === 0)
return _db.executeSql(` return _db.executeSql(`

View File

@ -57,13 +57,13 @@ export default function EditSet() {
const add = useCallback( const add = useCallback(
async (set: Set) => { async (set: Set) => {
const {name, reps, weight, unit} = set; const {name, reps, weight, unit, image} = set;
const insert = ` const insert = `
INSERT INTO sets(name, reps, weight, created, unit) INSERT INTO sets(name, reps, weight, created, unit, image)
VALUES (?,?,?,strftime('%Y-%m-%dT%H:%M:%S', 'now', 'localtime'),?) VALUES (?,?,?,strftime('%Y-%m-%dT%H:%M:%S', 'now', 'localtime'),?, ?)
`; `;
startTimer(); startTimer();
await db.executeSql(insert, [name, reps, weight, unit]); await db.executeSql(insert, [name, reps, weight, unit, image]);
const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`); const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`);
const settings: Settings = result.rows.item(0); const settings: Settings = result.rows.item(0);
if (settings.notify === 0) return navigation.goBack(); if (settings.notify === 0) return navigation.goBack();

View File

@ -15,6 +15,7 @@ import {WorkoutsPageParams} from './WorkoutsPage';
export default function EditWorkout() { export default function EditWorkout() {
const [name, setName] = useState(''); const [name, setName] = useState('');
const [uri, setUri] = useState('');
const {params} = useRoute<RouteProp<WorkoutsPageParams, 'EditWorkout'>>(); const {params} = useRoute<RouteProp<WorkoutsPageParams, 'EditWorkout'>>();
const db = useContext(DatabaseContext); const db = useContext(DatabaseContext);
const navigation = useNavigation(); const navigation = useNavigation();
@ -28,22 +29,32 @@ export default function EditWorkout() {
headerRight: null, headerRight: null,
title: params.value.name ? 'Edit workout' : 'New workout', title: params.value.name ? 'Edit workout' : 'New workout',
}); });
}, [navigation, params.value.name]), db.executeSql(`SELECT image FROM sets WHERE name = ? LIMIT 1`, [
params.value.name,
]).then(([result]) => setUri(result.rows.item(0)?.image));
}, [navigation, params.value.name, db]),
); );
const update = useCallback(async () => { const update = useCallback(async () => {
console.log(`${EditWorkout.name}.update`, set); console.log(`${EditWorkout.name}.update`, set);
await db.executeSql(`UPDATE sets SET name = ? WHERE name = ?`, [ if (name) {
name, await db.executeSql(`UPDATE sets SET name = ? WHERE name = ?`, [
params.value.name, name,
]); params.value.name,
await db.executeSql( ]);
`UPDATE plans SET workouts = REPLACE(workouts, ?, ?) await db.executeSql(
`UPDATE plans SET workouts = REPLACE(workouts, ?, ?)
WHERE workouts LIKE ?`, WHERE workouts LIKE ?`,
[params.value.name, name, `%${params.value.name}%`], [params.value.name, name, `%${params.value.name}%`],
); );
}
if (uri)
await db.executeSql(`UPDATE sets SET image = ? WHERE name = ?`, [
uri,
params.value.name,
]);
navigation.goBack(); navigation.goBack();
}, [db, navigation, params.value.name, name]); }, [db, navigation, params.value.name, name, uri]);
const add = useCallback(async () => { const add = useCallback(async () => {
const insert = ` const insert = `
@ -59,18 +70,32 @@ export default function EditWorkout() {
return add(); return add();
}, [update, add, params.value.name]); }, [update, add, params.value.name]);
const changeImage = useCallback(async () => {
const {fileCopyUri} = await DocumentPicker.pickSingle({
type: 'image/*',
copyTo: 'documentDirectory',
});
if (fileCopyUri) setUri(fileCopyUri);
}, []);
return ( return (
<ScrollView style={{padding: 10, height: '90%'}}> <ScrollView style={{padding: 10, height: '90%'}}>
{params.value.name ? ( {params.value.name ? (
<> <>
<MassiveInput label="Old name" value={params.value.name} disabled /> <MassiveInput label="Old name" value={params.value.name} disabled />
<MassiveInput label="New name" value={name} onChangeText={setName} /> <MassiveInput label="New name" value={name} onChangeText={setName} />
<View style={{flexDirection: 'row', paddingBottom: 10}}>
{uri && <Image source={{uri}} style={{height: 50, width: 50}} />}
<Button onPress={changeImage} icon="image">
Image
</Button>
</View>
</> </>
) : ( ) : (
<MassiveInput label="Name" value={name} onChangeText={setName} /> <MassiveInput label="Name" value={name} onChangeText={setName} />
)} )}
<Button <Button
disabled={!name && !!params.value.name} disabled={!name && !!params.value.name && !uri}
mode="contained" mode="contained"
icon="save" icon="save"
onPress={save}> onPress={save}>

View File

@ -18,6 +18,7 @@ export default function SetForm({
const [reps, setReps] = useState(set.reps.toString()); const [reps, setReps] = useState(set.reps.toString());
const [weight, setWeight] = useState(set.weight.toString()); const [weight, setWeight] = useState(set.weight.toString());
const [unit, setUnit] = useState(set.unit); const [unit, setUnit] = useState(set.unit);
const [uri, setUri] = useState(set.image);
const [selection, setSelection] = useState({ const [selection, setSelection] = useState({
start: 0, start: 0,
end: set.reps.toString().length, end: set.reps.toString().length,
@ -33,8 +34,18 @@ export default function SetForm({
weight: Number(weight), weight: Number(weight),
id: set.id, id: set.id,
unit, unit,
image: uri,
}); });
}; };
const db = useContext(DatabaseContext);
useEffect(() => {
console.log('SetForm.useEffect:', {uri, name: set.name});
if (!uri)
db.executeSql(`SELECT image FROM sets WHERE name = ? LIMIT 1`, [
set.name,
]).then(([result]) => setUri(result.rows.item(0).image));
}, [uri, db, set.name]);
return ( return (
<> <>
@ -78,7 +89,7 @@ export default function SetForm({
{set.created.replace('T', ' ')} {set.created.replace('T', ' ')}
</Text> </Text>
)} )}
<Text> <Text style={{marginBottom: 10}}>
{workouts?.map((workout, index) => ( {workouts?.map((workout, index) => (
<React.Fragment key={workout}> <React.Fragment key={workout}>
<Text <Text
@ -92,6 +103,7 @@ export default function SetForm({
</React.Fragment> </React.Fragment>
))} ))}
</Text> </Text>
{uri && <Image source={{uri}} style={{width: 250, height: 250}} />}
</ScrollView> </ScrollView>
<Button <Button
disabled={!name} disabled={!name}

View File

@ -1,6 +1,6 @@
import {NavigationProp, useNavigation} from '@react-navigation/native'; import {NavigationProp, useNavigation} from '@react-navigation/native';
import React, {useCallback, useContext, useState} from 'react'; import React, {useCallback, useContext, useState} from 'react';
import {GestureResponderEvent, Text} from 'react-native'; import {GestureResponderEvent, Image, Text} from 'react-native';
import {Divider, List, Menu} from 'react-native-paper'; import {Divider, List, Menu} from 'react-native-paper';
import {DatabaseContext} from './App'; import {DatabaseContext} from './App';
import {HomePageParams} from './HomePage'; import {HomePageParams} from './HomePage';
@ -11,11 +11,15 @@ export default function SetItem({
onRemove, onRemove,
dates, dates,
setDates, setDates,
images,
setImages,
}: { }: {
item: Set; item: Set;
onRemove: () => void; onRemove: () => void;
dates: boolean; dates: boolean;
setDates: (value: boolean) => void; setDates: (value: boolean) => void;
images: boolean;
setImages: (value: boolean) => void;
}) { }) {
const [showMenu, setShowMenu] = useState(false); const [showMenu, setShowMenu] = useState(false);
const [anchor, setAnchor] = useState({x: 0, y: 0}); const [anchor, setAnchor] = useState({x: 0, y: 0});
@ -46,7 +50,14 @@ export default function SetItem({
const toggleDates = useCallback(() => { const toggleDates = useCallback(() => {
setDates(!dates); setDates(!dates);
setShowMenu(false); setShowMenu(false);
}, [dates, setDates]); if (!dates && images) setImages(false);
}, [dates, setDates, images, setImages]);
const toggleImages = useCallback(() => {
setImages(!images);
setShowMenu(false);
if (!images && dates) setDates(false);
}, [dates, setDates, images, setImages]);
return ( return (
<> <>
@ -56,16 +67,31 @@ export default function SetItem({
description={`${item.reps} x ${item.weight}${item.unit || 'kg'}`} description={`${item.reps} x ${item.weight}${item.unit || 'kg'}`}
onLongPress={longPress} onLongPress={longPress}
right={() => ( right={() => (
<Text <>
style={{ {dates && (
alignSelf: 'center', <Text
}}> style={{
{dates ? item.created?.replace('T', ' ') : null} alignSelf: 'center',
}}>
{item.created?.replace('T', ' ')}
</Text>
)}
{images && (
<Image
source={{uri: item.image}}
style={{height: 75, width: 75}}
/>
)}
<Menu <Menu
anchor={anchor} anchor={anchor}
visible={showMenu} visible={showMenu}
onDismiss={() => setShowMenu(false)}> onDismiss={() => setShowMenu(false)}>
<Menu.Item icon="copy" onPress={copy} title="Copy" /> <Menu.Item icon="copy" onPress={copy} title="Copy" />
<Menu.Item
icon="image-outline"
onPress={toggleImages}
title="Images"
/>
<Menu.Item <Menu.Item
icon="calendar-outline" icon="calendar-outline"
onPress={toggleDates} onPress={toggleDates}
@ -74,7 +100,7 @@ export default function SetItem({
<Divider /> <Divider />
<Menu.Item icon="trash" onPress={remove} title="Delete" /> <Menu.Item icon="trash" onPress={remove} title="Delete" />
</Menu> </Menu>
</Text> </>
)} )}
/> />
</> </>

View File

@ -34,6 +34,7 @@ export default function SetList() {
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const [end, setEnd] = useState(false); const [end, setEnd] = useState(false);
const [dates, setDates] = useState(false); const [dates, setDates] = useState(false);
const [images, setImages] = useState(false);
const db = useContext(DatabaseContext); const db = useContext(DatabaseContext);
const navigation = useNavigation<NavigationProp<HomePageParams>>(); const navigation = useNavigation<NavigationProp<HomePageParams>>();
@ -143,12 +144,14 @@ export default function SetList() {
<SetItem <SetItem
dates={dates} dates={dates}
setDates={setDates} setDates={setDates}
images={images}
setImages={setImages}
item={item} item={item}
key={item.id} key={item.id}
onRemove={refresh} onRemove={refresh}
/> />
), ),
[refresh, dates, setDates], [refresh, dates, setDates, images, setImages],
); );
const next = useCallback(async () => { const next = useCallback(async () => {

4
db.ts
View File

@ -51,3 +51,7 @@ export const addHidden = `
export const addNotify = ` export const addNotify = `
ALTER TABLE settings ADD COLUMN notify DEFAULT false; ALTER TABLE settings ADD COLUMN notify DEFAULT false;
`; `;
export const addImage = `
ALTER TABLE sets ADD COLUMN image TEXT NULL;
`;

1
set.ts
View File

@ -6,4 +6,5 @@ export default interface Set {
created?: string; created?: string;
unit?: string; unit?: string;
hidden?: boolean; hidden?: boolean;
image?: string;
} }