├── .watchmanconfig ├── .vscode └── settings.json ├── .eslintrc.js ├── assets ├── icon.png ├── select.png ├── splash.png └── countdown.png ├── .gitignore ├── babel.config.js ├── README.md ├── package.json ├── app.json └── App └── index.js /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: "handlebarlabs" 3 | }; 4 | -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanBinu007/react-native-timer-app/HEAD/assets/icon.png -------------------------------------------------------------------------------- /assets/select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanBinu007/react-native-timer-app/HEAD/assets/select.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanBinu007/react-native-timer-app/HEAD/assets/splash.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | *.jks 5 | *.p12 6 | *.key 7 | *.mobileprovision 8 | -------------------------------------------------------------------------------- /assets/countdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanBinu007/react-native-timer-app/HEAD/assets/countdown.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Installation 4 | 5 | - `git clone https://github.com/ReactNativeSchool/react-native-timer-app` 6 | - `yarn install`/`npm install` 7 | 8 | ### Running 9 | 10 | - `yarn run ios`/`npm run ios` or `yarn run android`/`npm run android` 11 | 12 | --- 13 | 14 | This project was put together to serve as an example to help you in building your own React Native apps. Feel free to download it and tinker with it! 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node_modules/expo/AppEntry.js", 3 | "scripts": { 4 | "start": "expo start", 5 | "android": "expo start --android", 6 | "ios": "expo start --ios", 7 | "eject": "expo eject", 8 | "lint": "eslint ." 9 | }, 10 | "dependencies": { 11 | "expo": "^38.0.0", 12 | "react": "16.11.0", 13 | "react-native": "https://github.com/expo/react-native/archive/sdk-38.0.2.tar.gz" 14 | }, 15 | "devDependencies": { 16 | "babel-preset-expo": "^8.2.3", 17 | "eslint": "^7.4.0", 18 | "eslint-config-handlebarlabs": "^0.0.6" 19 | }, 20 | "private": true 21 | } 22 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "Timer App", 4 | "slug": "Timer", 5 | "privacy": "public", 6 | "platforms": [ 7 | "ios", 8 | "android" 9 | ], 10 | "version": "1.0.0", 11 | "orientation": "portrait", 12 | "icon": "./assets/icon.png", 13 | "splash": { 14 | "image": "./assets/splash.png", 15 | "resizeMode": "contain", 16 | "backgroundColor": "#ffffff" 17 | }, 18 | "updates": { 19 | "fallbackToCacheTimeout": 0 20 | }, 21 | "assetBundlePatterns": [ 22 | "**/*" 23 | ], 24 | "ios": { 25 | "supportsTablet": true 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /App/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | StyleSheet, 4 | Text, 5 | View, 6 | StatusBar, 7 | TouchableOpacity, 8 | Dimensions, 9 | Picker, 10 | Platform 11 | } from "react-native"; 12 | 13 | const screen = Dimensions.get("window"); 14 | 15 | const styles = StyleSheet.create({ 16 | container: { 17 | flex: 1, 18 | backgroundColor: "#07121B", 19 | alignItems: "center", 20 | justifyContent: "center" 21 | }, 22 | button: { 23 | borderWidth: 10, 24 | borderColor: "#89AAFF", 25 | width: screen.width / 2, 26 | height: screen.width / 2, 27 | borderRadius: screen.width / 2, 28 | alignItems: "center", 29 | justifyContent: "center", 30 | marginTop: 30 31 | }, 32 | buttonStop: { 33 | borderColor: "#FF851B" 34 | }, 35 | buttonText: { 36 | fontSize: 45, 37 | color: "#89AAFF" 38 | }, 39 | buttonTextStop: { 40 | color: "#FF851B" 41 | }, 42 | timerText: { 43 | color: "#fff", 44 | fontSize: 90 45 | }, 46 | picker: { 47 | width: 50, 48 | ...Platform.select({ 49 | android: { 50 | color: "#fff", 51 | backgroundColor: "#07121B", 52 | marginLeft: 10 53 | } 54 | }) 55 | }, 56 | pickerItem: { 57 | color: "#fff", 58 | fontSize: 20 59 | }, 60 | pickerContainer: { 61 | flexDirection: "row", 62 | alignItems: "center" 63 | } 64 | }); 65 | 66 | // 3 => 03, 10 => 10 67 | const formatNumber = number => `0${number}`.slice(-2); 68 | 69 | const getRemaining = time => { 70 | const minutes = Math.floor(time / 60); 71 | const seconds = time - minutes * 60; 72 | return { minutes: formatNumber(minutes), seconds: formatNumber(seconds) }; 73 | }; 74 | 75 | const createArray = length => { 76 | const arr = []; 77 | let i = 0; 78 | while (i < length) { 79 | arr.push(i.toString()); 80 | i += 1; 81 | } 82 | 83 | return arr; 84 | }; 85 | 86 | const AVAILABLE_MINUTES = createArray(10); 87 | const AVAILABLE_SECONDS = createArray(60); 88 | 89 | export default class App extends React.Component { 90 | state = { 91 | remainingSeconds: 5, 92 | isRunning: false, 93 | selectedMinutes: "0", 94 | selectedSeconds: "5" 95 | }; 96 | 97 | interval = null; 98 | 99 | componentDidUpdate(prevProp, prevState) { 100 | if (this.state.remainingSeconds === 0 && prevState.remainingSeconds !== 0) { 101 | this.stop(); 102 | } 103 | } 104 | 105 | componentWillUnmount() { 106 | if (this.interval) { 107 | clearInterval(this.interval); 108 | } 109 | } 110 | 111 | start = () => { 112 | this.setState(state => ({ 113 | remainingSeconds: 114 | parseInt(state.selectedMinutes, 10) * 60 + 115 | parseInt(state.selectedSeconds, 10), 116 | isRunning: true 117 | })); 118 | 119 | this.interval = setInterval(() => { 120 | this.setState(state => ({ 121 | remainingSeconds: state.remainingSeconds - 1 122 | })); 123 | }, 1000); 124 | }; 125 | 126 | stop = () => { 127 | clearInterval(this.interval); 128 | this.interval = null; 129 | this.setState({ 130 | remainingSeconds: 5, // temporary 131 | isRunning: false 132 | }); 133 | }; 134 | 135 | renderPickers = () => ( 136 | 137 | { 142 | this.setState({ selectedMinutes: itemValue }); 143 | }} 144 | mode="dropdown" 145 | > 146 | {AVAILABLE_MINUTES.map(value => ( 147 | 148 | ))} 149 | 150 | minutes 151 | { 156 | this.setState({ selectedSeconds: itemValue }); 157 | }} 158 | mode="dropdown" 159 | > 160 | {AVAILABLE_SECONDS.map(value => ( 161 | 162 | ))} 163 | 164 | seconds 165 | 166 | ); 167 | 168 | render() { 169 | const { minutes, seconds } = getRemaining(this.state.remainingSeconds); 170 | 171 | return ( 172 | 173 | 174 | {this.state.isRunning ? ( 175 | {`${minutes}:${seconds}`} 176 | ) : ( 177 | this.renderPickers() 178 | )} 179 | {this.state.isRunning ? ( 180 | 184 | Stop 185 | 186 | ) : ( 187 | 188 | Start 189 | 190 | )} 191 | 192 | ); 193 | } 194 | } 195 | --------------------------------------------------------------------------------