Skip to content

Commit 92d448e

Browse files
committedFeb 6, 2024
initial commit
0 parents  commit 92d448e

20 files changed

+669
-0
lines changed
 

‎.gitignore

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
2+
3+
# dependencies
4+
node_modules/
5+
6+
# Expo
7+
.expo/
8+
dist/
9+
web-build/
10+
11+
# Native
12+
*.orig.*
13+
*.jks
14+
*.p8
15+
*.p12
16+
*.key
17+
*.mobileprovision
18+
19+
# Metro
20+
.metro-health-check*
21+
22+
# debug
23+
npm-debug.*
24+
yarn-debug.*
25+
yarn-error.*
26+
27+
# macOS
28+
.DS_Store
29+
*.pem
30+
31+
# local env files
32+
.env*.local
33+
34+
# typescript
35+
*.tsbuildinfo

‎App.js

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import React, { useState } from 'react';
2+
import {
3+
Text,
4+
View,
5+
SafeAreaView,
6+
StyleSheet,
7+
Platform,
8+
StatusBar,
9+
} from 'react-native';
10+
import { colors } from './src/utils/colors';
11+
import { AddTask } from './src/features/AddTask';
12+
import { Timer } from './src/components/Timer';
13+
import { StartButton } from './src/components/StartButton';
14+
import { StopButton } from './src/components/StopButton';
15+
import { PauseButton } from './src/components/PauseButton';
16+
import { Pomodoro } from './src/components/Pomodoro';
17+
18+
export default function App({ onPress = { onPress } }) {
19+
const [currentTextInput, setCurrentTextInput] = useState(null);
20+
const [isStartTimerPressed, setIsStartTimerPressed] = useState(false);
21+
const [isStopTimerPressed, setIsStopTimerPressed] = useState(false);
22+
const [isPauseTimerPressed, setIsSPauseTimerPressed] = useState(false);
23+
24+
const stopTimer = () => {
25+
if (isStartTimerPressed) {
26+
setIsStartTimerPressed(false);
27+
} else {
28+
setIsStartTimerPressed(true);
29+
}
30+
};
31+
const pauseTimer = () => {
32+
if (isPauseTimerPressed) {
33+
setIsSPauseTimerPressed(false);
34+
} else {
35+
setIsSPauseTimerPressed(true);
36+
}
37+
};
38+
39+
return (
40+
<SafeAreaView style={styles.container}>
41+
<View style={styles.titleContainer}>
42+
<Text style={styles.title}>Think Flow App</Text>
43+
</View>
44+
{!currentTextInput ? (
45+
<AddTask addFlow={setCurrentTextInput} />
46+
) : (
47+
<View style={styles.timerContainer}>
48+
<View style={styles.startTimeContainer}>
49+
{isStartTimerPressed ? (
50+
<View style={styles.timerContainer}>
51+
<Text style={styles.text}>
52+
Focusing on: {currentTextInput}
53+
</Text>
54+
</View>
55+
) : (
56+
<View style={styles.timerContainer}>
57+
<Text style={styles.text}>
58+
Start your flow state timer for {currentTextInput}
59+
</Text>
60+
</View>
61+
)}
62+
{!isStartTimerPressed ? (
63+
<StartButton
64+
startTimer={setIsStartTimerPressed}
65+
isStartTimerPressed={isStartTimerPressed}
66+
/>
67+
) : (
68+
<View style={styles.stopTimeContainer}>
69+
<Timer isPauseTimerPressed={isPauseTimerPressed} />
70+
<View style={styles.buttons}>
71+
<StopButton
72+
stopTimer={stopTimer}
73+
isStopTimerPressed={isStopTimerPressed}
74+
isStartTimerPressed={isStartTimerPressed}
75+
/>
76+
<PauseButton
77+
pauseTimer={pauseTimer}
78+
isPauseTimerPressed={isPauseTimerPressed}
79+
setIsSPauseTimerPressed={setIsSPauseTimerPressed}
80+
/>
81+
</View>
82+
<View style={styles.pomodoro}>
83+
<Pomodoro />
84+
</View>
85+
</View>
86+
)}
87+
</View>
88+
</View>
89+
)}
90+
</SafeAreaView>
91+
);
92+
}
93+
94+
const styles = StyleSheet.create({
95+
container: {
96+
flex: 1,
97+
paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,
98+
backgroundColor: colors.backgroundDark,
99+
},
100+
titleContainer: {
101+
alignItems: 'center',
102+
justifyContent: 'center',
103+
color: 'white',
104+
marginTop: 80,
105+
},
106+
title: {
107+
justifyContent: 'center',
108+
alignItems: 'center',
109+
fontSize: 24,
110+
color: 'white',
111+
fontWeight: 900,
112+
},
113+
timerContainer: {
114+
marginTop: 10,
115+
alignItems: 'center',
116+
justifyContent: 'center',
117+
height: 50,
118+
},
119+
text: {
120+
color: colors.textColor,
121+
alignItems: 'center',
122+
justifyContent: 'center',
123+
fontSize: 16,
124+
},
125+
startTimeContainer: {
126+
alignItems: 'center',
127+
justifyContent: 'center',
128+
marginTop: 60,
129+
},
130+
stopTimeContainer: {
131+
alignItems: 'center',
132+
justifyContent: 'space-between',
133+
height: 90,
134+
},
135+
buttons: {
136+
width: 320,
137+
flexDirection: 'row',
138+
marginTop: 10,
139+
justifyContent: 'space-between',
140+
},
141+
pomodoro: {
142+
height: 350,
143+
width: 350,
144+
marginTop: 20,
145+
alignItems: 'center',
146+
textAlign: 'center',
147+
},
148+
});

