Move sessions page functionality onto Plan page
The sessions page mostly copied the exact same features as Plans, which would confuse the user.
This commit is contained in:
parent
5481e8a20d
commit
e0b84af9e7
42
PlanItem.tsx
42
PlanItem.tsx
|
@ -1,10 +1,12 @@
|
|||
import {NavigationProp, useNavigation} from '@react-navigation/native';
|
||||
import React, {useCallback, useState} from 'react';
|
||||
import {GestureResponderEvent} from 'react-native';
|
||||
import React, {useCallback, useMemo, useState} from 'react';
|
||||
import {GestureResponderEvent, Text} from 'react-native';
|
||||
import {List, Menu} from 'react-native-paper';
|
||||
import {getBestSet} from './best.service';
|
||||
import {Plan} from './plan';
|
||||
import {PlanPageParams} from './plan-page-params';
|
||||
import {deletePlan} from './plan.service';
|
||||
import {DAYS} from './time';
|
||||
|
||||
export default function PlanItem({
|
||||
item,
|
||||
|
@ -15,7 +17,9 @@ export default function PlanItem({
|
|||
}) {
|
||||
const [show, setShow] = useState(false);
|
||||
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
||||
const days = useMemo(() => item.days.split(','), [item.days]);
|
||||
const navigation = useNavigation<NavigationProp<PlanPageParams>>();
|
||||
const today = useMemo(() => DAYS[new Date().getDay()], []);
|
||||
|
||||
const remove = useCallback(async () => {
|
||||
if (typeof item.id === 'number') await deletePlan(item.id);
|
||||
|
@ -23,6 +27,14 @@ export default function PlanItem({
|
|||
onRemove();
|
||||
}, [setShow, item.id, onRemove]);
|
||||
|
||||
const start = useCallback(async () => {
|
||||
const workouts = item.workouts.split(',');
|
||||
const first = workouts[0];
|
||||
const set = await getBestSet(first);
|
||||
setShow(false);
|
||||
navigation.navigate('StartPlan', {plan: item, set});
|
||||
}, [item, navigation]);
|
||||
|
||||
const longPress = useCallback(
|
||||
(e: GestureResponderEvent) => {
|
||||
setAnchor({x: e.nativeEvent.pageX, y: e.nativeEvent.pageY});
|
||||
|
@ -31,19 +43,33 @@ export default function PlanItem({
|
|||
[setAnchor, setShow],
|
||||
);
|
||||
|
||||
const edit = useCallback(() => {
|
||||
setShow(false);
|
||||
navigation.navigate('EditPlan', {plan: item});
|
||||
}, [navigation, item]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<List.Item
|
||||
onPress={() => navigation.navigate('EditPlan', {plan: item})}
|
||||
title={
|
||||
item.days
|
||||
? item.days.replace(/,/g, ', ')
|
||||
: item.workouts.replace(/,/g, ', ')
|
||||
}
|
||||
onPress={start}
|
||||
title={days.map((day, index) => (
|
||||
<Text key={day}>
|
||||
{day === today ? (
|
||||
<Text
|
||||
style={{fontWeight: 'bold', textDecorationLine: 'underline'}}>
|
||||
{day}
|
||||
</Text>
|
||||
) : (
|
||||
day
|
||||
)}
|
||||
{index === days.length - 1 ? '' : ', '}
|
||||
</Text>
|
||||
))}
|
||||
description={item.days ? item.workouts.replace(/,/g, ', ') : null}
|
||||
onLongPress={longPress}
|
||||
right={() => (
|
||||
<Menu anchor={anchor} visible={show} onDismiss={() => setShow(false)}>
|
||||
<Menu.Item icon="edit" onPress={edit} title="Edit" />
|
||||
<Menu.Item icon="delete" onPress={remove} title="Delete" />
|
||||
</Menu>
|
||||
)}
|
||||
|
|
15
PlanPage.tsx
15
PlanPage.tsx
|
@ -7,6 +7,7 @@ import {DrawerParamList} from './drawer-param-list';
|
|||
import EditPlan from './EditPlan';
|
||||
import {PlanPageParams} from './plan-page-params';
|
||||
import PlanList from './PlanList';
|
||||
import StartPlan from './StartPlan';
|
||||
|
||||
const Stack = createStackNavigator<PlanPageParams>();
|
||||
|
||||
|
@ -31,6 +32,20 @@ export default function PlanPage() {
|
|||
},
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="StartPlan"
|
||||
component={StartPlan}
|
||||
listeners={{
|
||||
beforeRemove: () => {
|
||||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
||||
),
|
||||
title: 'Plans',
|
||||
});
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import {DrawerParamList} from './drawer-param-list';
|
|||
import HomePage from './HomePage';
|
||||
import PlanPage from './PlanPage';
|
||||
import Route from './route';
|
||||
import SessionPage from './SessionPage';
|
||||
import SettingsPage from './SettingsPage';
|
||||
import useDark from './use-dark';
|
||||
import WorkoutsPage from './WorkoutsPage';
|
||||
|
@ -19,7 +18,6 @@ export default function Routes() {
|
|||
const routes: Route[] = [
|
||||
{name: 'Home', component: HomePage, icon: 'home'},
|
||||
{name: 'Plans', component: PlanPage, icon: 'event'},
|
||||
{name: 'Session', component: SessionPage, icon: 'directions-run'},
|
||||
{name: 'Best', component: BestPage, icon: 'insights'},
|
||||
{name: 'Workouts', component: WorkoutsPage, icon: 'fitness-center'},
|
||||
{name: 'Settings', component: SettingsPage, icon: 'settings'},
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
import {
|
||||
NavigationProp,
|
||||
useFocusEffect,
|
||||
useNavigation,
|
||||
} from '@react-navigation/native';
|
||||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {FlatList} from 'react-native';
|
||||
import {List} from 'react-native-paper';
|
||||
import {getBestSet} from './best.service';
|
||||
import Page from './Page';
|
||||
import {Plan} from './plan';
|
||||
import {getPlans} from './plan.service';
|
||||
import {SessionPageParams} from './session-page-params';
|
||||
|
||||
export default function SessionList() {
|
||||
const [search, setSearch] = useState('');
|
||||
const [plans, setPlans] = useState<Plan[]>([]);
|
||||
const navigation = useNavigation<NavigationProp<SessionPageParams>>();
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
getPlans(search).then(setPlans);
|
||||
}, [search]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
refresh();
|
||||
}, [refresh]),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
}, [search, refresh]);
|
||||
|
||||
const press = useCallback(
|
||||
async (item: Plan) => {
|
||||
const workouts = item.workouts.split(',');
|
||||
const first = workouts[0];
|
||||
const set = await getBestSet(first);
|
||||
navigation.navigate('StartSession', {plan: item, set});
|
||||
},
|
||||
[navigation],
|
||||
);
|
||||
|
||||
const renderItem = useCallback(
|
||||
({item}: {item: Plan}) => (
|
||||
<List.Item
|
||||
title={item.days.replace(/,/g, ', ')}
|
||||
description={item.workouts.replace(/,/g, ', ')}
|
||||
onPress={() => press(item)}
|
||||
/>
|
||||
),
|
||||
[press],
|
||||
);
|
||||
|
||||
return (
|
||||
<Page search={search} setSearch={setSearch}>
|
||||
<FlatList
|
||||
style={{height: '99%'}}
|
||||
data={plans}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={set => set.id?.toString() || ''}
|
||||
ListEmptyComponent={
|
||||
<List.Item
|
||||
title="No plans yet"
|
||||
description="After making a plan, you can use it here."
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Page>
|
||||
);
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
import {DrawerNavigationProp} from '@react-navigation/drawer';
|
||||
import {useNavigation} from '@react-navigation/native';
|
||||
import {createStackNavigator} from '@react-navigation/stack';
|
||||
import React from 'react';
|
||||
import {IconButton} from 'react-native-paper';
|
||||
import {DrawerParamList} from './drawer-param-list';
|
||||
import {SessionPageParams} from './session-page-params';
|
||||
import SessionList from './SessionList';
|
||||
import StartSession from './StartSession';
|
||||
|
||||
const Stack = createStackNavigator<SessionPageParams>();
|
||||
|
||||
export default function SessionPage() {
|
||||
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
|
||||
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{headerShown: false, animationEnabled: false}}>
|
||||
<Stack.Screen name="SessionList" component={SessionList} />
|
||||
<Stack.Screen
|
||||
name="StartSession"
|
||||
component={StartSession}
|
||||
listeners={{
|
||||
beforeRemove: () => {
|
||||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
||||
),
|
||||
title: 'Session',
|
||||
});
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
|
@ -12,13 +12,13 @@ import {MARGIN, PADDING} from './constants';
|
|||
import CountMany from './count-many';
|
||||
import MassiveInput from './MassiveInput';
|
||||
import {SnackbarContext} from './MassiveSnack';
|
||||
import {SessionPageParams} from './session-page-params';
|
||||
import {PlanPageParams} from './plan-page-params';
|
||||
import {addSet, countManyToday} from './set.service';
|
||||
import SetForm from './SetForm';
|
||||
import {useSettings} from './use-settings';
|
||||
|
||||
export default function StartSession() {
|
||||
const {params} = useRoute<RouteProp<SessionPageParams, 'StartSession'>>();
|
||||
export default function StartPlan() {
|
||||
const {params} = useRoute<RouteProp<PlanPageParams, 'StartPlan'>>();
|
||||
const {set} = params;
|
||||
const [name, setName] = useState(set.name);
|
||||
const [reps, setReps] = useState(set.reps.toString());
|
||||
|
@ -64,6 +64,7 @@ export default function StartSession() {
|
|||
unit,
|
||||
});
|
||||
countManyToday().then(setCounts);
|
||||
toast('Saved workout', 3000);
|
||||
if (!settings.alarm) return;
|
||||
const milliseconds = Number(minutes) * 60 * 1000 + Number(seconds) * 1000;
|
||||
const args = [milliseconds, !!settings.vibrate, settings.sound];
|
||||
|
@ -81,11 +82,11 @@ export default function StartSession() {
|
|||
|
||||
const select = useCallback(
|
||||
async (index: number) => {
|
||||
console.log(`${StartSession.name}.next:`, {name, workouts});
|
||||
console.log(`${StartPlan.name}.next:`, {name, workouts});
|
||||
const workout = workouts[index];
|
||||
console.log(`${StartSession.name}.next:`, {workout});
|
||||
console.log(`${StartPlan.name}.next:`, {workout});
|
||||
const best = await getBestSet(workout);
|
||||
console.log(`${StartSession.name}.next:`, {best});
|
||||
console.log(`${StartPlan.name}.next:`, {best});
|
||||
setMinutes(best.minutes);
|
||||
setSeconds(best.seconds);
|
||||
setName(best.name);
|
||||
|
@ -97,47 +98,50 @@ export default function StartSession() {
|
|||
);
|
||||
|
||||
return (
|
||||
<View style={{padding: PADDING}}>
|
||||
<MassiveInput
|
||||
label="Reps"
|
||||
keyboardType="numeric"
|
||||
value={reps}
|
||||
onChangeText={setReps}
|
||||
onSubmitEditing={() => weightRef.current?.focus()}
|
||||
selection={selection}
|
||||
onSelectionChange={e => setSelection(e.nativeEvent.selection)}
|
||||
autoFocus
|
||||
innerRef={repsRef}
|
||||
/>
|
||||
<MassiveInput
|
||||
label="Weight"
|
||||
keyboardType="numeric"
|
||||
value={weight}
|
||||
onChangeText={setWeight}
|
||||
onSubmitEditing={handleSubmit}
|
||||
innerRef={weightRef}
|
||||
/>
|
||||
{!!settings.showUnit && (
|
||||
<View style={{padding: PADDING, flex: 1, flexDirection: 'column'}}>
|
||||
<View style={{flex: 1}}>
|
||||
<MassiveInput
|
||||
autoCapitalize="none"
|
||||
label="Unit"
|
||||
value={unit}
|
||||
onChangeText={handleUnit}
|
||||
innerRef={unitRef}
|
||||
label="Reps"
|
||||
keyboardType="numeric"
|
||||
value={reps}
|
||||
onChangeText={setReps}
|
||||
onSubmitEditing={() => weightRef.current?.focus()}
|
||||
selection={selection}
|
||||
onSelectionChange={e => setSelection(e.nativeEvent.selection)}
|
||||
autoFocus
|
||||
innerRef={repsRef}
|
||||
/>
|
||||
)}
|
||||
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
|
||||
{workouts.map((workout, index) => (
|
||||
<Chip
|
||||
key={workout}
|
||||
selected={workout === name}
|
||||
icon="fitness-center"
|
||||
onPress={() => select(index)}
|
||||
style={{marginBottom: MARGIN, marginRight: MARGIN}}>
|
||||
{workout} x
|
||||
{counts?.find(count => count.name === workout)?.total || 0}
|
||||
</Chip>
|
||||
))}
|
||||
<MassiveInput
|
||||
label="Weight"
|
||||
keyboardType="numeric"
|
||||
value={weight}
|
||||
onChangeText={setWeight}
|
||||
onSubmitEditing={handleSubmit}
|
||||
innerRef={weightRef}
|
||||
blurOnSubmit
|
||||
/>
|
||||
{!!settings.showUnit && (
|
||||
<MassiveInput
|
||||
autoCapitalize="none"
|
||||
label="Unit"
|
||||
value={unit}
|
||||
onChangeText={handleUnit}
|
||||
innerRef={unitRef}
|
||||
/>
|
||||
)}
|
||||
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
|
||||
{workouts.map((workout, index) => (
|
||||
<Chip
|
||||
key={workout}
|
||||
selected={workout === name}
|
||||
icon="fitness-center"
|
||||
onPress={() => select(index)}
|
||||
style={{marginBottom: MARGIN, marginRight: MARGIN}}>
|
||||
{workout} x
|
||||
{counts?.find(count => count.name === workout)?.total || 0}
|
||||
</Chip>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
<Button mode="contained" icon="save" onPress={handleSubmit}>
|
||||
Save
|
|
@ -83,6 +83,7 @@ class TimerService() : Service() {
|
|||
.setProgress(0, 0, false)
|
||||
.setAutoCancel(true)
|
||||
.setOngoing(true)
|
||||
.setContentIntent(finishPending)
|
||||
.setFullScreenIntent(finishPending, true)
|
||||
.setChannelId(CHANNEL_ID_DONE)
|
||||
.setCategory(NotificationCompat.CATEGORY_ALARM)
|
||||
|
|
|
@ -4,5 +4,4 @@ export type DrawerParamList = {
|
|||
Best: {};
|
||||
Plans: {};
|
||||
Workouts: {};
|
||||
Session: {};
|
||||
};
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import {Plan} from './plan';
|
||||
import Set from './set';
|
||||
|
||||
export type PlanPageParams = {
|
||||
PlanList: {};
|
||||
EditPlan: {
|
||||
plan: Plan;
|
||||
};
|
||||
StartPlan: {
|
||||
plan: Plan;
|
||||
set: Set;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
import {Plan} from './plan';
|
||||
import Set from './set';
|
||||
|
||||
export type SessionPageParams = {
|
||||
SessionList: {};
|
||||
StartSession: {
|
||||
plan: Plan;
|
||||
set: Set;
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user