Factor out MassiveFab

This commit is contained in:
Brandon Presley 2022-07-08 14:59:19 +12:00
parent dc21f1266e
commit b12b41b77e
6 changed files with 47 additions and 63 deletions

View File

@ -17,13 +17,11 @@ const DAYS = [
export default function EditPlan({ export default function EditPlan({
plan, plan,
onSave, onSave,
show, setPlan,
setShow,
}: { }: {
onSave: () => void; onSave: () => void;
show: boolean;
setShow: (visible: boolean) => void;
plan?: Plan; plan?: Plan;
setPlan: (plan?: Plan) => void;
}) { }) {
const [days, setDays] = useState<string[]>([]); const [days, setDays] = useState<string[]>([]);
const [workouts, setWorkouts] = useState<string[]>([]); const [workouts, setWorkouts] = useState<string[]>([]);
@ -41,7 +39,7 @@ export default function EditPlan({
useEffect(() => { useEffect(() => {
refresh(); refresh();
}, [plan, show]); }, [plan]);
const save = async () => { const save = async () => {
if (!days || !workouts) return; if (!days || !workouts) return;
@ -57,7 +55,7 @@ export default function EditPlan({
`UPDATE plans SET days = ?, workouts = ? WHERE id = ?`, `UPDATE plans SET days = ?, workouts = ? WHERE id = ?`,
[newDays, newWorkouts, plan.id], [newDays, newWorkouts, plan.id],
); );
setShow(false); setPlan(undefined);
onSave(); onSave();
}; };
@ -79,7 +77,7 @@ export default function EditPlan({
return ( return (
<Portal> <Portal>
<Dialog visible={show} onDismiss={() => setShow(false)}> <Dialog visible={!!plan} onDismiss={() => setPlan(undefined)}>
<Dialog.Title> <Dialog.Title>
{plan ? `Edit "${days.slice(0, 2).join(', ')}"` : 'Add a plan'} {plan ? `Edit "${days.slice(0, 2).join(', ')}"` : 'Add a plan'}
</Dialog.Title> </Dialog.Title>
@ -123,7 +121,7 @@ export default function EditPlan({
</View> </View>
</Dialog.Content> </Dialog.Content>
<Dialog.Actions> <Dialog.Actions>
<Button icon="close" onPress={() => setShow(false)}> <Button icon="close" onPress={() => setPlan(undefined)}>
Cancel Cancel
</Button> </Button>
<Button mode="contained" icon="save" onPress={save}> <Button mode="contained" icon="save" onPress={save}>

View File

@ -1,9 +1,10 @@
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import React, {useContext, useEffect, useState} from 'react'; import React, {useContext, useEffect, useState} from 'react';
import {FlatList, NativeModules, StyleSheet, View} from 'react-native'; import {FlatList, NativeModules, StyleSheet, View} from 'react-native';
import {AnimatedFAB, List, Searchbar} from 'react-native-paper'; import {List, Searchbar} from 'react-native-paper';
import {DatabaseContext} from './App'; import {DatabaseContext} from './App';
import EditSet from './EditSet'; import EditSet from './EditSet';
import MassiveFab from './MassiveFab';
import Set from './set'; import Set from './set';
import SetItem from './SetItem'; import SetItem from './SetItem';
@ -99,13 +100,7 @@ export default function Home() {
/> />
<EditSet set={edit} setSet={setEdit} onSave={save} /> <EditSet set={edit} setSet={setEdit} onSave={save} />
<AnimatedFAB <MassiveFab onPress={() => setEdit({} as Set)} />
extended={false}
label="Add"
icon="add"
style={{position: 'absolute', right: 10, bottom: 50}}
onPress={() => setEdit({} as Set)}
/>
</View> </View>
); );
} }

16
MassiveFab.tsx Normal file
View File

@ -0,0 +1,16 @@
import {AnimatedFAB} from 'react-native-paper';
import React from 'react';
export default function MassiveFab(
props: Partial<React.ComponentProps<typeof AnimatedFAB>>,
) {
return (
<AnimatedFAB
{...props}
extended={false}
label="Add"
icon="add"
style={{position: 'absolute', right: 10, bottom: 50}}
/>
);
}

View File

@ -1,20 +1,20 @@
import React, {useContext, useState} from 'react'; import React, {useContext, useState} from 'react';
import {IconButton, List, Menu} from 'react-native-paper'; import {GestureResponderEvent} from 'react-native';
import {List, Menu} from 'react-native-paper';
import {DatabaseContext} from './App'; import {DatabaseContext} from './App';
import {Plan} from './plan'; import {Plan} from './plan';
export default function PlanItem({ export default function PlanItem({
item, item,
setPlan, setPlan,
setShowEdit,
onRemove, onRemove,
}: { }: {
item: Plan; item: Plan;
setPlan: (plan: Plan) => void; setPlan: (plan: Plan) => void;
setShowEdit: (show: boolean) => void;
onRemove: () => void; onRemove: () => void;
}) { }) {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const [anchor, setAnchor] = useState({x: 0, y: 0});
const db = useContext(DatabaseContext); const db = useContext(DatabaseContext);
const remove = async () => { const remove = async () => {
@ -23,26 +23,20 @@ export default function PlanItem({
onRemove(); onRemove();
}; };
const longPress = (e: GestureResponderEvent) => {
setAnchor({x: e.nativeEvent.pageX, y: e.nativeEvent.pageY});
setShow(true);
};
return ( return (
<> <>
<List.Item <List.Item
onPress={() => { onPress={() => setPlan(item)}
setPlan(item);
setShowEdit(true);
}}
title={item.days.replace(/,/g, ', ')} title={item.days.replace(/,/g, ', ')}
description={item.workouts.replace(/,/g, ', ')} description={item.workouts.replace(/,/g, ', ')}
onLongPress={() => setShow(true)} onLongPress={longPress}
right={() => ( right={() => (
<Menu <Menu anchor={anchor} visible={show} onDismiss={() => setShow(false)}>
anchor={
<IconButton
icon="ellipsis-vertical"
onPress={() => setShow(true)}
/>
}
visible={show}
onDismiss={() => setShow(false)}>
<Menu.Item icon="trash" onPress={remove} title="Delete" /> <Menu.Item icon="trash" onPress={remove} title="Delete" />
</Menu> </Menu>
)} )}

View File

@ -1,8 +1,9 @@
import React, {useContext, useEffect, useState} from 'react'; import React, {useContext, useEffect, useState} from 'react';
import {FlatList, StyleSheet, View} from 'react-native'; import {FlatList, StyleSheet, View} from 'react-native';
import {AnimatedFAB, List, Searchbar} from 'react-native-paper'; import {List, Searchbar} from 'react-native-paper';
import {DatabaseContext} from './App'; import {DatabaseContext} from './App';
import EditPlan from './EditPlan'; import EditPlan from './EditPlan';
import MassiveFab from './MassiveFab';
import {Plan} from './plan'; import {Plan} from './plan';
import PlanItem from './PlanItem'; import PlanItem from './PlanItem';
@ -11,7 +12,6 @@ export default function Plans() {
const [plans, setPlans] = useState<Plan[]>([]); const [plans, setPlans] = useState<Plan[]>([]);
const [refreshing, setRefresing] = useState(false); const [refreshing, setRefresing] = useState(false);
const [plan, setPlan] = useState<Plan>(); const [plan, setPlan] = useState<Plan>();
const [showEdit, setShowEdit] = useState(false);
const db = useContext(DatabaseContext); const db = useContext(DatabaseContext);
const selectPlans = ` const selectPlans = `
@ -31,13 +31,7 @@ export default function Plans() {
}, [search]); }, [search]);
const renderItem = ({item}: {item: Plan}) => ( const renderItem = ({item}: {item: Plan}) => (
<PlanItem <PlanItem item={item} key={item.id} setPlan={setPlan} onRemove={refresh} />
item={item}
key={item.id}
setShowEdit={setShowEdit}
setPlan={setPlan}
onRemove={refresh}
/>
); );
return ( return (
@ -61,21 +55,11 @@ export default function Plans() {
} }
/> />
<EditPlan <EditPlan setPlan={setPlan} onSave={refresh} plan={plan} />
onSave={refresh}
setShow={setShowEdit}
show={showEdit}
plan={plan}
/>
<AnimatedFAB <MassiveFab
extended={false}
label="Add"
icon="add"
style={{position: 'absolute', right: 20, bottom: 50}}
onPress={() => { onPress={() => {
setPlan(undefined); setPlan({} as Plan);
setShowEdit(true);
}} }}
/> />
</View> </View>

View File

@ -13,25 +13,25 @@ export default function SetItem({
setSet: (set: Set) => void; setSet: (set: Set) => void;
onRemove: () => void; onRemove: () => void;
}) { }) {
const [showMenu, setShowMenu] = useState(false); const [show, setShow] = useState(false);
const [anchor, setAnchor] = useState({x: 0, y: 0}); const [anchor, setAnchor] = useState({x: 0, y: 0});
const db = useContext(DatabaseContext); const db = useContext(DatabaseContext);
const remove = async () => { const remove = async () => {
await db.executeSql(`DELETE FROM sets WHERE id = ?`, [item.id]); await db.executeSql(`DELETE FROM sets WHERE id = ?`, [item.id]);
setShowMenu(false); setShow(false);
onRemove(); onRemove();
}; };
const copy = () => { const copy = () => {
const {id, ...set} = {...item}; const {id, ...set} = {...item};
setSet(set); setSet(set);
setShowMenu(false); setShow(false);
}; };
const longPress = (e: GestureResponderEvent) => { const longPress = (e: GestureResponderEvent) => {
setAnchor({x: e.nativeEvent.pageX, y: e.nativeEvent.pageY}); setAnchor({x: e.nativeEvent.pageX, y: e.nativeEvent.pageY});
setShowMenu(true); setShow(true);
}; };
return ( return (
@ -44,10 +44,7 @@ export default function SetItem({
description={`${item.reps} x ${item.weight}${item.unit}`} description={`${item.reps} x ${item.weight}${item.unit}`}
onLongPress={longPress} onLongPress={longPress}
right={() => ( right={() => (
<Menu <Menu anchor={anchor} visible={show} onDismiss={() => setShow(false)}>
anchor={anchor}
visible={showMenu}
onDismiss={() => setShowMenu(false)}>
<Menu.Item icon="trash" onPress={remove} title="Delete" /> <Menu.Item icon="trash" onPress={remove} title="Delete" />
<Menu.Item icon="copy" onPress={copy} title="Copy" /> <Menu.Item icon="copy" onPress={copy} title="Copy" />
</Menu> </Menu>