‎README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Sample Snack app
2+
3+
Open the `App.js` file to start writing some code. You can preview the changes directly on your phone or tablet by scanning the **QR code** or use the iOS or Android emulators. When you're done, click **Save** and share the link!
4+
5+
When you're ready to see everything that Expo provides (or if you want to use your own editor) you can **Download** your project and use it with [expo cli](https://docs.expo.dev/get-started/installation/#expo-cli)).
6+
7+
All projects created in Snack are publicly available, so you can easily share the link to this project via link, or embed it on a web page with the `<>` button.
8+
9+
If you're having problems, you can tweet to us [@expo](https://twitter.com/expo) or ask in our [forums](https://forums.expo.dev/c/expo-dev-tools/61) or [Discord](https://chat.expo.dev/).
10+
11+
Snack is Open Source. You can find the code on the [GitHub repo](https://github.com/expo/snack).

‎app.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"expo": {
3+
"name": "flow-state-time",
4+
"slug": "snack-366210ab-0b32-417b-94a3-e716f77758d9",
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+
}

‎assets/adaptive-icon.png

17.1 KB
Loading

‎assets/favicon.png

1.43 KB
Loading

‎assets/icon.png

21.9 KB
Loading

‎assets/splash.png

46.2 KB
Loading

‎babel.config.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = function(api) {
2+
api.cache(true);
3+
return {
4+
presets: ['babel-preset-expo'],
5+
};
6+
};

‎package.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
"web": "expo start --web"
8+
},
9+
"dependencies": {
10+
"expo": "~49.0.18",
11+
"expo-status-bar": "~1.6.0",
12+
"react": "18.2.0",
13+
"react-native": "0.72.6",
14+
"@expo/vector-icons": "^13.0.0",
15+
"react-native-paper": "4.9.2",
16+
"react-native-screens": "~3.22.0",
17+
"@react-navigation/stack": "^5.14.9",
18+
"@react-navigation/native": "^5.9.8",
19+
"react-native-gesture-handler": "~2.12.0",
20+
"react-native-safe-area-context": "4.6.3",
21+
"@react-native-community/masked-view": "^0.1.0"
22+
},
23+
"devDependencies": {
24+
"@babel/core": "^7.20.0"
25+
},
26+
"private": true
27+
}

