├── .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 |
--------------------------------------------------------------------------------