├── 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 | ![GitHub repo size](https://img.shields.io/github/repo-size/geeky-prashant/react-native-fitness-app) 4 | ![GitHub stars](https://img.shields.io/github/stars/geeky-prashant/react-native-fitness-app?style=social) 5 | ![GitHub forks](https://img.shields.io/github/forks/geeky-prashant/react-native-fitness-app?style=social) 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 | ![React Native Fitness App Demo](./readme-images/React-Native-Fitness-App.png "Desktop Demo") 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 | ]; --------------------------------------------------------------------------------