‎src/components/AddTaskButton.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React from 'react';
2+
import { TouchableOpacity, Text, StyleSheet, Platform } from 'react-native';
3+
import { colors } from '../utils/colors';
4+
5+
export const AddTaskButton = ({onPress}) => {
6+
return (
7+
<TouchableOpacity style={styles.button} onPress={onPress}>
8+
<Text style={styles.buttonText}>
9+
+
10+
</Text>
11+
</TouchableOpacity>
12+
);
13+
};
14+
15+
const styles = StyleSheet.create({
16+
button: {
17+
width: 50,
18+
height: 50,
19+
marginLeft: 5,
20+
borderRadius: 125/2,
21+
borderWidth: 2,
22+
borderColor: colors.buttonBorder,
23+
paddingVertical: 15,
24+
paddingHorizontal: 20,
25+
alignItems: 'center',
26+
justifyContent: 'center',
27+
...Platform.select({
28+
ios: {
29+
shadowColor: colors.buttonShadow,
30+
shadowOffset: { width: 5, height: 2 },
31+
shadowOpacity: 0.8,
32+
shadowRadius: 4,
33+
},
34+
android: {
35+
elevation: 4,
36+
},
37+
}),
38+
},
39+
buttonText: {
40+
color: colors.textColor,
41+
fontSize: 14,
42+
fontWeight: 'light',
43+
},
44+
});

‎src/components/PauseButton.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from 'react';
2+
import { View, TouchableOpacity, Text, StyleSheet, Button, Platform } from 'react-native';
3+
import { colors } from '../utils/colors';
4+
5+
export const PauseButton = ({ pauseTimer, isPauseTimerPressed, onPress={onPress} }) => {
6+
7+
return (
8+
<TouchableOpacity style={styles.button} onPress={() => pauseTimer(!isPauseTimerPressed)}>
9+
<Text style={styles.buttonText}>
10+
{isPauseTimerPressed ? 'Resume Timer' : 'Pause Timer'}
11+
</Text>
12+
</TouchableOpacity>
13+
)
14+
}
15+
16+
const styles = StyleSheet.create({
17+
button: {
18+
width: 140,
19+
height: 50,
20+
borderRadius: 125/2,
21+
borderWidth: 2,
22+
borderColor: colors.buttonBorder,
23+
alignItems: 'center',
24+
justifyContent: 'center',
25+
...Platform.select({
26+
ios: {
27+
shadowColor: colors.buttonShadow,
28+
shadowOffset: { width: 5, height: 2 },
29+
shadowOpacity: 0.8,
30+
shadowRadius: 4,
31+
},
32+
android: {
33+
elevation: 4,
34+
},
35+
}),
36+
},
37+
buttonText: {
38+
color: colors.textColor,
39+
fontSize: 14,
40+
fontWeight: 'light',
41+
},
42+
});

‎src/components/Pomodoro.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import { TouchableOpacity, Text, StyleSheet, Platform } from 'react-native';
3+
import { colors } from '../utils/colors';
4+
5+
export const Pomodoro = () => {
6+
return (
7+
<Text style={styles.text}>
8+
The Pomodoro Technique is a time management method that uses a timer to
9+
break work into intervals, traditionally 25 minutes in length, separated
10+
by short breaks. This technique aims to enhance focus and productivity by
11+
encouraging individuals to work in short, concentrated bursts, known as
12+
"pomodoros," followed by brief periods of rest. By incorporating regular
13+
breaks, it helps maintain mental agility and reduces the likelihood of
14+
burnout, ultimately improving overall work efficiency and output.
15+
</Text>
16+
);
17+
};
18+
19+
const styles = StyleSheet.create({
20+
text: {
21+
color: colors.textColor,
22+
textAlign: 'center',
23+
fontSize: 16,
24+
fontWeight: 'light',
25+
lineHeight: 25,
26+
},
27+
});

‎src/components/RestTimer.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React, { useState, useEffect, useRef } from 'react';
2+
import { Text, View, StyleSheet } from 'react-native';
3+
4+
export const RestTimer = () => {
5+
const initialTime = 5 * 60;
6+
const [timeRemaining, setTimeRemaining] = useState(initialTime);
7+
8+
const timerRef = useRef(null);
9+
10+
useEffect(() => {
11+
timerRef.current = setInterval(() => {
12+
setTimeRemaining((prevTime) => (prevTime > 0 ? prevTime - 1 : 0));
13+
}, 1000);
14+
15+
return () => {
16+
clearInterval(timerRef.current);
17+
};
18+
}, []);
19+
20+
const formatTime = (seconds) => {
21+
const minutes = Math.floor(seconds / 60);
22+
const remainingSeconds = seconds % 60;
23+
24+
const formattedMinutes = String(minutes).padStart(2, '0');
25+
const formattedSeconds = String(remainingSeconds).padStart(2, '0');
26+
27+
return `${formattedMinutes}:${formattedSeconds}`;
28+
};
29+
30+
return (
31+
<View>
32+
<Text style={styles.timerText}>{formatTime(timeRemaining)}</Text>
33+
</View>
34+
);
35+
};
36+
const styles = StyleSheet.create({
37+
timerText: {
38+
fontSize: 35,
39+
fontWeight: 800,
40+
color: colors.textColor,
41+
},
42+
});

