├── assets
├── icon.png
├── favicon.png
├── splash.png
└── adaptive-icon.png
├── babel.config.js
├── readme-images
└── React-Native-Fitness-App.png
├── .gitignore
├── App.js
├── package.json
├── Context.js
├── app.json
├── StackNavigator.js
├── components
└── FitnessCards.js
├── screens
├── RestScreen.js
├── HomeScreen.js
├── WorkoutScreen.js
└── FitScreen.js
├── README.md
└── data
└── fitness.js
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prashantbuilds/react-native-fitness-app/HEAD/assets/icon.png
--------------------------------------------------------------------------------
/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prashantbuilds/react-native-fitness-app/HEAD/assets/favicon.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prashantbuilds/react-native-fitness-app/HEAD/assets/splash.png
--------------------------------------------------------------------------------
/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prashantbuilds/react-native-fitness-app/HEAD/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/readme-images/React-Native-Fitness-App.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prashantbuilds/react-native-fitness-app/HEAD/readme-images/React-Native-Fitness-App.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .expo/
3 | dist/
4 | npm-debug.*
5 | *.jks
6 | *.p8
7 | *.p12
8 | *.key
9 | *.mobileprovision
10 | *.orig.*
11 | web-build/
12 |
13 | # macOS
14 | .DS_Store
15 |
16 | # Temporary files created by Metro to check the health of the file watcher
17 | .metro-health-check*
18 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import { FitnessContext } from './Context';
2 | import StackNavigator from './StackNavigator';
3 | import { StatusBar } from 'expo-status-bar';
4 |
5 | export default function App() {
6 | return (
7 | <>
8 |
9 |
10 |
11 |
12 | >
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-fitness-app",
3 | "version": "1.0.0",
4 | "main": "node_modules/expo/AppEntry.js",
5 | "scripts": {
6 | "start": "expo start",
7 | "android": "expo start --android",
8 | "ios": "expo start --ios",
9 | "web": "expo start --web"
10 | },
11 | "dependencies": {
12 | "@react-navigation/native": "^6.1.7",
13 | "@react-navigation/native-stack": "^6.9.13",
14 | "expo": "~48.0.18",
15 | "expo-status-bar": "~1.4.4",
16 | "react": "18.2.0",
17 | "react-native": "0.71.8",
18 | "react-native-safe-area-context": "4.5.0",
19 | "react-native-screens": "~3.20.0"
20 | },
21 | "devDependencies": {
22 | "@babel/core": "^7.20.0"
23 | },
24 | "private": true
25 | }
26 |
--------------------------------------------------------------------------------
/Context.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useState } from "react";
2 |
3 | const FitnessItems = createContext();
4 |
5 | const FitnessContext = ({ children }) => {
6 | const [completed, setCompleted] = useState([]);
7 | const [workout, setWorkout] = useState(0);
8 | const [calories, setCalories] = useState(0);
9 | const [minutes, setMinutes] = useState(0);
10 | return (
11 |
23 | {children}
24 |
25 | );
26 | };
27 |
28 | export { FitnessContext, FitnessItems }
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "react-native-fitness-app",
4 | "slug": "react-native-fitness-app",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "userInterfaceStyle": "light",
9 | "splash": {
10 | "image": "./assets/splash.png",
11 | "resizeMode": "contain",
12 | "backgroundColor": "#ffffff"
13 | },
14 | "assetBundlePatterns": [
15 | "**/*"
16 | ],
17 | "ios": {
18 | "supportsTablet": true
19 | },
20 | "android": {
21 | "adaptiveIcon": {
22 | "foregroundImage": "./assets/adaptive-icon.png",
23 | "backgroundColor": "#ffffff"
24 | }
25 | },
26 | "web": {
27 | "favicon": "./assets/favicon.png"
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/StackNavigator.js:
--------------------------------------------------------------------------------
1 | import { NavigationContainer } from '@react-navigation/native';
2 | import { createNativeStackNavigator } from '@react-navigation/native-stack';
3 | import HomeScreen from './screens/HomeScreen';
4 | import WorkoutScreen from './screens/WorkoutScreen';
5 | import FitScreen from './screens/FitScreen';
6 | import RestScreen from './screens/RestScreen';
7 |
8 | const StackNavigator = () => {
9 | const Stack = createNativeStackNavigator();
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 |
22 | export default StackNavigator
--------------------------------------------------------------------------------
/components/FitnessCards.js:
--------------------------------------------------------------------------------
1 | import { Image, Text, View, TouchableOpacity } from 'react-native'
2 | import fitness from '../data/fitness'
3 | import { MaterialCommunityIcons } from '@expo/vector-icons';
4 | import { useNavigation } from '@react-navigation/native';
5 |
6 | const FitnessCards = () => {
7 | const FitnessData = fitness;
8 | const navigation = useNavigation();
9 |
10 | return (
11 |
12 | {
13 | FitnessData.map((item, id) => (
14 | navigation.navigate("Workout", {
15 | image: item.image,
16 | exercises: item.exercises,
17 | id: item.id
18 | })} style={{alignItems: 'center', justifyContent: "center", marginTop: 10, marginBottom: 10}} key={id}>
19 |
20 | {item.name}
21 |
22 |
23 | ))
24 | }
25 |
26 | )
27 | }
28 |
29 | export default FitnessCards
--------------------------------------------------------------------------------
/screens/RestScreen.js:
--------------------------------------------------------------------------------
1 | import { useNavigation } from '@react-navigation/native';
2 | import { useEffect, useState } from 'react';
3 | import { Image, Text } from 'react-native'
4 | import { SafeAreaView } from 'react-native-safe-area-context'
5 | SafeAreaView;
6 | import { MaterialIcons } from '@expo/vector-icons';
7 |
8 | const RestScreen = () => {
9 | const navigation = useNavigation();
10 | let timer = 0;
11 | const [timeLeft, setTimeLeft] = useState(2);
12 |
13 | const startTime = () => {
14 | setTimeout(() => {
15 | if (timeLeft <= 0) {
16 | navigation.goBack();
17 | clearTimeout(timer);
18 | }
19 | setTimeLeft(timeLeft - 1)
20 | }, 1000)
21 | }
22 |
23 | useEffect(() => {
24 | startTime();
25 |
26 | //Cleanup Function
27 | return() => clearTimeout(timer);
28 | },)
29 |
30 | return (
31 |
32 |
39 |
40 | TAKE A BREAK!
41 |
42 | {timeLeft}
43 |
44 | )
45 | }
46 |
47 | export default RestScreen
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 
4 | 
5 | 
6 |
7 |
8 |
9 |
React Native Fitness App
10 |
11 | In this project, I have created a Fitness App, The project is built using Expo, React Native, and React Native Navigation.
12 |
13 |
14 |
15 | ### Demo Screenshot
16 |
17 | 
18 |
19 | ## Get Started
20 |
21 | install dev dependencies
22 |
23 | ### `npm install`
24 |
25 | ## Then
26 |
27 | Run The App
28 |
29 | ### `npm start`
30 |
31 | Runs your app in development mode.
32 |
33 | Open it in the [Expo app](https://expo.io) on your phone to view it. It will reload if you save edits to your files, and you will see build errors and logs in the terminal.
34 |
35 | #### `npm run ios`
36 |
37 | Like `npm start` / `yarn start`, but also attempts to open your app in the iOS Simulator if you're on a Mac and have it installed.
38 |
39 | #### `npm run android`
40 |
41 | Like `npm start` / `yarn start`, but also attempts to open your app on a connected Android device or emulator. Requires an installation of Android build tools (see [React Native docs](https://facebook.github.io/react-native/docs/getting-started.html) for detailed setup).
42 |
43 | ### Contact
44 |
45 | If you want to contact me you can reach me at [LinkedIn](https://www.linkedin.com/in/geekyprashant/).
46 |
47 | ### License
48 |
49 | This project is **free to use** and does not contain any license.
50 |
--------------------------------------------------------------------------------
/screens/HomeScreen.js:
--------------------------------------------------------------------------------
1 | import { Text, View, StyleSheet, ScrollView, TouchableOpacity } from 'react-native';
2 | import FitnessCards from '../components/FitnessCards';
3 | import { Ionicons } from '@expo/vector-icons';
4 | import { useContext, useState } from 'react';
5 | import { FitnessItems } from '../Context';
6 |
7 | const HomeScreen = () => {
8 | const [showIcon, setShowIcon] = useState(false);
9 | const { calories, minutes, workout, } = useContext(FitnessItems);
10 |
11 | return (
12 |
14 |
15 |
16 | SIX PACK IN 30 DAYS
17 |
18 | {/* Dark Mode */}
19 | setShowIcon(!showIcon)}>
20 | {showIcon ? : }
21 |
22 |
23 |
24 | {/* Cards Row */}
25 |
26 |
27 | {/* First Card */}
28 |
29 | {calories.toFixed(2)}
30 | KCAL
31 |
32 |
33 | {/* Second Card */}
34 |
35 | {workout}
36 | WORKOUTS
37 |
38 |
39 | {/* Third Card */}
40 |
41 | {minutes}
42 | MINUTES
43 |
44 |
45 |
46 | {/* Fitness Cards */}
47 |
48 |
49 | )
50 | }
51 |
52 | export default HomeScreen
53 |
54 | const styles = StyleSheet.create({
55 | shadowCards: {
56 | backgroundColor: "#ffffff",
57 | width: "32%",
58 | height: 80,
59 | borderRadius: 10,
60 | alignItems: "center",
61 | justifyContent: "center",
62 | shadowColor: "#000",
63 | shadowOffset: { width: 0, height: 2 },
64 | shadowOpacity: 0.25,
65 | shadowRadius: 3.84,
66 | elevation: 5
67 | },
68 | });
--------------------------------------------------------------------------------
/screens/WorkoutScreen.js:
--------------------------------------------------------------------------------
1 | import { useNavigation, useRoute } from '@react-navigation/native'
2 | import { Image, ScrollView, TouchableOpacity, View, Text } from 'react-native'
3 | import { Ionicons } from '@expo/vector-icons';
4 | import { MaterialCommunityIcons } from '@expo/vector-icons';
5 | import { useContext } from 'react';
6 | import { AntDesign } from '@expo/vector-icons';
7 | import { FitnessItems } from '../Context';
8 |
9 | const WorkoutScreen = () => {
10 | const route = useRoute();
11 | const navigation = useNavigation();
12 | const { completed, setCompleted } = useContext(FitnessItems);
13 |
14 | return (
15 | <>
16 |
20 |
24 |
25 | navigation.goBack()}
27 | style={{ position: 'absolute', top: 30, left: 20, backgroundColor: "white", borderRadius: 8, padding: 3 }}
28 | name="arrow-back-outline"
29 | size={24}
30 | color="black"
31 | />
32 |
33 | {
34 | route.params.exercises.map((item, index) => (
35 |
36 |
37 |
38 |
39 |
40 | {item.name}
41 | {item.sets}
42 |
43 |
44 |
45 | {
46 | completed.includes(item?.name) ? () : null
47 | }
48 |
49 | ))
50 | }
51 |
52 |
53 | {
54 | navigation.navigate("Fit", { exercises: route.params.exercises })
55 | setCompleted([]);
56 | }} style={{ backgroundColor: "#198f51", padding: 12, marginHorizontal: 15, marginVertical: 20, borderRadius: 50}}>
57 | START
58 |
59 | >
60 | )
61 | }
62 |
63 | export default WorkoutScreen
--------------------------------------------------------------------------------
/screens/FitScreen.js:
--------------------------------------------------------------------------------
1 | import { useNavigation, useRoute } from '@react-navigation/native'
2 | import { useState } from 'react';
3 | import { Image, Text, TouchableOpacity, View } from 'react-native'
4 | import { SafeAreaView } from 'react-native-safe-area-context'
5 | import { Ionicons } from '@expo/vector-icons';
6 | import { Octicons } from '@expo/vector-icons';
7 | import { useContext } from 'react';
8 | import { FitnessItems } from '../Context';
9 |
10 | const FitScreen = () => {
11 | const route = useRoute();
12 | const navigation = useNavigation();
13 | const [index, setIndex] = useState(0);
14 | const exercise = route.params.exercises;
15 | const current = exercise[index];
16 | const { completed, setCompleted, calories, setCalories, minutes, setMinutes, workout, setWorkout, } = useContext(FitnessItems);
17 |
18 | return (
19 |
20 |
21 |
22 | {current?.name}
23 |
24 | x{current?.sets}
25 |
26 | {/* Done Button */}
27 | {
28 | index + 1 >= exercise.length ? (
29 | {
30 | navigation.navigate("Home");
31 | setCompleted([...completed, current?.name]);
32 | setWorkout(workout + 1);
33 | setMinutes(minutes + 2.5);
34 | setCalories(calories + 6.3);
35 | setTimeout(() => {
36 | setIndex(index + 1);
37 | }, 2000);
38 | }} style={{ backgroundColor: "#198f51", marginLeft: "auto", marginRight: "auto", marginTop: 50, borderRadius: 30, padding: 10, width: "90%", }}>
39 | DONE
40 |
41 | ) : (
42 | {
43 | navigation.navigate("Rest");
44 | setCompleted([...completed, current?.name]);
45 | setWorkout(workout + 1);
46 | setMinutes(minutes + 2.5);
47 | setCalories(calories + 6.3);
48 | setTimeout(() => {
49 | setIndex(index + 1);
50 | }, 2000);
51 | }} style={{ backgroundColor: "#198f51", marginLeft: "auto", marginRight: "auto", marginTop: 50, borderRadius: 30, padding: 10, width: "90%", }}>
52 | DONE
53 |
54 | )
55 | }
56 |
57 | {/* Previous Button */}
58 |
59 | {navigation.navigate("Rest"); setTimeout(() => {
60 | setIndex(index - 1)
61 | }, 2000)}} style={{ borderRadius: 30, padding: 10, width: "42%" }}>
62 | PREV
63 |
64 |
65 | {/* Skip Button */}
66 | {
67 | index + 1 >= exercise.length ? (
68 | {
69 | navigation.navigate("Home");
70 | }} style={{ borderRadius: 30, padding: 10, width: "42%" }}>
71 | SKIP
72 |
73 | ) : (
74 | {
75 | navigation.navigate("Rest");
76 |
77 | setTimeout(() => {
78 | setIndex(index + 1);
79 | }, 2000);
80 | }} style={{ borderRadius: 30, padding: 10, width: "42%" }}>
81 | SKIP
82 |
83 | )
84 | }
85 |
86 |
87 | )
88 | }
89 |
90 | export default FitScreen
--------------------------------------------------------------------------------
/data/fitness.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | id: "0",
4 | image:
5 | "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRrEM-6gDUO7g1cdrNhBaqk_0nwxy6ILlIqsQ&usqp=CAU",
6 | name: "FULL BODY",
7 | description: "7x4 CHALLENGE",
8 | exercises: [
9 | {
10 | id: "10",
11 | image:
12 | "https://sworkit.com/wp-content/uploads/2020/06/sworkit-jumping-jack.gif",
13 | name: "JUMPING JACKS",
14 | sets: 12,
15 | },
16 | {
17 | id: "11",
18 | image: "https://media.self.com/photos/583c641ca8746f6e65a60c7e/master/w_1600%2Cc_limit/DIAMOND_PUSHUP_MOTIFIED.gif",
19 | name: "INCLINED PUSH-UPS",
20 | sets: 10,
21 | },
22 | {
23 | id: "12",
24 | image: "https://cdn.prod.openfit.com/uploads/2020/03/10162714/wide-arm-push-up.gif",
25 | name: "WIDE ARM PUSH-UPS",
26 | sets: 12,
27 | },
28 | {
29 | id: "13",
30 | image: "https://www.yogajournal.com/wp-content/uploads/2021/12/Cobra.gif?width=730",
31 | name: "COBRA STRETCH",
32 | sets: 10,
33 | },
34 | {
35 | id: "14",
36 | image: "https://www.vissco.com/wp-content/uploads/animation/sub/double-knee-to-chest-stretch.gif",
37 | name: "CHEST STRETCH",
38 | sets: 10,
39 | }
40 | ],
41 | },
42 | {
43 | id: "1",
44 | image:
45 | "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRonpSjpGQ2-JD8-XFFD7LYsVSFCOiASj0wSOq1qxNvxGFHe7W6AU1LRAeJ2fOIzYICMGc&usqp=CAU",
46 | name: "ABS BEGINNER",
47 | description: "7x4 CHALLENGE",
48 | exercises: [
49 | {
50 | id: "90",
51 | image: "https://media1.popsugar-assets.com/files/thumbor/f2sbzQY1h1zqiGEV9Mhr1IAcFMU/fit-in/2048xorig/filters:format_auto-!!-:strip_icc-!!-/2017/03/13/796/n/1922729/19cf2a4428446429_EXAMPLE.crossjacks.gif",
52 | name: "JUMPING JACKS",
53 | sets: 12,
54 | },
55 | {
56 | id: "91",
57 | image: "https://i.pinimg.com/originals/18/27/be/1827be178c019b1dc6f8a8d8b4a7b0b8.gif",
58 | name: "MOUNTAIN CLIMBERS",
59 | sets: 10,
60 | },
61 | {
62 | id: "92",
63 | image: "https://i.pinimg.com/originals/f4/b0/f3/f4b0f3093fcadd64968e4c46d1767b50.gif",
64 | name: "HEEL TOUCH",
65 | sets: 20,
66 | },
67 | {
68 | id: "94",
69 | image: "https://i.pinimg.com/originals/cf/b5/67/cfb5677a755fe7288b608a4fec6f09a0.gif",
70 | name: "PLANK",
71 | sets: 10,
72 | },
73 | {
74 | id: "95",
75 | image: "https://www.gymguider.com/wp-content/uploads/2017/10/straight-leg-raise.gif",
76 | name: "LEG RAISES",
77 | sets: 14,
78 | }
79 | ]
80 | },
81 | {
82 | id: "2",
83 | image:
84 | "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT1NHvoutGn-Vr_uwVbOOtezhENvx9jhV6pfQ&usqp=CAU",
85 | name: "ARM BEGINNER",
86 | description: "7x4 CHALLENGE",
87 | exercises: [
88 | {
89 | id: "70",
90 | image: "https://post.healthline.com/wp-content/uploads/2020/06/400x400_How_to_do_Zac_Efrons_Baywatch_Workout_Dumbbell_Lateral_Raise.gif",
91 | name: "ARM RAISES",
92 | sets: 8,
93 | },
94 | {
95 | id: "71",
96 | image: "https://thumbs.gfycat.com/CompleteZigzagFossa-max-1mb.gif",
97 | name: "TRICEP DIPS",
98 | sets: 10,
99 | },
100 | {
101 | id: "72",
102 | image: "https://thumbs.gfycat.com/MisguidedAridAlaskanmalamute-max-1mb.gif",
103 | name: "DIAMOND_PUSHUP",
104 | sets: 10,
105 | },
106 | {
107 | id: "73",
108 | image: "https://c.tenor.com/gI-8qCUEko8AAAAC/pushup.gif",
109 | name: "PUSH-UPS",
110 | sets: 10,
111 | },
112 | {
113 | id: "74",
114 | image: "https://i.pinimg.com/originals/8c/53/27/8c532774e4e1c524576bf1fb829ad895.gif",
115 | name: "DUMBELL CURL",
116 | sets: 11,
117 |
118 | },
119 | {
120 | id: "75",
121 | image: "https://www.vissco.com/wp-content/uploads/animation/sub/inch-worm.gif",
122 | name: "INCH WORMS",
123 | sets: 5,
124 | },
125 | {
126 | id: "76",
127 | image: "https://c.tenor.com/jqwaOmRs-7gAAAAC/tricep-kick-back-tricep.gif",
128 | name: "TRICEP LIFT",
129 | sets: 8,
130 | }
131 | ]
132 | },
133 | {
134 | id: "3",
135 | image:
136 | "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSqCT0tewpNAZ6R9JUoMDHIHGnpE44U2Fl1Zw&usqp=CAU",
137 | name: "CHEST BEGINNER",
138 | description: "7x4 CHALLENGE",
139 | exercises: [
140 | {
141 | id: "20",
142 | image: "https://i.pinimg.com/originals/ff/cf/40/ffcf40474f0758dfedebc823f5532aa1.gif",
143 | name: "DECLINE PUSH-UPS",
144 | sets: 9,
145 | },
146 | {
147 | id: "21",
148 | image: "https://image.2bstronger.com/article/fitness/the-14-toughest-do-anywhere-workout-moves-56348/1006.gif",
149 | name: "HINDU PUSH-UPS",
150 | sets: 10,
151 | },
152 | {
153 | id: "22",
154 | image: "https://thumbs.gfycat.com/TheseRigidBorer-size_restricted.gif",
155 | name: "SHOULDER STRETCH",
156 | sets: 5,
157 | },
158 | {
159 | id: "23",
160 | image: "https://thumbs.gfycat.com/AlertAfraidAldabratortoise-max-1mb.gif",
161 | name: "COBRA STRETCH",
162 | sets: 4,
163 | },
164 | {
165 | id: "25",
166 | image: "https://media4.popsugar-assets.com/files/thumbor/BaWEAcCjtJEjiwf3PqJHnZ_S23A/fit-in/2048xorig/filters:format_auto-!!-:strip_icc-!!-/2016/08/10/766/n/1922729/1eae2dcf3d395379_PushUpTwist.gif",
167 | name: "PUSH-UP & ROTATION",
168 | sets: 12,
169 | },
170 | {
171 | id: "26",
172 | image: "https://media3.popsugar-assets.com/files/thumbor/0Xiqpo7pxrKz5CKcRl7XYrKegko/fit-in/1024x1024/filters:format_auto-!!-:strip_icc-!!-/2014/02/27/847/n/1922729/1baf9ec0f5ce4ea9_burpee.3.gif",
173 | name: "BURPEES",
174 | sets: 10
175 | }
176 | ]
177 | }
178 | ];
--------------------------------------------------------------------------------