├── alarm.wav
├── flyer.pdf
├── assets
├── images
│ ├── icon.png
│ ├── splash.png
│ ├── robot-dev.png
│ ├── stretch_1.PNG
│ ├── stretch_2.PNG
│ ├── stretch_3.PNG
│ ├── stretch_5.PNG
│ ├── stretch_6.PNG
│ ├── stretch_7.PNG
│ ├── stretch_9.PNG
│ ├── robot-prod.png
│ ├── stretch_10.PNG
│ ├── stretch_11.PNG
│ ├── stretch_12.PNG
│ ├── stretch_13.PNG
│ └── stretch_14.PNG
└── fonts
│ └── SpaceMono-Regular.ttf
├── babel.config.js
├── .gitignore
├── components
├── StyledText.js
├── __tests__
│ ├── StyledText-test.js
│ └── __snapshots__
│ │ └── StyledText-test.js.snap
├── TabBarIcon.js
└── Button.js
├── constants
├── Layout.js
└── Colors.js
├── .expo-shared
└── assets.json
├── screens
├── SettingsScreen.js
├── LinksScreen.js
├── ArrivedScreen.js
├── HomeScreen.js
├── BreakScreen.js
├── HelpScreen.js
└── QuizScreen.js
├── navigation
├── AppNavigator.js
├── AppNavigator.web.js
└── MainTabNavigator.js
├── __tests__
├── __snapshots__
│ └── App-test.js.snap
└── App-test.js
├── README.md
├── app.json
├── package.json
└── App.js
/alarm.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/alarm.wav
--------------------------------------------------------------------------------
/flyer.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/flyer.pdf
--------------------------------------------------------------------------------
/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/icon.png
--------------------------------------------------------------------------------
/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/splash.png
--------------------------------------------------------------------------------
/assets/images/robot-dev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/robot-dev.png
--------------------------------------------------------------------------------
/assets/images/stretch_1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_1.PNG
--------------------------------------------------------------------------------
/assets/images/stretch_2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_2.PNG
--------------------------------------------------------------------------------
/assets/images/stretch_3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_3.PNG
--------------------------------------------------------------------------------
/assets/images/stretch_5.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_5.PNG
--------------------------------------------------------------------------------
/assets/images/stretch_6.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_6.PNG
--------------------------------------------------------------------------------
/assets/images/stretch_7.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_7.PNG
--------------------------------------------------------------------------------
/assets/images/stretch_9.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_9.PNG
--------------------------------------------------------------------------------
/assets/images/robot-prod.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/robot-prod.png
--------------------------------------------------------------------------------
/assets/images/stretch_10.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_10.PNG
--------------------------------------------------------------------------------
/assets/images/stretch_11.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_11.PNG
--------------------------------------------------------------------------------
/assets/images/stretch_12.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_12.PNG
--------------------------------------------------------------------------------
/assets/images/stretch_13.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_13.PNG
--------------------------------------------------------------------------------
/assets/images/stretch_14.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/images/stretch_14.PNG
--------------------------------------------------------------------------------
/assets/fonts/SpaceMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CompSciLauren/drive-awake/master/assets/fonts/SpaceMono-Regular.ttf
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 | web-report/
12 |
13 | # macOS
14 | .DS_Store
15 |
--------------------------------------------------------------------------------
/components/StyledText.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text } from 'react-native';
3 |
4 | export function MonoText(props) {
5 | return (
6 |
7 | );
8 | }
9 |
--------------------------------------------------------------------------------
/constants/Layout.js:
--------------------------------------------------------------------------------
1 | import { Dimensions } from 'react-native';
2 |
3 | const width = Dimensions.get('window').width;
4 | const height = Dimensions.get('window').height;
5 |
6 | export default {
7 | window: {
8 | width,
9 | height,
10 | },
11 | isSmallDevice: width < 375,
12 | };
13 |
--------------------------------------------------------------------------------
/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "0cae4d70c6df3e5e96ee8b5c442b59d55c8ab8deb466992ab9abc523822f2a1b": true,
3 | "e997a5256149a4b76e6bfd6cbf519c5e5a0f1d278a3d8fa1253022b03c90473b": true,
4 | "af683c96e0ffd2cf81287651c9433fa44debc1220ca7cb431fe482747f34a505": true,
5 | "e7fc0741cc6562975a990e3d9ef820571588dab20aba97032df9f00caa9cd57a": true
6 | }
--------------------------------------------------------------------------------
/components/__tests__/StyledText-test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 |
4 | import { MonoText } from '../StyledText';
5 |
6 | it(`renders correctly`, () => {
7 | const tree = renderer.create(Snapshot test!).toJSON();
8 |
9 | expect(tree).toMatchSnapshot();
10 | });
11 |
--------------------------------------------------------------------------------
/components/__tests__/__snapshots__/StyledText-test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`renders correctly 1`] = `
4 |
14 | Snapshot test!
15 |
16 | `;
17 |
--------------------------------------------------------------------------------
/constants/Colors.js:
--------------------------------------------------------------------------------
1 | const tintColor = '#2f95dc';
2 |
3 | export default {
4 | tintColor,
5 | tabIconDefault: '#ccc',
6 | tabIconSelected: tintColor,
7 | tabBar: '#fefefe',
8 | errorBackground: 'red',
9 | errorText: '#fff',
10 | warningBackground: '#EAEB5E',
11 | warningText: '#666804',
12 | noticeBackground: tintColor,
13 | noticeText: '#fff',
14 | };
15 |
--------------------------------------------------------------------------------
/components/TabBarIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Ionicons } from '@expo/vector-icons';
3 |
4 | import Colors from '../constants/Colors';
5 |
6 | export default function TabBarIcon(props) {
7 | return (
8 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/screens/SettingsScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ExpoConfigView } from '@expo/samples';
3 |
4 | export default function SettingsScreen() {
5 | /**
6 | * Go ahead and delete ExpoConfigView and replace it with your content;
7 | * we just wanted to give you a quick view of your config.
8 | */
9 | return ;
10 | }
11 |
12 | SettingsScreen.navigationOptions = {
13 | header: null,
14 | };
15 |
--------------------------------------------------------------------------------
/navigation/AppNavigator.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createAppContainer, createSwitchNavigator } from 'react-navigation';
3 |
4 | import MainTabNavigator from './MainTabNavigator';
5 |
6 | export default createAppContainer(
7 | createSwitchNavigator({
8 | // You could add another route here for authentication.
9 | // Read more at https://reactnavigation.org/docs/en/auth-flow.html
10 | Main: MainTabNavigator,
11 | })
12 | );
13 |
--------------------------------------------------------------------------------
/__tests__/__snapshots__/App-test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`App renders the loading screen 1`] = `
4 |
9 | `;
10 |
11 | exports[`App renders the root without loading screen 1`] = `
12 |
20 |
21 |
22 | `;
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ASTIR
2 |
3 | A mobile app and hardware component that work together to help detect and prevent drowsy driving.
4 |
5 | ## Devpost Link
6 |
7 | https://devpost.com/software/astir
8 |
9 | ## Flyer
10 |
11 | [Flyer](https://github.com/CompSciLauren/drive-awake/blob/master/flyer.pdf)
12 |
13 | ## Related GitHub Repos
14 |
15 | https://github.com/SebastianMcMillan/astir-sensors
16 |
17 | https://github.com/ellyrichardson/HackKU-2020_Backend-API
18 |
19 | https://github.com/ellyrichardson/HackKU-2020_Drowsy-Detection
20 |
--------------------------------------------------------------------------------
/navigation/AppNavigator.web.js:
--------------------------------------------------------------------------------
1 | import { createBrowserApp } from '@react-navigation/web';
2 | import { createSwitchNavigator } from 'react-navigation';
3 |
4 | import MainTabNavigator from './MainTabNavigator';
5 |
6 | const switchNavigator = createSwitchNavigator({
7 | // You could add another route here for authentication.
8 | // Read more at https://reactnavigation.org/docs/en/auth-flow.html
9 | Main: MainTabNavigator,
10 | });
11 | switchNavigator.path = '';
12 |
13 | export default createBrowserApp(switchNavigator, { history: 'hash' });
14 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "Tab Navigation Template",
4 | "slug": "drive-awake",
5 | "privacy": "public",
6 | "sdkVersion": "36.0.0",
7 | "platforms": ["ios", "android", "web"],
8 | "version": "1.0.0",
9 | "orientation": "portrait",
10 | "icon": "./assets/images/icon.png",
11 | "splash": {
12 | "image": "./assets/images/splash.png",
13 | "resizeMode": "contain",
14 | "backgroundColor": "#ffffff"
15 | },
16 | "updates": {
17 | "fallbackToCacheTimeout": 0
18 | },
19 | "assetBundlePatterns": ["**/*"],
20 | "ios": {
21 | "supportsTablet": true
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/__tests__/App-test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import NavigationTestUtils from 'react-navigation/NavigationTestUtils';
3 | import renderer from 'react-test-renderer';
4 |
5 | import App from '../App';
6 |
7 | jest.mock('expo', () => ({
8 | AppLoading: 'AppLoading',
9 | }));
10 |
11 | jest.mock('../navigation/AppNavigator', () => 'AppNavigator');
12 |
13 | describe('App', () => {
14 | jest.useFakeTimers();
15 |
16 | beforeEach(() => {
17 | NavigationTestUtils.resetInternalState();
18 | });
19 |
20 | it(`renders the loading screen`, () => {
21 | const tree = renderer.create().toJSON();
22 | expect(tree).toMatchSnapshot();
23 | });
24 |
25 | it(`renders the root without loading screen`, () => {
26 | const tree = renderer.create().toJSON();
27 | expect(tree).toMatchSnapshot();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/components/Button.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Platform,
4 | StyleSheet,
5 | Text,
6 | TouchableOpacity,
7 | View,
8 | } from 'react-native';
9 |
10 | export function Button(props) {
11 | const { title } = props;
12 | return (
13 |
14 |
15 | {title}
16 |
17 |
18 | );
19 | }
20 |
21 | const styles = StyleSheet.create({
22 | buttonContainer: {
23 | paddingHorizontal: 100,
24 | },
25 | buttonButton: {
26 | width: 154,
27 | height: 72,
28 | backgroundColor: '#930101',
29 | borderRadius: 10,
30 | marginTop: 10,
31 | marginBottom: 25,
32 | justifyContent: 'center',
33 | alignItems: 'center',
34 | ...Platform.select({
35 | ios: {
36 | shadowColor: 'black',
37 | shadowOffset: { width: 0, height: -3 },
38 | shadowOpacity: 0.1,
39 | shadowRadius: 3,
40 | },
41 | android: {
42 | elevation: 5,
43 | },
44 | }),
45 | },
46 | buttonText: {
47 | fontSize: 17,
48 | fontWeight: 'bold',
49 | color: 'white',
50 | paddingVertical: 10,
51 | },
52 | });
53 |
--------------------------------------------------------------------------------
/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 | "web": "expo start --web",
8 | "eject": "expo eject",
9 | "test": "jest --watchAll"
10 | },
11 | "jest": {
12 | "preset": "jest-expo"
13 | },
14 | "dependencies": {
15 | "@expo/samples": "~36.0.0",
16 | "@expo/vector-icons": "~10.0.0",
17 | "@react-navigation/web": "~1.0.0-alpha.9",
18 | "expo": "~36.0.0",
19 | "expo-asset": "~8.0.0",
20 | "expo-constants": "~8.0.0",
21 | "expo-font": "~8.0.0",
22 | "expo-web-browser": "~8.0.0",
23 | "react": "~16.9.0",
24 | "react-dom": "~16.9.0",
25 | "react-native": "https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz",
26 | "react-native-countdown-component": "^2.6.0",
27 | "react-native-geocoding": "^0.4.0",
28 | "react-native-geolocation-service": "^4.0.0",
29 | "react-native-gesture-handler": "~1.5.0",
30 | "react-native-play-sound": "^1.0.24",
31 | "react-native-reanimated": "~1.4.0",
32 | "react-native-screens": "2.0.0-alpha.12",
33 | "react-native-sound": "^0.11.0",
34 | "react-native-swipe-gestures": "^1.0.4",
35 | "react-native-web": "~0.11.7",
36 | "react-navigation": "~4.0.10",
37 | "react-navigation-stack": "~1.10.3",
38 | "react-navigation-tabs": "~2.6.2"
39 | },
40 | "devDependencies": {
41 | "@babel/core": "^7.0.0",
42 | "babel-preset-expo": "~8.0.0",
43 | "jest-expo": "~36.0.1"
44 | },
45 | "private": true
46 | }
47 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import { AppLoading } from 'expo';
2 | import { Asset } from 'expo-asset';
3 | import * as Font from 'expo-font';
4 | import React, { useState } from 'react';
5 | import { Platform, StatusBar, StyleSheet, View } from 'react-native';
6 | import { Ionicons } from '@expo/vector-icons';
7 |
8 | import AppNavigator from './navigation/AppNavigator';
9 |
10 | export default function App(props) {
11 | const [isLoadingComplete, setLoadingComplete] = useState(false);
12 |
13 | if (!isLoadingComplete && !props.skipLoadingScreen) {
14 | return (
15 | handleFinishLoading(setLoadingComplete)}
19 | />
20 | );
21 | } else {
22 | return (
23 |
24 | {Platform.OS === 'ios' && }
25 |
26 |
27 | );
28 | }
29 | }
30 |
31 | async function loadResourcesAsync() {
32 | await Promise.all([
33 | Asset.loadAsync([
34 | require('./assets/images/robot-dev.png'),
35 | require('./assets/images/robot-prod.png'),
36 | ]),
37 | Font.loadAsync({
38 | // This is the font that we are using for our tab bar
39 | ...Ionicons.font,
40 | // We include SpaceMono because we use it in HomeScreen.js. Feel free to
41 | // remove this if you are not using it in your app
42 | 'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf'),
43 | }),
44 | ]);
45 | }
46 |
47 | function handleLoadingError(error) {
48 | // In this case, you might want to report the error to your error reporting
49 | // service, for example Sentry
50 | console.warn(error);
51 | }
52 |
53 | function handleFinishLoading(setLoadingComplete) {
54 | setLoadingComplete(true);
55 | }
56 |
57 | const styles = StyleSheet.create({
58 | container: {
59 | flex: 1,
60 | backgroundColor: '#fff',
61 | },
62 | });
63 |
--------------------------------------------------------------------------------
/screens/LinksScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { TouchableOpacity, View, Text, Vibration } from 'react-native';
3 | import { Button } from '../components/Button';
4 |
5 | export default class LinksScreen extends React.Component {
6 | handleTurnDeviceOn = async () => {
7 | fetch('http://13.58.89.149:8000/endpoint/api/onoff/', {
8 | method: 'POST',
9 | headers: {
10 | Accept: 'application/json',
11 | 'Content-Type': 'application/json',
12 | },
13 | body: JSON.stringify({
14 | turnOnConnection: true,
15 | }),
16 | });
17 | };
18 |
19 | handleTurnDeviceOff = async () => {
20 | fetch('http://13.58.89.149:8000/endpoint/api/onoff/', {
21 | method: 'POST',
22 | headers: {
23 | Accept: 'application/json',
24 | 'Content-Type': 'application/json',
25 | },
26 | body: JSON.stringify({
27 | turnOnConnection: false,
28 | }),
29 | });
30 | };
31 |
32 | componentDidMount() {
33 | this.timer = setInterval(() => this.handleGetRequest(), 5000);
34 | }
35 |
36 | handleGetRequest = async () => {
37 | fetch('http://13.58.89.149:8000/endpoint/api/status/', {
38 | method: 'GET',
39 | //Request Type
40 | })
41 | .then(response => response.json())
42 | //If response is in json then in success
43 | .then(responseJson => {
44 | //Success
45 | if (responseJson[responseJson.length - 1].isDrowsy == true) {
46 | const DURATION = 5000;
47 |
48 | Vibration.vibrate(DURATION);
49 | alert('You are falling asleep. Pull over as soon as possible.');
50 | }
51 | })
52 | //If response is not in json then in error
53 | .catch(error => {
54 | //Error
55 | console.error(error);
56 | });
57 | };
58 |
59 | render() {
60 | return (
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | );
71 | }
72 | }
73 |
74 | LinksScreen.navigationOptions = {
75 | header: null,
76 | };
77 |
--------------------------------------------------------------------------------
/screens/ArrivedScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ScrollView, StyleSheet, Text, View } from 'react-native';
3 | import { TouchableOpacity } from 'react-native-gesture-handler';
4 | import { Button } from '../components/Button';
5 |
6 | export default class ArrivedScreen extends React.Component {
7 | handleSendSMS = async () => {
8 | fetch('http://13.58.89.149:8000/contacts/api/sms/', {
9 | method: 'POST',
10 | headers: {
11 | Accept: 'application/json',
12 | 'Content-Type': 'application/json',
13 | },
14 | body: JSON.stringify({
15 | receiver: '+18167729435',
16 | sender: '+15307224633',
17 | message: 'I arrived at my destination successfully.',
18 | }),
19 | });
20 | fetch('http://13.58.89.149:8000/contacts/api/sms/', {
21 | method: 'POST',
22 | headers: {
23 | Accept: 'application/json',
24 | 'Content-Type': 'application/json',
25 | },
26 | body: JSON.stringify({
27 | receiver: '+18165502253',
28 | sender: '+15307224633',
29 | message: 'I arrived at my destination successfully.',
30 | }),
31 | });
32 | fetch('http://13.58.89.149:8000/contacts/api/sms/', {
33 | method: 'POST',
34 | headers: {
35 | Accept: 'application/json',
36 | 'Content-Type': 'application/json',
37 | },
38 | body: JSON.stringify({
39 | receiver: '+19137558051',
40 | sender: '+15307224633',
41 | message: 'I arrived at my destination successfully.',
42 | }),
43 | });
44 | };
45 | render() {
46 | return (
47 |
48 |
52 |
53 | Hurray!
54 |
55 |
56 |
57 |
58 | Send a text to let your buddy know you arrived safely!
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | );
69 | }
70 | }
71 |
72 | ArrivedScreen.navigationOptions = {
73 | header: null,
74 | };
75 |
76 | const styles = StyleSheet.create({
77 | container: {
78 | flex: 1,
79 | backgroundColor: '#fff',
80 | },
81 | contentContainer: {
82 | paddingTop: 30,
83 | },
84 | textContainer: {
85 | alignItems: 'center',
86 | marginHorizontal: 50,
87 | marginBottom: 12,
88 | },
89 | randomText: {
90 | fontSize: 24,
91 | color: 'rgba(0,0,0, 0.87)',
92 | lineHeight: 24,
93 | textAlign: 'center',
94 | },
95 | buttonContainer: {
96 | alignItems: 'center',
97 | },
98 | });
99 |
--------------------------------------------------------------------------------
/screens/HomeScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ScrollView, StyleSheet, Text, View } from 'react-native';
3 | import { TouchableOpacity } from 'react-native-gesture-handler';
4 | import CountDown from 'react-native-countdown-component';
5 | import { Button } from '../components/Button';
6 |
7 | export default class HomeScreen extends React.Component {
8 | render() {
9 | const { navigate } = this.props.navigation;
10 | return (
11 |
12 |
16 |
17 | Time until required break:
18 |
19 | navigate('Break')}
23 | digitStyle={{
24 | backgroundColor: '#FFF',
25 | borderWidth: 2,
26 | borderColor: '#930101',
27 | }}
28 | digitTxtStyle={{ color: '#930101' }}
29 | timeLabelStyle={{ color: 'red', fontWeight: 'bold' }}
30 | separatorStyle={{ color: '#930101' }}
31 | timeToShow={['H', 'M', 'S']}
32 | timeLabels={{ m: null, s: null }}
33 | showSeparator
34 | />
35 |
36 |
37 |
38 | navigate('Help')}>
39 |
40 |
41 |
42 | navigate('Arrived')}>
43 |
44 |
45 |
46 | navigate('Quiz')}>
47 |
48 |
49 |
50 | {/*
51 | The weather is (good/bad). Road conditions (should be normal / may
52 | be bad).
53 | */}
54 |
55 | navigate('Break')}>
56 |
57 |
58 |
59 |
60 |
61 | );
62 | }
63 | }
64 |
65 | HomeScreen.navigationOptions = {
66 | header: null,
67 | };
68 |
69 | const styles = StyleSheet.create({
70 | container: {
71 | flex: 1,
72 | backgroundColor: '#fff',
73 | },
74 | contentContainer: {
75 | paddingTop: 30,
76 | },
77 | getStartedContainer: {
78 | alignItems: 'center',
79 | marginHorizontal: 50,
80 | },
81 | buttonsAndWeatherContainer: {
82 | marginTop: 60,
83 | alignItems: 'center',
84 | },
85 | breakText: {
86 | fontSize: 24,
87 | color: 'rgba(0,0,0, 0.87)',
88 | lineHeight: 24,
89 | textAlign: 'center',
90 | marginBottom: 20,
91 | },
92 | // weatherText: {
93 | // marginTop: 40,
94 | // fontSize: 24,
95 | // color: 'rgba(0,0,0, 0.87)',
96 | // lineHeight: 24,
97 | // textAlign: 'center',
98 | // marginHorizontal: 20,
99 | // },
100 | });
101 |
--------------------------------------------------------------------------------
/screens/BreakScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Image, ScrollView, StyleSheet, Text, View } from 'react-native';
3 | import CountDown from 'react-native-countdown-component';
4 |
5 | const funFactsList = [
6 | 'The Sleep Foundation recommends that you take a break every 2 hours or every 100 miles to do something stimulating.',
7 | 'Caffeine does not increase your reaction time on the road.',
8 | 'Certain music can help to increase your awakeness, so pump it up!',
9 | ];
10 |
11 | export default class BreakScreen extends React.Component {
12 | render() {
13 | const { navigate } = this.props.navigation;
14 |
15 | const stretchArray2 = [
16 | 'Do the Cha Cha slide!',
17 | 'Jog in place.',
18 | 'Do jumping jacks.',
19 | 'Hope on one foot for 30 seconds.',
20 | 'Do five lunges.',
21 | 'Do a little shimmy!',
22 | ];
23 |
24 | const stretchArray = [
25 | 'stretch_1.PNG',
26 | 'stretch_2.PNG',
27 | 'stretch_3.PNG',
28 | 'stretch_5.PNG',
29 | 'stretch_6.PNG',
30 | 'stretch_7.PNG',
31 | 'stretch_9.PNG',
32 | 'stretch_10.PNG',
33 | 'stretch_11.PNG',
34 | 'stretch_12.PNG',
35 | 'stretch_13.PNG',
36 | 'stretch_14.PNG',
37 | ];
38 | return (
39 |
40 |
44 |
45 |
46 | Time to pull over and take a short break!
47 |
48 |
49 |
50 | navigate('Quiz')}
54 | digitStyle={{
55 | backgroundColor: '#FFF',
56 | borderWidth: 2,
57 | borderColor: '#930101',
58 | }}
59 | digitTxtStyle={{ color: '#930101' }}
60 | timeLabelStyle={{ color: 'red', fontWeight: 'bold' }}
61 | separatorStyle={{ color: '#930101' }}
62 | timeToShow={['H', 'M', 'S']}
63 | timeLabels={{ m: null, s: null }}
64 | showSeparator
65 | />
66 |
67 |
68 |
69 | Take this opportunity to stretch!
70 |
71 |
72 |
73 |
74 |
75 | {stretchArray2[Math.floor(Math.random() * stretchArray2.length)]}
76 |
77 |
78 |
79 | {/*
80 |
85 | */}
86 |
87 |
88 | Did you know?
89 |
90 |
91 |
92 |
93 | {funFactsList[Math.floor(Math.random() * funFactsList.length)]}
94 |
95 |
96 |
97 |
98 | );
99 | }
100 | }
101 |
102 | BreakScreen.navigationOptions = {
103 | header: null,
104 | };
105 |
106 | const styles = StyleSheet.create({
107 | container: {
108 | flex: 1,
109 | backgroundColor: '#fff',
110 | },
111 | contentContainer: {
112 | paddingTop: 30,
113 | },
114 | textContainer: {
115 | alignItems: 'center',
116 | marginHorizontal: 50,
117 | marginBottom: 12,
118 | },
119 | randomText: {
120 | fontSize: 24,
121 | color: 'rgba(0,0,0, 0.87)',
122 | lineHeight: 24,
123 | textAlign: 'center',
124 | },
125 | biggerText: {
126 | fontSize: 24,
127 | color: 'rgba(0,0,0, 0.87)',
128 | lineHeight: 24,
129 | textAlign: 'center',
130 | marginTop: 50,
131 | },
132 | biggerText2: {
133 | fontSize: 24,
134 | color: 'rgba(0,0,0, 0.87)',
135 | lineHeight: 24,
136 | textAlign: 'center',
137 | marginTop: 50,
138 | marginBottom: 20,
139 | },
140 | smallerText: {
141 | fontSize: 18,
142 | color: 'rgba(0,0,0, 0.87)',
143 | lineHeight: 24,
144 | textAlign: 'center',
145 | marginTop: 15,
146 | },
147 | imageSize: {
148 | width: 'auto',
149 | height: 160,
150 | },
151 | });
152 |
--------------------------------------------------------------------------------
/navigation/MainTabNavigator.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Platform } from 'react-native';
3 | import { createStackNavigator } from 'react-navigation-stack';
4 | import { createMaterialTopTabNavigator } from 'react-navigation-tabs';
5 |
6 | import TabBarIcon from '../components/TabBarIcon';
7 | import HomeScreen from '../screens/HomeScreen';
8 | import HelpScreen from '../screens/HelpScreen';
9 | import ArrivedScreen from '../screens/ArrivedScreen';
10 | import QuizScreen from '../screens/QuizScreen';
11 | import BreakScreen from '../screens/BreakScreen';
12 | import LinksScreen from '../screens/LinksScreen';
13 | import SettingsScreen from '../screens/SettingsScreen';
14 |
15 | const config = Platform.select({
16 | web: { headerMode: 'screen' },
17 | default: {},
18 | });
19 |
20 | const HomeStack = createStackNavigator(
21 | {
22 | Home: HomeScreen,
23 | Help: HelpScreen,
24 | Arrived: ArrivedScreen,
25 | Quiz: QuizScreen,
26 | Break: BreakScreen,
27 | Settings: SettingsScreen,
28 | },
29 | config
30 | );
31 |
32 | HomeStack.navigationOptions = {
33 | tabBarLabel: 'Home',
34 | tabBarIcon: ({ focused }) => (
35 |
43 | ),
44 | };
45 |
46 | HomeStack.path = '';
47 |
48 | const HelpStack = createStackNavigator(
49 | {
50 | Help: HelpScreen,
51 | },
52 | config
53 | );
54 |
55 | HelpStack.navigationOptions = {
56 | tabBarLabel: 'Help',
57 | tabBarIcon: ({ focused }) => (
58 |
66 | ),
67 | };
68 |
69 | HelpStack.path = '';
70 |
71 | const ArrivedStack = createStackNavigator(
72 | {
73 | Arrived: ArrivedScreen,
74 | },
75 | config
76 | );
77 |
78 | ArrivedStack.navigationOptions = {
79 | tabBarLabel: 'Arrived',
80 | tabBarIcon: ({ focused }) => (
81 |
89 | ),
90 | };
91 |
92 | ArrivedStack.path = '';
93 |
94 | const QuizStack = createStackNavigator(
95 | {
96 | Quiz: QuizScreen,
97 | },
98 | config
99 | );
100 |
101 | QuizStack.navigationOptions = {
102 | tabBarLabel: 'Astir',
103 | tabBarIcon: ({ focused }) => (
104 |
108 | ),
109 | };
110 |
111 | QuizStack.path = '';
112 |
113 | const BreakStack = createStackNavigator(
114 | {
115 | Break: BreakScreen,
116 | },
117 | config
118 | );
119 |
120 | BreakStack.navigationOptions = {
121 | tabBarLabel: 'Break',
122 | tabBarIcon: ({ focused }) => (
123 |
131 | ),
132 | };
133 |
134 | BreakStack.path = '';
135 |
136 | const LinksStack = createStackNavigator(
137 | {
138 | Links: LinksScreen,
139 | },
140 | config
141 | );
142 |
143 | LinksStack.navigationOptions = {
144 | tabBarLabel: 'Astir',
145 | tabBarIcon: ({ focused }) => (
146 |
150 | ),
151 | };
152 |
153 | LinksStack.path = '';
154 |
155 | const SettingsStack = createStackNavigator(
156 | {
157 | Settings: SettingsScreen,
158 | },
159 | config
160 | );
161 |
162 | SettingsStack.navigationOptions = {
163 | tabBarLabel: 'Settings',
164 | tabBarIcon: ({ focused }) => (
165 |
169 | ),
170 | };
171 |
172 | SettingsStack.path = '';
173 |
174 | const tabNavigator = createMaterialTopTabNavigator(
175 | {
176 | HomeStack,
177 | LinksStack,
178 | SettingsStack,
179 | },
180 | {
181 | tabBarOptions: {
182 | style: {
183 | backgroundColor: '#009890',
184 | height: 75,
185 | justifyContent: 'flex-end',
186 | },
187 | },
188 | }
189 | );
190 |
191 | tabNavigator.path = '';
192 |
193 | export default tabNavigator;
194 |
--------------------------------------------------------------------------------
/screens/HelpScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ScrollView, StyleSheet, Text, View } from 'react-native';
3 | import { TouchableOpacity } from 'react-native-gesture-handler';
4 | import { Button } from '../components/Button';
5 | import Geolocation from 'react-native-geolocation-service';
6 | import Geocoder from 'react-native-geocoding';
7 |
8 | export default class HelpScreen extends React.Component {
9 | handleSendSMS = async () => {
10 | fetch('http://13.58.89.149:8000/contacts/api/sms/', {
11 | method: 'POST',
12 | headers: {
13 | Accept: 'application/json',
14 | 'Content-Type': 'application/json',
15 | },
16 | body: JSON.stringify({
17 | receiver: '+18167729435',
18 | sender: '+15307224633',
19 | message:
20 | 'I am in need of assistance in this location: 1450 Jayhawk Blvd, Lawrence, KS 66045',
21 | }),
22 | });
23 | fetch('http://13.58.89.149:8000/contacts/api/sms/', {
24 | method: 'POST',
25 | headers: {
26 | Accept: 'application/json',
27 | 'Content-Type': 'application/json',
28 | },
29 | body: JSON.stringify({
30 | receiver: '+18165502253',
31 | sender: '+15307224633',
32 | message:
33 | 'I am in need of assistance in this location: 1450 Jayhawk Blvd, Lawrence, KS 66045',
34 | }),
35 | });
36 | fetch('http://13.58.89.149:8000/contacts/api/sms/', {
37 | method: 'POST',
38 | headers: {
39 | Accept: 'application/json',
40 | 'Content-Type': 'application/json',
41 | },
42 | body: JSON.stringify({
43 | receiver: '+19137558051',
44 | sender: '+15307224633',
45 | message:
46 | 'I am in need of assistance in this location: 1450 Jayhawk Blvd, Lawrence, KS 66045',
47 | }),
48 | });
49 | };
50 |
51 | handleSendCall = async () => {
52 | fetch('http://13.58.89.149:8000/contacts/api/call/', {
53 | method: 'POST',
54 | headers: {
55 | Accept: 'application/json',
56 | 'Content-Type': 'application/json',
57 | },
58 | body: JSON.stringify({
59 | receiver: '+18167729435',
60 | sender: '+15307224633',
61 | message:
62 | 'I am in need of assistance in this location: 1450 Jayhawk Blvd, Lawrence, KS 66045',
63 | }),
64 | });
65 | fetch('http://13.58.89.149:8000/contacts/api/call/', {
66 | method: 'POST',
67 | headers: {
68 | Accept: 'application/json',
69 | 'Content-Type': 'application/json',
70 | },
71 | body: JSON.stringify({
72 | receiver: '+19134855706',
73 | sender: '+15307224633',
74 | message:
75 | 'I am in need of assistance in this location: 1450 Jayhawk Blvd, Lawrence, KS 66045',
76 | }),
77 | });
78 | fetch('http://13.58.89.149:8000/contacts/api/call/', {
79 | method: 'POST',
80 | headers: {
81 | Accept: 'application/json',
82 | 'Content-Type': 'application/json',
83 | },
84 | body: JSON.stringify({
85 | receiver: '+19137558051',
86 | sender: '+15307224633',
87 | message:
88 | 'I am in need of assistance in this location: 1450 Jayhawk Blvd, Lawrence, KS 66045',
89 | }),
90 | });
91 | };
92 |
93 | render() {
94 | return (
95 |
96 |
100 |
101 |
102 | Press the button to send your location to your buddy and let them
103 | know you need their help.
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | );
118 | }
119 | }
120 |
121 | HelpScreen.navigationOptions = {
122 | header: null,
123 | };
124 |
125 | const styles = StyleSheet.create({
126 | container: {
127 | flex: 1,
128 | backgroundColor: '#fff',
129 | },
130 | contentContainer: {
131 | paddingTop: 30,
132 | },
133 | textContainer: {
134 | alignItems: 'center',
135 | marginHorizontal: 50,
136 | marginBottom: 12,
137 | },
138 | randomText: {
139 | fontSize: 24,
140 | color: 'rgba(0,0,0, 0.87)',
141 | lineHeight: 24,
142 | textAlign: 'center',
143 | },
144 | buttonsContainer: {
145 | alignItems: 'center',
146 | textAlign: 'center',
147 | },
148 | });
149 |
--------------------------------------------------------------------------------
/screens/QuizScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ScrollView, StyleSheet, Text, View } from 'react-native';
3 | import { TouchableOpacity } from 'react-native-gesture-handler';
4 |
5 | import { Button } from '../components/Button';
6 |
7 | const quizData = {
8 | quiz: {
9 | quiz1: {
10 | question1: {
11 | correctoption: 'option1',
12 | options: {
13 | option1: 'Not Tired At All',
14 | option2: 'A Bit Tired',
15 | option3: 'Very Tired',
16 | option4: 'Exhausted',
17 | },
18 | question: 'How tired are you right now?',
19 | },
20 | question2: {
21 | correctoption: 'option4',
22 | options: {
23 | option1: 'XML',
24 | option2: 'YML',
25 | option3: 'HTML',
26 | option4: 'JSX',
27 | },
28 | question: '____ tag syntax is used in React',
29 | },
30 | question3: {
31 | correctoption: 'option1',
32 | options: {
33 | option1: 'Single root DOM node',
34 | option2: 'Double root DOM node',
35 | option3: 'Multiple root DOM node',
36 | option4: 'None of the above',
37 | },
38 | question: 'Application built with just React usually have ____',
39 | },
40 | question4: {
41 | correctoption: 'option2',
42 | options: {
43 | option1: 'mutable',
44 | option2: 'immutable',
45 | option3: 'variable',
46 | option4: 'none of the above',
47 | },
48 | question: 'React elements are ____',
49 | },
50 | question5: {
51 | correctoption: 'option3',
52 | options: {
53 | option1: 'functions',
54 | option2: 'array',
55 | option3: 'components',
56 | option4: 'json data',
57 | },
58 | question:
59 | 'React allows to split UI into independent and reusable pieses of ____',
60 | },
61 | },
62 | },
63 | };
64 |
65 | export default class QuizScreen extends React.Component {
66 | constructor() {
67 | super();
68 | this.state = {
69 | show: true,
70 | show2: false,
71 | show3: false,
72 | show4: false,
73 | tiredScore: 0,
74 | quizFeedback: 'None. Quiz was not taken successfully.',
75 | };
76 | }
77 |
78 | ShowHideComponent = () => {
79 | if (this.state.show == true) {
80 | this.setState({ show: false });
81 | this.setState({ show2: true });
82 | } else if (this.state.show2 == true) {
83 | this.setState({ show2: false });
84 | this.setState({ show3: true });
85 | } else if (this.state.show3 == true) {
86 | this.setState({ show3: false });
87 | this.setState({ show4: true });
88 | }
89 | };
90 |
91 | setQuizFeedback(tiredScore) {
92 | if (tiredScore <= 2) {
93 | this.setState({
94 | quizFeedback:
95 | 'Your results do not indicate that you are too tired to drive. However, use your best judgement and do not drive if you feel too tired.',
96 | });
97 | } else if (tiredScore <= 4) {
98 | this.setState({
99 | quizFeedback:
100 | 'You seem moderately tired. You should take a break before getting back on the road.',
101 | });
102 | } else {
103 | this.setState({
104 | quizFeedback:
105 | 'You are exhausted. It is too dangerous for you to drive. What would you like to do instead?\n\n1. Call a buddy\n2. Call the police\n3. Sleep in your car...?',
106 | });
107 | }
108 | }
109 |
110 | render() {
111 | return (
112 |
113 | {this.state.show ? (
114 |
118 |
119 |
120 |
121 | {quizData.quiz.quiz1.question1.question}
122 |
123 |
124 |
130 |
131 |
132 | {
134 | this.ShowHideComponent();
135 | }}
136 | >
137 |
138 |
139 |
140 | {
142 | this.ShowHideComponent(),
143 | this.setState({ tiredScore: this.state.tiredScore + 1 });
144 | }}
145 | >
146 |
147 |
148 |
149 | {
151 | this.ShowHideComponent(),
152 | this.setState({ tiredScore: this.state.tiredScore + 2 });
153 | }}
154 | >
155 |
156 |
157 |
158 | {
160 | this.ShowHideComponent(),
161 | this.setState({ tiredScore: this.state.tiredScore + 4 });
162 | }}
163 | >
164 |
165 |
166 |
167 |
168 | ) : null}
169 |
170 |
171 | {this.state.show2 ? (
172 |
173 | {
175 | this.ShowHideComponent();
176 | }}
177 | >
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 | {
187 | this.ShowHideComponent(),
188 | this.setState({ tiredScore: this.state.tiredScore + 1 });
189 | }}
190 | >
191 |
192 |
193 |
194 | ) : null}
195 |
196 |
197 |
198 | {this.state.show3 ? (
199 |
200 | {
202 | this.ShowHideComponent(),
203 | this.setState({ tiredScore: this.state.tiredScore + 1 }),
204 | this.setQuizFeedback(this.state.tiredScore);
205 | }}
206 | >
207 |
208 |
209 |
210 |
211 |
212 | 3
213 |
214 |
215 |
216 | {
218 | this.ShowHideComponent(),
219 | this.setQuizFeedback(this.state.tiredScore);
220 | }}
221 | >
222 |
223 |
224 |
225 | ) : null}
226 |
227 |
228 |
229 | {this.state.show4 ? (
230 |
231 |
232 | Your score: {this.state.tiredScore}
233 |
234 |
235 |
236 | {this.state.quizFeedback}
237 |
238 |
239 | ) : null}
240 |
241 |
242 | );
243 | }
244 | }
245 |
246 | QuizScreen.navigationOptions = {
247 | header: null,
248 | };
249 |
250 | const styles = StyleSheet.create({
251 | container: {
252 | flex: 1,
253 | backgroundColor: '#fff',
254 | marginTop: 50,
255 | },
256 | contentContainer: {
257 | paddingTop: 30,
258 | },
259 | welcomeContainer: {
260 | alignItems: 'center',
261 | marginTop: 10,
262 | marginBottom: 20,
263 | },
264 | getStartedContainer: {
265 | alignItems: 'center',
266 | marginHorizontal: 50,
267 | },
268 | quizScreenFilename: {
269 | marginVertical: 7,
270 | },
271 | codeHighlightContainer: {
272 | backgroundColor: 'rgba(0,0,0,0.05)',
273 | borderRadius: 3,
274 | paddingHorizontal: 4,
275 | },
276 | breakText: {
277 | fontSize: 24,
278 | color: 'rgba(0,0,0, 0.87)',
279 | lineHeight: 24,
280 | textAlign: 'center',
281 | },
282 | clockText: {
283 | fontSize: 60,
284 | },
285 | quizText: {
286 | fontSize: 96,
287 | marginTop: 55,
288 | },
289 | quizResultsText: {
290 | fontSize: 24,
291 | marginTop: 110,
292 | },
293 | mainCircleContainer: {
294 | alignItems: 'center',
295 | },
296 | circleContainer: {
297 | backgroundColor: '#00FF55',
298 | borderRadius: 150,
299 | width: 300,
300 | height: 300,
301 | marginTop: 20,
302 | marginBottom: 20,
303 | },
304 | quizTextContainer: {
305 | backgroundColor: '#FFF',
306 | borderRadius: 150,
307 | width: 300,
308 | height: 300,
309 | marginTop: 20,
310 | alignItems: 'center',
311 | },
312 | buttonsContainer: {
313 | alignItems: 'center',
314 | },
315 | });
316 |
--------------------------------------------------------------------------------