‎src/components/StartButton.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from 'react';
2+
import { View, TouchableOpacity, Text, StyleSheet, Button, Platform } from 'react-native';
3+
import { colors } from '../utils/colors';
4+
5+
export const StartButton = ({ startTimer, isStartTimerPressed, onPress={onPress} }) => {
6+
7+
return (
8+
<TouchableOpacity style={styles.button} onPress={() => startTimer(!isStartTimerPressed)}>
9+
<Text style={styles.buttonText}>
10+
Start Flow Timer
11+
</Text>
12+
</TouchableOpacity>
13+
)
14+
}
15+
16+
const styles = StyleSheet.create({
17+
button: {
18+
width: 180,
19+
height: 50,
20+
borderRadius: 125/2,
21+
borderWidth: 2,
22+
borderColor: colors.buttonBorder,
23+
alignItems: 'center',
24+
justifyContent: 'center',
25+
...Platform.select({
26+
ios: {
27+
shadowColor: colors.buttonShadow,
28+
shadowOffset: { width: 5, height: 2 },
29+
shadowOpacity: 0.8,
30+
shadowRadius: 4,
31+
},
32+
android: {
33+
elevation: 4,
34+
},
35+
}),
36+
},
37+
buttonText: {
38+
color: colors.textColor,
39+
fontSize: 14,
40+
fontWeight: 'light',
41+
},
42+
});

‎src/components/StartNewTaskButton.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react';
2+
import {
3+
View,
4+
TouchableOpacity,
5+
Text,
6+
StyleSheet,
7+
Button,
8+
Platform,
9+
} from 'react-native';
10+
import { colors } from '../utils/colors';
11+
12+
export const StartNewTaskButton = ({onPress}) => {
13+
return (
14+
<TouchableOpacity style={styles.button} onPress={onPress}>
15+
<Text style={styles.buttonText}>
16+
Start a new task
17+
</Text>
18+
</TouchableOpacity>
19+
);
20+
};
21+
22+
const styles = StyleSheet.create({
23+
button: {
24+
width: 180,
25+
height: 50,
26+
borderRadius: 125/2,
27+
borderWidth: 2,
28+
borderColor: colors.buttonBorder,
29+
marginTop: 20,
30+
alignItems: 'center',
31+
justifyContent: 'center',
32+
...Platform.select({
33+
ios: {
34+
shadowColor: colors.buttonShadow,
35+
shadowOffset: { width: 5, height: 2 },
36+
shadowOpacity: 0.8,
37+
shadowRadius: 4,
38+
},
39+
android: {
40+
elevation: 4,
41+
},
42+
}),
43+
},
44+
buttonText: {
45+
color: colors.textColor,
46+
fontSize: 14,
47+
fontWeight: 'light',
48+
},
49+
});

‎src/components/StopButton.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import React from 'react';
2+
import {
3+
View,
4+
TouchableOpacity,
5+
Text,
6+
StyleSheet,
7+
Button,
8+
Platform,
9+
} from 'react-native';
10+
import { colors } from '../utils/colors';
11+
12+
export const StopButton = ({
13+
stopTimer,
14+
isStopTimerPressed,
15+
onPress = { onPress },
16+
}) => {
17+
return (
18+
<TouchableOpacity
19+
style={styles.button}
20+
onPress={() => stopTimer(!isStopTimerPressed)}>
21+
<Text style={styles.buttonText}>Stop Timer</Text>
22+
</TouchableOpacity>
23+
);
24+
};
25+
26+
const styles = StyleSheet.create({
27+
button: {
28+
width: 140,
29+
height: 50,
30+
borderRadius: 125 / 2,
31+
borderWidth: 2,
32+
borderColor: colors.buttonBorder,
33+
alignItems: 'center',
34+
justifyContent: 'center',
35+
...Platform.select({
36+
ios: {
37+
shadowColor: colors.buttonShadow,
38+
shadowOffset: { width: 5, height: 2 },
39+
shadowOpacity: 0.8,
40+
shadowRadius: 4,
41+
},
42+
android: {
43+
elevation: 4,
44+
},
45+
}),
46+
},
47+
buttonText: {
48+
color: colors.textColor,
49+
fontSize: 14,
50+
fontWeight: 'light',
51+
},
52+
});

