Fix single views for new custom headers
This commit is contained in:
parent
36e6637ba2
commit
80b1a1ef56
|
@ -8,7 +8,7 @@ import {FlatList, Image} from 'react-native';
|
|||
import {List} from 'react-native-paper';
|
||||
import {getBestReps, getBestWeights} from './best.service';
|
||||
import {BestPageParams} from './BestPage';
|
||||
import Header from './Header';
|
||||
import DrawerHeader from './DrawerHeader';
|
||||
import Page from './Page';
|
||||
import Set from './set';
|
||||
import {useSettings} from './use-settings';
|
||||
|
@ -33,10 +33,7 @@ export default function BestList() {
|
|||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
refresh();
|
||||
navigation.getParent()?.setOptions({
|
||||
headerRight: () => null,
|
||||
});
|
||||
}, [refresh, navigation]),
|
||||
}, [refresh]),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -60,7 +57,7 @@ export default function BestList() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header name="Best" />
|
||||
<DrawerHeader name="Best" />
|
||||
<Page search={search} setSearch={setSearch}>
|
||||
{bests?.length === 0 ? (
|
||||
<List.Item
|
||||
|
|
21
BestPage.tsx
21
BestPage.tsx
|
@ -1,10 +1,6 @@
|
|||
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 BestList from './BestList';
|
||||
import {DrawerParamList} from './drawer-param-list';
|
||||
import Set from './set';
|
||||
import ViewBest from './ViewBest';
|
||||
|
||||
|
@ -17,26 +13,11 @@ export type BestPageParams = {
|
|||
};
|
||||
|
||||
export default function BestPage() {
|
||||
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
|
||||
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{headerShown: false, animationEnabled: false}}>
|
||||
<Stack.Screen name="BestList" component={BestList} />
|
||||
<Stack.Screen
|
||||
name="ViewBest"
|
||||
component={ViewBest}
|
||||
listeners={{
|
||||
beforeRemove: () => {
|
||||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
||||
),
|
||||
title: 'Best',
|
||||
});
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen name="ViewBest" component={ViewBest} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import {DrawerNavigationProp} from '@react-navigation/drawer';
|
||||
import {useNavigation} from '@react-navigation/native';
|
||||
import React from 'react';
|
||||
import {Appbar, IconButton} from 'react-native-paper';
|
||||
import {DrawerParamList} from './drawer-param-list';
|
||||
import DrawerMenu from './DrawerMenu';
|
||||
|
||||
export default function Header({name}: {name: keyof DrawerParamList}) {
|
||||
const navigation = useNavigation();
|
||||
export default function DrawerHeader({name}: {name: keyof DrawerParamList}) {
|
||||
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
|
||||
|
||||
return (
|
||||
<Appbar.Header>
|
||||
<IconButton icon="menu" onPress={(navigation as any).openDrawer} />
|
||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
||||
<Appbar.Content title={name} />
|
||||
<DrawerMenu name={name} />
|
||||
</Appbar.Header>
|
120
EditPlan.tsx
120
EditPlan.tsx
|
@ -1,18 +1,18 @@
|
|||
import {
|
||||
NavigationProp,
|
||||
RouteProp,
|
||||
useFocusEffect,
|
||||
useNavigation,
|
||||
useRoute,
|
||||
} from '@react-navigation/native';
|
||||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {ScrollView, StyleSheet, View} from 'react-native';
|
||||
import {Button, IconButton, Text} from 'react-native-paper';
|
||||
import {Button, Text} from 'react-native-paper';
|
||||
import {MARGIN, PADDING} from './constants';
|
||||
import {DrawerParamList} from './drawer-param-list';
|
||||
import {PlanPageParams} from './plan-page-params';
|
||||
import {addPlan, updatePlan} from './plan.service';
|
||||
import {getNames} from './set.service';
|
||||
import StackHeader from './StackHeader';
|
||||
import Switch from './Switch';
|
||||
import {DAYS} from './time';
|
||||
|
||||
|
@ -28,19 +28,6 @@ export default function EditPlan() {
|
|||
const [names, setNames] = useState<string[]>([]);
|
||||
const navigation = useNavigation<NavigationProp<DrawerParamList>>();
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
console.log(`${EditPlan.name}.focus:`, {plan});
|
||||
navigation.getParent()?.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
||||
),
|
||||
headerRight: () => null,
|
||||
title: plan.id ? 'Edit plan' : 'Create plan',
|
||||
});
|
||||
}, [navigation, plan]),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
getNames().then(n => {
|
||||
console.log(EditPlan.name, {n});
|
||||
|
@ -87,59 +74,62 @@ export default function EditPlan() {
|
|||
);
|
||||
|
||||
return (
|
||||
<View style={{padding: PADDING, flex: 1}}>
|
||||
<ScrollView style={{flex: 1}}>
|
||||
<Text style={styles.title}>Days</Text>
|
||||
{DAYS.map(day => (
|
||||
<Switch
|
||||
key={day}
|
||||
onValueChange={value => toggleDay(value, day)}
|
||||
onPress={() => toggleDay(!days.includes(day), day)}
|
||||
value={days.includes(day)}>
|
||||
{day}
|
||||
</Switch>
|
||||
))}
|
||||
<Text style={[styles.title, {marginTop: MARGIN}]}>Workouts</Text>
|
||||
{names.length === 0 ? (
|
||||
<View>
|
||||
<Text>No workouts found.</Text>
|
||||
</View>
|
||||
) : (
|
||||
names.map(name => (
|
||||
<>
|
||||
<StackHeader title="Edit plan" />
|
||||
<View style={{padding: PADDING, flex: 1}}>
|
||||
<ScrollView style={{flex: 1}}>
|
||||
<Text style={styles.title}>Days</Text>
|
||||
{DAYS.map(day => (
|
||||
<Switch
|
||||
key={name}
|
||||
onValueChange={value => toggleWorkout(value, name)}
|
||||
value={workouts.includes(name)}
|
||||
onPress={() => toggleWorkout(!workouts.includes(name), name)}>
|
||||
{name}
|
||||
key={day}
|
||||
onValueChange={value => toggleDay(value, day)}
|
||||
onPress={() => toggleDay(!days.includes(day), day)}
|
||||
value={days.includes(day)}>
|
||||
{day}
|
||||
</Switch>
|
||||
))
|
||||
))}
|
||||
<Text style={[styles.title, {marginTop: MARGIN}]}>Workouts</Text>
|
||||
{names.length === 0 ? (
|
||||
<View>
|
||||
<Text>No workouts found.</Text>
|
||||
</View>
|
||||
) : (
|
||||
names.map(name => (
|
||||
<Switch
|
||||
key={name}
|
||||
onValueChange={value => toggleWorkout(value, name)}
|
||||
value={workouts.includes(name)}
|
||||
onPress={() => toggleWorkout(!workouts.includes(name), name)}>
|
||||
{name}
|
||||
</Switch>
|
||||
))
|
||||
)}
|
||||
</ScrollView>
|
||||
{names.length === 0 ? (
|
||||
<Button
|
||||
disabled={workouts.length === 0 && days.length === 0}
|
||||
mode="contained"
|
||||
onPress={() => {
|
||||
navigation.goBack();
|
||||
navigation.navigate('Workouts', {
|
||||
screen: 'EditWorkout',
|
||||
params: {value: {name: ''}},
|
||||
});
|
||||
}}>
|
||||
Add workout
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
disabled={workouts.length === 0 && days.length === 0}
|
||||
style={{marginTop: MARGIN}}
|
||||
mode="contained"
|
||||
icon="save"
|
||||
onPress={save}>
|
||||
Save
|
||||
</Button>
|
||||
)}
|
||||
</ScrollView>
|
||||
{names.length === 0 ? (
|
||||
<Button
|
||||
disabled={workouts.length === 0 && days.length === 0}
|
||||
mode="contained"
|
||||
onPress={() => {
|
||||
navigation.goBack();
|
||||
navigation.navigate('Workouts', {
|
||||
screen: 'EditWorkout',
|
||||
params: {value: {name: ''}},
|
||||
});
|
||||
}}>
|
||||
Add workout
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
disabled={workouts.length === 0 && days.length === 0}
|
||||
style={{marginTop: MARGIN}}
|
||||
mode="contained"
|
||||
icon="save"
|
||||
onPress={save}>
|
||||
Save
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
33
EditSet.tsx
33
EditSet.tsx
|
@ -1,18 +1,13 @@
|
|||
import {
|
||||
RouteProp,
|
||||
useFocusEffect,
|
||||
useNavigation,
|
||||
useRoute,
|
||||
} from '@react-navigation/native';
|
||||
import {RouteProp, useNavigation, useRoute} from '@react-navigation/native';
|
||||
import React, {useCallback} from 'react';
|
||||
import {NativeModules, View} from 'react-native';
|
||||
import {IconButton} from 'react-native-paper';
|
||||
import {PADDING} from './constants';
|
||||
import {HomePageParams} from './home-page-params';
|
||||
import {useSnackbar} from './MassiveSnack';
|
||||
import Set from './set';
|
||||
import {addSet, getSet, updateSet} from './set.service';
|
||||
import SetForm from './SetForm';
|
||||
import StackHeader from './StackHeader';
|
||||
import {useSettings} from './use-settings';
|
||||
|
||||
export default function EditSet() {
|
||||
|
@ -22,21 +17,6 @@ export default function EditSet() {
|
|||
const {toast} = useSnackbar();
|
||||
const {settings} = useSettings();
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
console.log(`${EditSet.name}.focus:`, set);
|
||||
let title = 'Create set';
|
||||
if (typeof set.id === 'number') title = 'Edit set';
|
||||
navigation.getParent()?.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
||||
),
|
||||
headerRight: null,
|
||||
title,
|
||||
});
|
||||
}, [navigation, set]),
|
||||
);
|
||||
|
||||
const startTimer = useCallback(
|
||||
async (name: string) => {
|
||||
if (!settings.alarm) return;
|
||||
|
@ -85,8 +65,11 @@ export default function EditSet() {
|
|||
);
|
||||
|
||||
return (
|
||||
<View style={{padding: PADDING, flex: 1}}>
|
||||
<SetForm save={save} set={set} />
|
||||
</View>
|
||||
<>
|
||||
<StackHeader title="Edit set" />
|
||||
<View style={{padding: PADDING, flex: 1}}>
|
||||
<SetForm save={save} set={set} />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
168
EditWorkout.tsx
168
EditWorkout.tsx
|
@ -1,19 +1,15 @@
|
|||
import {
|
||||
RouteProp,
|
||||
useFocusEffect,
|
||||
useNavigation,
|
||||
useRoute,
|
||||
} from '@react-navigation/native';
|
||||
import {RouteProp, useNavigation, useRoute} from '@react-navigation/native';
|
||||
import React, {useCallback, useRef, useState} from 'react';
|
||||
import {ScrollView, TextInput, View} from 'react-native';
|
||||
import DocumentPicker from 'react-native-document-picker';
|
||||
import {Button, Card, IconButton, TouchableRipple} from 'react-native-paper';
|
||||
import {Button, Card, TouchableRipple} from 'react-native-paper';
|
||||
import ConfirmDialog from './ConfirmDialog';
|
||||
import {MARGIN, PADDING} from './constants';
|
||||
import MassiveInput from './MassiveInput';
|
||||
import {useSnackbar} from './MassiveSnack';
|
||||
import {updatePlanWorkouts} from './plan.service';
|
||||
import {addSet, updateManySet, updateSetImage} from './set.service';
|
||||
import StackHeader from './StackHeader';
|
||||
import {useSettings} from './use-settings';
|
||||
import {WorkoutsPageParams} from './WorkoutsPage';
|
||||
|
||||
|
@ -39,19 +35,6 @@ export default function EditWorkout() {
|
|||
const secondsRef = useRef<TextInput>(null);
|
||||
const {settings} = useSettings();
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
navigation.getParent()?.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
||||
),
|
||||
headerRight: null,
|
||||
title: params.value.name || 'New workout',
|
||||
});
|
||||
if (!name) return;
|
||||
}, [navigation, name, params.value.name]),
|
||||
);
|
||||
|
||||
const update = async () => {
|
||||
await updateManySet({
|
||||
oldName: params.value.name,
|
||||
|
@ -118,83 +101,86 @@ export default function EditWorkout() {
|
|||
};
|
||||
|
||||
return (
|
||||
<View style={{padding: PADDING, flex: 1}}>
|
||||
<ScrollView style={{flex: 1}}>
|
||||
<MassiveInput
|
||||
autoFocus
|
||||
label="Name"
|
||||
value={name}
|
||||
onChangeText={handleName}
|
||||
onSubmitEditing={submitName}
|
||||
/>
|
||||
{!!settings.steps && (
|
||||
<>
|
||||
<StackHeader title="Edit workout" />
|
||||
<View style={{padding: PADDING, flex: 1}}>
|
||||
<ScrollView style={{flex: 1}}>
|
||||
<MassiveInput
|
||||
innerRef={stepsRef}
|
||||
selectTextOnFocus={false}
|
||||
value={steps}
|
||||
onChangeText={handleSteps}
|
||||
label="Steps"
|
||||
multiline
|
||||
onSubmitEditing={() => setsRef.current?.focus()}
|
||||
autoFocus
|
||||
label="Name"
|
||||
value={name}
|
||||
onChangeText={handleName}
|
||||
onSubmitEditing={submitName}
|
||||
/>
|
||||
)}
|
||||
{!!settings.showSets && (
|
||||
<MassiveInput
|
||||
innerRef={setsRef}
|
||||
value={sets}
|
||||
onChangeText={setSets}
|
||||
label="Sets per workout"
|
||||
keyboardType="numeric"
|
||||
onSubmitEditing={() => minutesRef.current?.focus()}
|
||||
/>
|
||||
)}
|
||||
{!!settings.alarm && (
|
||||
<>
|
||||
{!!settings.steps && (
|
||||
<MassiveInput
|
||||
innerRef={minutesRef}
|
||||
onSubmitEditing={() => secondsRef.current?.focus()}
|
||||
value={minutes}
|
||||
onChangeText={setMinutes}
|
||||
label="Rest minutes"
|
||||
keyboardType="numeric"
|
||||
innerRef={stepsRef}
|
||||
selectTextOnFocus={false}
|
||||
value={steps}
|
||||
onChangeText={handleSteps}
|
||||
label="Steps"
|
||||
multiline
|
||||
onSubmitEditing={() => setsRef.current?.focus()}
|
||||
/>
|
||||
)}
|
||||
{!!settings.showSets && (
|
||||
<MassiveInput
|
||||
innerRef={secondsRef}
|
||||
value={seconds}
|
||||
onChangeText={setSeconds}
|
||||
label="Rest seconds"
|
||||
innerRef={setsRef}
|
||||
value={sets}
|
||||
onChangeText={setSets}
|
||||
label="Sets per workout"
|
||||
keyboardType="numeric"
|
||||
blurOnSubmit
|
||||
onSubmitEditing={() => minutesRef.current?.focus()}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!!settings.images && uri && (
|
||||
<TouchableRipple
|
||||
style={{marginBottom: MARGIN}}
|
||||
onPress={changeImage}
|
||||
onLongPress={() => setShowRemove(true)}>
|
||||
<Card.Cover source={{uri}} />
|
||||
</TouchableRipple>
|
||||
)}
|
||||
{!!settings.images && !uri && (
|
||||
<Button
|
||||
style={{marginBottom: MARGIN}}
|
||||
onPress={changeImage}
|
||||
icon="add-photo-alternate">
|
||||
Image
|
||||
</Button>
|
||||
)}
|
||||
</ScrollView>
|
||||
<Button disabled={!name} mode="contained" icon="save" onPress={save}>
|
||||
Save
|
||||
</Button>
|
||||
<ConfirmDialog
|
||||
title="Remove image"
|
||||
onOk={handleRemove}
|
||||
show={showRemove}
|
||||
setShow={setShowRemove}>
|
||||
Are you sure you want to remove the image?
|
||||
</ConfirmDialog>
|
||||
</View>
|
||||
)}
|
||||
{!!settings.alarm && (
|
||||
<>
|
||||
<MassiveInput
|
||||
innerRef={minutesRef}
|
||||
onSubmitEditing={() => secondsRef.current?.focus()}
|
||||
value={minutes}
|
||||
onChangeText={setMinutes}
|
||||
label="Rest minutes"
|
||||
keyboardType="numeric"
|
||||
/>
|
||||
<MassiveInput
|
||||
innerRef={secondsRef}
|
||||
value={seconds}
|
||||
onChangeText={setSeconds}
|
||||
label="Rest seconds"
|
||||
keyboardType="numeric"
|
||||
blurOnSubmit
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!!settings.images && uri && (
|
||||
<TouchableRipple
|
||||
style={{marginBottom: MARGIN}}
|
||||
onPress={changeImage}
|
||||
onLongPress={() => setShowRemove(true)}>
|
||||
<Card.Cover source={{uri}} />
|
||||
</TouchableRipple>
|
||||
)}
|
||||
{!!settings.images && !uri && (
|
||||
<Button
|
||||
style={{marginBottom: MARGIN}}
|
||||
onPress={changeImage}
|
||||
icon="add-photo-alternate">
|
||||
Image
|
||||
</Button>
|
||||
)}
|
||||
</ScrollView>
|
||||
<Button disabled={!name} mode="contained" icon="save" onPress={save}>
|
||||
Save
|
||||
</Button>
|
||||
<ConfirmDialog
|
||||
title="Remove image"
|
||||
onOk={handleRemove}
|
||||
show={showRemove}
|
||||
setShow={setShowRemove}>
|
||||
Are you sure you want to remove the image?
|
||||
</ConfirmDialog>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
21
HomePage.tsx
21
HomePage.tsx
|
@ -1,9 +1,5 @@
|
|||
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 EditSet from './EditSet';
|
||||
import {HomePageParams} from './home-page-params';
|
||||
import SetList from './SetList';
|
||||
|
@ -11,26 +7,11 @@ import SetList from './SetList';
|
|||
const Stack = createStackNavigator<HomePageParams>();
|
||||
|
||||
export default function HomePage() {
|
||||
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
|
||||
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{headerShown: false, animationEnabled: false}}>
|
||||
<Stack.Screen name="Sets" component={SetList} />
|
||||
<Stack.Screen
|
||||
name="EditSet"
|
||||
component={EditSet}
|
||||
listeners={{
|
||||
beforeRemove: () => {
|
||||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
||||
),
|
||||
title: 'Home',
|
||||
});
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen name="EditSet" component={EditSet} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
|
10
PlanList.tsx
10
PlanList.tsx
|
@ -6,8 +6,7 @@ import {
|
|||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {FlatList} from 'react-native';
|
||||
import {List} from 'react-native-paper';
|
||||
import DrawerMenu from './DrawerMenu';
|
||||
import Header from './Header';
|
||||
import DrawerHeader from './DrawerHeader';
|
||||
import Page from './Page';
|
||||
import {Plan} from './plan';
|
||||
import {PlanPageParams} from './plan-page-params';
|
||||
|
@ -26,10 +25,7 @@ export default function PlanList() {
|
|||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
refresh();
|
||||
navigation.getParent()?.setOptions({
|
||||
headerRight: () => <DrawerMenu name="Plans" />,
|
||||
});
|
||||
}, [refresh, navigation]),
|
||||
}, [refresh]),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -48,7 +44,7 @@ export default function PlanList() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header name="Plans" />
|
||||
<DrawerHeader name="Plans" />
|
||||
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
||||
{plans?.length === 0 ? (
|
||||
<List.Item
|
||||
|
|
36
PlanPage.tsx
36
PlanPage.tsx
|
@ -1,9 +1,5 @@
|
|||
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 EditPlan from './EditPlan';
|
||||
import {PlanPageParams} from './plan-page-params';
|
||||
import PlanList from './PlanList';
|
||||
|
@ -12,40 +8,12 @@ import StartPlan from './StartPlan';
|
|||
const Stack = createStackNavigator<PlanPageParams>();
|
||||
|
||||
export default function PlanPage() {
|
||||
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
|
||||
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{headerShown: false, animationEnabled: false}}>
|
||||
<Stack.Screen name="PlanList" component={PlanList} />
|
||||
<Stack.Screen
|
||||
name="EditPlan"
|
||||
component={EditPlan}
|
||||
listeners={{
|
||||
beforeRemove: () => {
|
||||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
||||
),
|
||||
title: 'Plans',
|
||||
});
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="StartPlan"
|
||||
component={StartPlan}
|
||||
listeners={{
|
||||
beforeRemove: () => {
|
||||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
||||
),
|
||||
title: 'Plans',
|
||||
});
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen name="EditPlan" component={EditPlan} />
|
||||
<Stack.Screen name="StartPlan" component={StartPlan} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {FlatList} from 'react-native';
|
||||
import {List} from 'react-native-paper';
|
||||
import Header from './Header';
|
||||
import DrawerHeader from './DrawerHeader';
|
||||
import {HomePageParams} from './home-page-params';
|
||||
import Page from './Page';
|
||||
import Set from './set';
|
||||
|
@ -84,7 +84,7 @@ export default function SetList() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header name="Home" />
|
||||
<DrawerHeader name="Home" />
|
||||
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
||||
{sets?.length === 0 ? (
|
||||
<List.Item
|
||||
|
|
|
@ -8,7 +8,7 @@ import {useColor} from './color';
|
|||
import {darkColors, lightColors} from './colors';
|
||||
import ConfirmDialog from './ConfirmDialog';
|
||||
import {MARGIN} from './constants';
|
||||
import Header from './Header';
|
||||
import DrawerHeader from './DrawerHeader';
|
||||
import Input from './input';
|
||||
import {useSnackbar} from './MassiveSnack';
|
||||
import Page from './Page';
|
||||
|
@ -168,7 +168,7 @@ export default function SettingsPage() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header name="Settings" />
|
||||
<DrawerHeader name="Settings" />
|
||||
<Page search={search} setSearch={setSearch}>
|
||||
<ScrollView style={{marginTop: MARGIN}}>
|
||||
{switches
|
||||
|
|
30
StackHeader.tsx
Normal file
30
StackHeader.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
import {useNavigation} from '@react-navigation/native';
|
||||
import React from 'react';
|
||||
import Share from 'react-native-share';
|
||||
import {FileSystem} from 'react-native-file-access';
|
||||
import {Appbar, IconButton} from 'react-native-paper';
|
||||
import {captureScreen} from 'react-native-view-shot';
|
||||
|
||||
export default function StackHeader({title}: {title: string}) {
|
||||
const navigation = useNavigation();
|
||||
|
||||
return (
|
||||
<Appbar.Header>
|
||||
<IconButton icon="arrow-back" onPress={navigation.goBack} />
|
||||
<Appbar.Content title={title} />
|
||||
<IconButton
|
||||
onPress={() =>
|
||||
captureScreen().then(async uri => {
|
||||
const base64 = await FileSystem.readFile(uri, 'base64');
|
||||
const url = `data:image/jpeg;base64,${base64}`;
|
||||
Share.open({
|
||||
type: 'image/jpeg',
|
||||
url,
|
||||
});
|
||||
})
|
||||
}
|
||||
icon="share"
|
||||
/>
|
||||
</Appbar.Header>
|
||||
);
|
||||
}
|
134
StartPlan.tsx
134
StartPlan.tsx
|
@ -1,13 +1,8 @@
|
|||
import {
|
||||
RouteProp,
|
||||
useFocusEffect,
|
||||
useNavigation,
|
||||
useRoute,
|
||||
} from '@react-navigation/native';
|
||||
import {RouteProp, useFocusEffect, useRoute} from '@react-navigation/native';
|
||||
import React, {useCallback, useMemo, useRef, useState} from 'react';
|
||||
import {NativeModules, TextInput, View} from 'react-native';
|
||||
import {FlatList} from 'react-native-gesture-handler';
|
||||
import {Button, IconButton, List, RadioButton} from 'react-native-paper';
|
||||
import {Button, List, RadioButton} from 'react-native-paper';
|
||||
import {getBestSet} from './best.service';
|
||||
import {useColor} from './color';
|
||||
import {PADDING} from './constants';
|
||||
|
@ -18,6 +13,7 @@ import {PlanPageParams} from './plan-page-params';
|
|||
import Set from './set';
|
||||
import {addSet, countManyToday, getDistinctSets} from './set.service';
|
||||
import SetForm from './SetForm';
|
||||
import StackHeader from './StackHeader';
|
||||
import {useSettings} from './use-settings';
|
||||
|
||||
export default function StartPlan() {
|
||||
|
@ -38,7 +34,6 @@ export default function StartPlan() {
|
|||
const weightRef = useRef<TextInput>(null);
|
||||
const repsRef = useRef<TextInput>(null);
|
||||
const unitRef = useRef<TextInput>(null);
|
||||
const navigation = useNavigation();
|
||||
const workouts = useMemo(() => params.plan.workouts.split(','), [params]);
|
||||
const {color} = useColor();
|
||||
|
||||
|
@ -49,13 +44,6 @@ export default function StartPlan() {
|
|||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
navigation.getParent()?.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
||||
),
|
||||
headerRight: null,
|
||||
title: params.plan.days.replace(/,/g, ', '),
|
||||
});
|
||||
countManyToday().then(newCounts => {
|
||||
setCounts(newCounts);
|
||||
console.log(`${StartPlan.name}.focus:`, {newCounts});
|
||||
|
@ -66,7 +54,7 @@ export default function StartPlan() {
|
|||
console.log(`${StartPlan.name}.focus:`, {newDistinct});
|
||||
},
|
||||
);
|
||||
}, [navigation, params]),
|
||||
}, [params]),
|
||||
);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
|
@ -129,70 +117,74 @@ export default function StartPlan() {
|
|||
if (!distinctSets) return;
|
||||
const distinct = distinctSets.find(d => d.name === countName);
|
||||
console.log(`${StartPlan.name}:`, {distinct});
|
||||
if (settings.showSets) return `${count?.total || 0} / ${distinct?.sets}`;
|
||||
if (settings.showSets)
|
||||
return `${count?.total || 0} / ${distinct?.sets || 3}`;
|
||||
return count?.total || '0';
|
||||
},
|
||||
[counts, distinctSets, settings.showSets],
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={{padding: PADDING, flex: 1, flexDirection: 'column'}}>
|
||||
<View style={{flex: 1}}>
|
||||
<MassiveInput
|
||||
label="Reps"
|
||||
keyboardType="numeric"
|
||||
value={reps}
|
||||
onChangeText={setReps}
|
||||
onSubmitEditing={() => weightRef.current?.focus()}
|
||||
selection={selection}
|
||||
onSelectionChange={e => setSelection(e.nativeEvent.selection)}
|
||||
innerRef={repsRef}
|
||||
/>
|
||||
<MassiveInput
|
||||
label="Weight"
|
||||
keyboardType="numeric"
|
||||
value={weight}
|
||||
onChangeText={setWeight}
|
||||
onSubmitEditing={handleSubmit}
|
||||
innerRef={weightRef}
|
||||
blurOnSubmit
|
||||
/>
|
||||
{!!settings.showUnit && (
|
||||
<>
|
||||
<StackHeader title={params.plan.days.replace(/,/g, ', ')} />
|
||||
<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)}
|
||||
innerRef={repsRef}
|
||||
/>
|
||||
)}
|
||||
{counts && distinctSets && (
|
||||
<FlatList
|
||||
data={workouts}
|
||||
renderItem={({item, index}) => (
|
||||
<List.Item
|
||||
title={item}
|
||||
description={getDescription(item)}
|
||||
onPress={() => select(index)}
|
||||
left={() => (
|
||||
<View
|
||||
style={{alignItems: 'center', justifyContent: 'center'}}>
|
||||
<RadioButton
|
||||
onPress={() => select(index)}
|
||||
value={index.toString()}
|
||||
status={selected === index ? 'checked' : 'unchecked'}
|
||||
color={color}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<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}
|
||||
/>
|
||||
)}
|
||||
{counts && distinctSets && (
|
||||
<FlatList
|
||||
data={workouts}
|
||||
renderItem={({item, index}) => (
|
||||
<List.Item
|
||||
title={item}
|
||||
description={getDescription(item)}
|
||||
onPress={() => select(index)}
|
||||
left={() => (
|
||||
<View
|
||||
style={{alignItems: 'center', justifyContent: 'center'}}>
|
||||
<RadioButton
|
||||
onPress={() => select(index)}
|
||||
value={index.toString()}
|
||||
status={selected === index ? 'checked' : 'unchecked'}
|
||||
color={color}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<Button mode="contained" icon="save" onPress={handleSubmit}>
|
||||
Save
|
||||
</Button>
|
||||
</View>
|
||||
<Button mode="contained" icon="save" onPress={handleSubmit}>
|
||||
Save
|
||||
</Button>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
123
ViewBest.tsx
123
ViewBest.tsx
|
@ -1,16 +1,7 @@
|
|||
import {Picker} from '@react-native-picker/picker';
|
||||
import {
|
||||
RouteProp,
|
||||
useFocusEffect,
|
||||
useNavigation,
|
||||
useRoute,
|
||||
} from '@react-navigation/native';
|
||||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {RouteProp, useRoute} from '@react-navigation/native';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {View} from 'react-native';
|
||||
import {FileSystem} from 'react-native-file-access';
|
||||
import {IconButton} from 'react-native-paper';
|
||||
import Share from 'react-native-share';
|
||||
import {captureScreen} from 'react-native-view-shot';
|
||||
import {getOneRepMax, getVolumes, getWeightsBy} from './best.service';
|
||||
import {BestPageParams} from './BestPage';
|
||||
import Chart from './Chart';
|
||||
|
@ -18,6 +9,7 @@ import {PADDING} from './constants';
|
|||
import {Metrics} from './metrics';
|
||||
import {Periods} from './periods';
|
||||
import Set from './set';
|
||||
import StackHeader from './StackHeader';
|
||||
import {formatMonth} from './time';
|
||||
import useDark from './use-dark';
|
||||
import Volume from './volume';
|
||||
|
@ -29,34 +21,6 @@ export default function ViewBest() {
|
|||
const [volumes, setVolumes] = useState<Volume[]>([]);
|
||||
const [metric, setMetric] = useState(Metrics.Weight);
|
||||
const [period, setPeriod] = useState(Periods.Monthly);
|
||||
const navigation = useNavigation();
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
console.log(`${ViewBest.name}.useFocusEffect`);
|
||||
navigation.getParent()?.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
|
||||
),
|
||||
headerRight: () => (
|
||||
<IconButton
|
||||
onPress={() =>
|
||||
captureScreen().then(async uri => {
|
||||
const base64 = await FileSystem.readFile(uri, 'base64');
|
||||
const url = `data:image/jpeg;base64,${base64}`;
|
||||
Share.open({
|
||||
type: 'image/jpeg',
|
||||
url,
|
||||
});
|
||||
})
|
||||
}
|
||||
icon="share"
|
||||
/>
|
||||
),
|
||||
title: params.best.name,
|
||||
});
|
||||
}, [navigation, params.best]),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(`${ViewBest.name}.useEffect`, {metric});
|
||||
|
@ -74,44 +38,47 @@ export default function ViewBest() {
|
|||
}, [params.best.name, metric, period]);
|
||||
|
||||
return (
|
||||
<View style={{padding: PADDING}}>
|
||||
<Picker
|
||||
style={{color: dark ? 'white' : 'black'}}
|
||||
dropdownIconColor={dark ? 'white' : 'black'}
|
||||
selectedValue={metric}
|
||||
onValueChange={value => setMetric(value)}>
|
||||
<Picker.Item value={Metrics.Volume} label={Metrics.Volume} />
|
||||
<Picker.Item value={Metrics.Weight} label={Metrics.Weight} />
|
||||
<Picker.Item value={Metrics.OneRepMax} label={Metrics.OneRepMax} />
|
||||
</Picker>
|
||||
<Picker
|
||||
style={{color: dark ? 'white' : 'black'}}
|
||||
dropdownIconColor={dark ? 'white' : 'black'}
|
||||
selectedValue={period}
|
||||
onValueChange={value => setPeriod(value)}>
|
||||
<Picker.Item value={Periods.Weekly} label={Periods.Weekly} />
|
||||
<Picker.Item value={Periods.Monthly} label={Periods.Monthly} />
|
||||
<Picker.Item value={Periods.Yearly} label={Periods.Yearly} />
|
||||
</Picker>
|
||||
{metric === Metrics.Volume ? (
|
||||
<Chart
|
||||
yData={volumes.map(v => v.value)}
|
||||
yFormat={(value: number) =>
|
||||
`${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}${
|
||||
volumes[0].unit
|
||||
}`
|
||||
}
|
||||
xData={weights}
|
||||
xFormat={(_value, index) => formatMonth(weights[index].created!)}
|
||||
/>
|
||||
) : (
|
||||
<Chart
|
||||
yData={weights.map(set => set.weight)}
|
||||
yFormat={value => `${value}${weights[0].unit}`}
|
||||
xData={weights}
|
||||
xFormat={(_value, index) => formatMonth(weights[index].created!)}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<>
|
||||
<StackHeader title={params.best.name} />
|
||||
<View style={{padding: PADDING}}>
|
||||
<Picker
|
||||
style={{color: dark ? 'white' : 'black'}}
|
||||
dropdownIconColor={dark ? 'white' : 'black'}
|
||||
selectedValue={metric}
|
||||
onValueChange={value => setMetric(value)}>
|
||||
<Picker.Item value={Metrics.Volume} label={Metrics.Volume} />
|
||||
<Picker.Item value={Metrics.Weight} label={Metrics.Weight} />
|
||||
<Picker.Item value={Metrics.OneRepMax} label={Metrics.OneRepMax} />
|
||||
</Picker>
|
||||
<Picker
|
||||
style={{color: dark ? 'white' : 'black'}}
|
||||
dropdownIconColor={dark ? 'white' : 'black'}
|
||||
selectedValue={period}
|
||||
onValueChange={value => setPeriod(value)}>
|
||||
<Picker.Item value={Periods.Weekly} label={Periods.Weekly} />
|
||||
<Picker.Item value={Periods.Monthly} label={Periods.Monthly} />
|
||||
<Picker.Item value={Periods.Yearly} label={Periods.Yearly} />
|
||||
</Picker>
|
||||
{metric === Metrics.Volume ? (
|
||||
<Chart
|
||||
yData={volumes.map(v => v.value)}
|
||||
yFormat={(value: number) =>
|
||||
`${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}${
|
||||
volumes[0].unit
|
||||
}`
|
||||
}
|
||||
xData={weights}
|
||||
xFormat={(_value, index) => formatMonth(weights[index].created!)}
|
||||
/>
|
||||
) : (
|
||||
<Chart
|
||||
yData={weights.map(set => set.weight)}
|
||||
yFormat={value => `${value}${weights[0].unit}`}
|
||||
xData={weights}
|
||||
xFormat={(_value, index) => formatMonth(weights[index].created!)}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {FlatList} from 'react-native';
|
||||
import {List} from 'react-native-paper';
|
||||
import Header from './Header';
|
||||
import DrawerHeader from './DrawerHeader';
|
||||
import Page from './Page';
|
||||
import Set from './set';
|
||||
import {getDistinctSets} from './set.service';
|
||||
|
@ -81,7 +81,7 @@ export default function WorkoutList() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header name="Workouts" />
|
||||
<DrawerHeader name="Workouts" />
|
||||
<Page onAdd={onAdd} search={search} setSearch={setSearch}>
|
||||
{workouts?.length === 0 ? (
|
||||
<List.Item
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
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 EditWorkout from './EditWorkout';
|
||||
import Set from './set';
|
||||
import WorkoutList from './WorkoutList';
|
||||
|
@ -18,26 +14,11 @@ export type WorkoutsPageParams = {
|
|||
const Stack = createStackNavigator<WorkoutsPageParams>();
|
||||
|
||||
export default function WorkoutsPage() {
|
||||
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>();
|
||||
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{headerShown: false, animationEnabled: false}}>
|
||||
<Stack.Screen name="WorkoutList" component={WorkoutList} />
|
||||
<Stack.Screen
|
||||
name="EditWorkout"
|
||||
component={EditWorkout}
|
||||
listeners={{
|
||||
beforeRemove: () => {
|
||||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<IconButton icon="menu" onPress={navigation.openDrawer} />
|
||||
),
|
||||
title: 'Workouts',
|
||||
});
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen name="EditWorkout" component={EditWorkout} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user