├── .gitignore
├── .watchmanconfig
├── App.js
├── app.json
├── assets
├── icon.png
└── splash.png
├── babel.config.js
├── components
├── Header.js
├── InputBar.js
└── TodoItem.js
├── package-lock.json
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p12
6 | *.key
7 | *.mobileprovision
8 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Platform, StyleSheet, Text, View, FlatList } from 'react-native';
3 | import Header from './components/Header';
4 | import InputBar from './components/InputBar';
5 | import TodoItem from './components/TodoItem';
6 |
7 | export default class App extends React.Component {
8 | constructor () {
9 | super();
10 |
11 | this.state = {
12 | todoInput: '',
13 | todos: [
14 | { id: 0, title: 'Take out the trash', done: false },
15 | { id: 1, title: 'Cook dinner', done: false }
16 | ]
17 | }
18 | }
19 |
20 | addNewTodo () {
21 | let todos = this.state.todos;
22 |
23 | todos.unshift({
24 | id: todos.length + 1,
25 | title: this.state.todoInput,
26 | done: false
27 | });
28 |
29 | this.setState({
30 | todos: todos,
31 | todoInput: ''
32 | });
33 | }
34 |
35 | toggleDone (item) {
36 | let todos = this.state.todos;
37 |
38 | todos = todos.map((todo) => {
39 | if (todo.id == item.id) {
40 | todo.done = !todo.done;
41 | }
42 |
43 | return todo;
44 | })
45 |
46 | this.setState({todos});
47 | }
48 |
49 | removeTodo (item) {
50 | let todos = this.state.todos;
51 |
52 | todos = todos.filter((todo) => todo.id !== item.id);
53 |
54 | this.setState({todos});
55 | }
56 |
57 | render() {
58 | const statusbar = (Platform.OS == 'ios') ? : ;
59 |
60 | return (
61 |
62 | {statusbar}
63 |
64 |
65 |
66 | this.addNewTodo()}
68 | textChange={todoInput => this.setState({ todoInput })}
69 | todoInput={this.state.todoInput}
70 | />
71 |
72 | index.toString()}
76 | renderItem={({item, index}) => {
77 | return (
78 | this.toggleDone(item)} removeTodo={() => this.removeTodo(item)} />
79 | )
80 | }}
81 | />
82 |
83 | );
84 | }
85 | }
86 |
87 | const styles = StyleSheet.create({
88 | container: {
89 | flex: 1,
90 | backgroundColor: '#fff',
91 | },
92 | statusbar: {
93 | backgroundColor: '#FFCE00',
94 | height: 20
95 | }
96 | });
97 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "React Native Todo application",
4 | "slug": "todo-app",
5 | "privacy": "public",
6 | "sdkVersion": "32.0.0",
7 | "platforms": [
8 | "ios",
9 | "android"
10 | ],
11 | "version": "1.0.0",
12 | "orientation": "portrait",
13 | "icon": "./assets/icon.png",
14 | "splash": {
15 | "image": "./assets/splash.png",
16 | "resizeMode": "contain",
17 | "backgroundColor": "#ffffff"
18 | },
19 | "updates": {
20 | "fallbackToCacheTimeout": 0
21 | },
22 | "assetBundlePatterns": [
23 | "**/*"
24 | ],
25 | "ios": {
26 | "supportsTablet": true
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TylerPottsDev/react-native-todo-app/a25c7d57672258d8868602c1185bd5b91c5bb2cd/assets/icon.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TylerPottsDev/react-native-todo-app/a25c7d57672258d8868602c1185bd5b91c5bb2cd/assets/splash.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/components/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet, Text, View } from 'react-native';
3 |
4 | const Header = (props) => {
5 | return (
6 |
7 | { props.title }
8 |
9 | )
10 | }
11 |
12 | const styles = StyleSheet.create({
13 | header: {
14 | backgroundColor: '#171717',
15 | height: 60,
16 | alignItems: 'center',
17 | justifyContent: 'center'
18 | },
19 | title: {
20 | color: '#F3F3F3',
21 | fontSize: 28,
22 | fontWeight: '900',
23 | textTransform: 'uppercase'
24 | }
25 | });
26 |
27 | export default Header;
--------------------------------------------------------------------------------
/components/InputBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet, Text, View, TextInput, TouchableOpacity } from 'react-native';
3 |
4 | const InputBar = (props) => {
5 | return (
6 |
7 | props.textChange(todoInput)}
10 | value={props.todoInput}
11 | />
12 |
13 | ADD
14 |
15 |
16 | )
17 | }
18 |
19 | const styles = StyleSheet.create({
20 | inputContainer: {
21 | flexDirection: 'row',
22 | justifyContent: 'space-between',
23 | shadowOffset: { width: 0, height: 3 },
24 | shadowColor: '#171717',
25 | shadowOpacity: .1
26 | },
27 | input: {
28 | backgroundColor: '#F3F3F3',
29 | flex: 1,
30 | fontSize: 18,
31 | height: 35
32 | },
33 | addButton: {
34 | width: 100,
35 | backgroundColor: '#FFCE00',
36 | alignItems: 'center',
37 | justifyContent: 'center'
38 | },
39 | addButtonText: {
40 | color: '#171717',
41 | fontSize: 18,
42 | fontWeight: '700'
43 | }
44 | })
45 |
46 | export default InputBar;
--------------------------------------------------------------------------------
/components/TodoItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet, Text, Button, TouchableOpacity } from 'react-native';
3 |
4 | export default class TodoItem extends React.Component {
5 | constructor (props) {
6 | super(props);
7 | }
8 |
9 | render () {
10 | const todoItem = this.props.todoItem;
11 |
12 | return (
13 | this.props.toggleDone()}
16 | >
17 |
18 | { todoItem.title }
19 |
20 |
21 |
27 | )
28 | }
29 | }
30 |
31 | const styles = StyleSheet.create({
32 | todoItem: {
33 | width: '100%',
34 | height: 40,
35 | borderBottomColor: '#DDD',
36 | borderBottomWidth: 1,
37 | flexDirection: 'row',
38 | alignItems: 'center',
39 | justifyContent: 'space-between',
40 | paddingLeft: 15
41 | }
42 | })
--------------------------------------------------------------------------------
/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 | },
9 | "dependencies": {
10 | "expo": "^32.0.0",
11 | "react": "16.5.0",
12 | "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz"
13 | },
14 | "devDependencies": {
15 | "babel-preset-expo": "^5.0.0"
16 | },
17 | "private": true
18 | }
19 |
--------------------------------------------------------------------------------