‎src/components/Timer.js

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React, { useState, useEffect, useRef } from 'react';
2+
import {
3+
TouchableOpacity,
4+
View,
5+
Text,
6+
StyleSheet,
7+
Platform,
8+
} from 'react-native';
9+
import { colors } from '../utils/colors';
10+
11+
export const Timer = ({isPauseTimerPressed}) => {
12+
const initialTime = 25 * 60;
13+
const [timeRemaining, setTimeRemaining] = useState(initialTime);
14+
15+
const timerRef = useRef(null);
16+
17+
useEffect(() => {
18+
if (isPauseTimerPressed) {
19+
clearInterval(timerRef.current);
20+
} else {
21+
timerRef.current = setInterval(() => {
22+
setTimeRemaining((prevTime) => (prevTime > 0 ? prevTime - 1 : 0));
23+
}, 1000);
24+
}
25+
26+
return () => {
27+
clearInterval(timerRef.current);
28+
};
29+
}, [isPauseTimerPressed]);
30+
31+
const formatTime = (seconds) => {
32+
const minutes = Math.floor(seconds / 60);
33+
const remainingSeconds = seconds % 60;
34+
35+
const formattedMinutes = String(minutes).padStart(2, '0');
36+
const formattedSeconds = String(remainingSeconds).padStart(2, '0');
37+
38+
return `${formattedMinutes}:${formattedSeconds}`;
39+
};
40+
41+
42+
43+
return (
44+
<View>
45+
<Text style={styles.timerText}>{formatTime(timeRemaining)}</Text>
46+
</View>
47+
);
48+
};
49+
50+
const styles = StyleSheet.create({
51+
timerText: {
52+
fontSize: 35,
53+
fontWeight: 800,
54+
color: colors.textColor,
55+
},
56+
});

‎src/features/AddTask.js

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React, { useState } from 'react';
2+
import {
3+
Text,
4+
View,
5+
SafeAreaView,
6+
StyleSheet,
7+
Platform,
8+
StatusBar,
9+
} from 'react-native';
10+
import { TextInput } from 'react-native-paper';
11+
import { colors } from '../utils/colors';
12+
import { AddTaskButton } from '../components/AddTaskButton';
13+
14+
export const AddTask = ({ addFlow }) => {
15+
const [flowTextInput, setFlowTextInput] = useState(null);
16+
17+
return (
18+
<View style={styles.inputContainer}>
19+
<TextInput
20+
style={styles.inputStyle}
21+
label="What task requires flow state today?"
22+
onChangeText={setFlowTextInput}
23+
/>
24+
<View style={styles.buttonContainer}>
25+
<AddTaskButton onPress={() => addFlow(flowTextInput)} />
26+
</View>
27+
</View>
28+
);
29+
};
30+
31+
const styles = StyleSheet.create({
32+
inputContainer: {
33+
flex: 0,
34+
padding: 25,
35+
justifyContent: 'center',
36+
flexDirection: 'row',
37+
},
38+
buttonContainer: {
39+
justifyContent: 'center',
40+
},
41+
inputStyle: {
42+
width: 280,
43+
height: 60,
44+
marginRight: 10,
45+
borderTopLeftRadius: 18,
46+
borderBottomLeftRadius: 18,
47+
borderBottomRightRadius: 18,
48+
color: colors.inputTextColor,
49+
},
50+
});

‎src/utils/colors.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const colors = {
2+
textColor: '#fff',
3+
inputTextColor: '#504a54',
4+
backgroundDark: '#343738',
5+
buttonBackground: '#a435f0',
6+
buttonBorder: '#fff',
7+
buttonShadow: '#0000',
8+
}

0 commit comments

Comments
 (0)
Please sign in to comment.