Refactor and re-style example app

This commit is contained in:
Scott Kyle 2015-10-07 16:20:05 -07:00
parent 0b35564830
commit 549c2ceff7
7 changed files with 276 additions and 195 deletions

View File

@ -0,0 +1,20 @@
{
"env": {
"commonjs": true,
"es6": true
},
"ecmaFeatures": {
"jsx": true
},
"plugins": [
"react"
],
"rules": {
"react/jsx-no-duplicate-props": 2,
"react/jsx-no-undef": 2,
"react/jsx-uses-react": 2,
"react/no-direct-mutation-state": 1,
"react/prefer-es6-class": 1,
"react/react-in-jsx-scope": 2
}
}

View File

@ -0,0 +1,21 @@
'use strict';
const Realm = require('realm');
module.exports = new Realm({
schema: [
{
name: 'Todo',
properties: [
{name: 'text', type: Realm.Types.STRING},
]
},
{
name: 'TodoList',
properties: [
{name: 'name', type: Realm.Types.STRING},
{name: 'items', type: Realm.Types.LIST, objectType: 'Todo'},
]
},
],
});

View File

@ -0,0 +1,34 @@
'use strict';
const React = require('react-native');
module.exports = React.StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'stretch',
backgroundColor: '#ffffff',
},
listItem: {
padding: 12,
borderColor: "#c8c7cc",
borderBottomWidth: 0.5,
alignItems: 'center',
alignSelf: 'stretch',
flexDirection: 'row',
flex: 1,
height: 44,
},
listItemText: {
fontFamily: 'System',
fontSize: 15,
flexDirection: 'column',
flex: 1,
lineHeight: 16,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
}
});

View File

@ -0,0 +1,51 @@
'use strict';
const React = require('react-native');
const TodoList = require('./todo-list');
const realm = require('./realm');
const { NavigatorIOS } = React;
class TodoApp extends React.Component {
componentWillMount() {
let todoLists = realm.objects('TodoList');
if (todoLists.length < 1) {
realm.write(() => {
realm.create('TodoList', {name: 'Todo List', items: []});
});
}
this.todoLists = todoLists;
}
render() {
let list = this.todoLists[0];
let route = {
title: list.name,
component: TodoList,
passProps: {
ref: 'todoList',
list: list,
},
rightButtonTitle: 'Add',
onRightButtonPress: () => this._addNewItem(list)
};
return (
<NavigatorIOS ref="nav" initialRoute={route} style={{flex: 1}} />
);
}
_addNewItem(list) {
realm.write(() => {
list.items.push({text: ''});
});
let todoList = this.refs.nav.refs.todoList;
todoList.setState({editingRow: list.items.length - 1});
}
}
module.exports = TodoApp;

View File

@ -0,0 +1,77 @@
'use strict';
const React = require('react-native');
const realm = require('./realm');
const styles = require('./styles');
const { Text, TextInput, View } = React;
class TodoItem extends React.Component {
constructor(props) {
super(props);
this._onChangeText = this._onChangeText.bind(this);
}
componentDidMount() {
// The autoFocus prop on TextInput was not working for us :(
this._focusInputIfNecessary();
}
componentDidUpdate() {
this._focusInputIfNecessary();
}
render() {
let contents;
if (this.props.editing) {
contents = (
<TextInput
ref="input"
value={this.props.item.text}
placeholder="Call Mom"
style={styles.listItemText}
onChangeText={this._onChangeText}
onEndEditing={this.props.onEndEditing}
enablesReturnKeyAutomatically={true} />
);
} else {
contents = (
<Text
style={styles.listItemText}
onPress={this.props.onPress}
suppressHighlighting={true}>
{this.props.item.text}
</Text>
);
}
return (
<View style={styles.listItem}>
{contents}
</View>
);
}
_onChangeText(text) {
realm.write(() => {
this.props.item.text = text;
});
this.forceUpdate();
}
_focusInputIfNecessary() {
if (!this.props.editing) {
return;
}
let input = this.refs.input;
if (!input.isFocused()) {
input.focus();
}
}
}
module.exports = TodoItem;

View File

@ -0,0 +1,70 @@
'use strict';
const React = require('react-native');
const TodoItem = require('./todo-item');
const realm = require('./realm');
const styles = require('./styles');
const { ListView, Text, View } = React;
class TodoList extends React.Component {
constructor(props) {
super(props);
this.dataSource = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
});
this.state = {};
this._renderRow = this._renderRow.bind(this);
}
render() {
let dataSource = this.dataSource.cloneWithRows(this.props.list.items);
return (
<View style={styles.container}>
<ListView style={styles.listView} dataSource={dataSource} renderRow={this._renderRow} />
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D for dev menu
</Text>
</View>
);
}
_renderRow(item, sectionIndex, rowIndex) {
return (
<TodoItem
item={item}
editing={this.state.editingRow == rowIndex}
onPress={() => this._onPressRow(rowIndex)}
onEndEditing={() => this._onEndEditingRow(rowIndex)} />
);
}
_onPressRow(rowIndex) {
let editingRow = this.state.editingRow;
if (editingRow != null && editingRow != rowIndex) {
this._onEndEditingRow(editingRow);
}
this.setState({editingRow: rowIndex});
}
_onEndEditingRow(rowIndex) {
let items = this.props.list.items;
// Delete the todo item if it doesn't have any text.
if (!items[rowIndex].text) {
realm.write(() => items.splice(rowIndex, 1));
}
if (this.state.editingRow == rowIndex) {
this.setState({editingRow: null});
}
}
}
module.exports = TodoList;

View File

@ -1,198 +1,6 @@
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
'use strict';
var Realm = require('realm');
var React = require('react-native');
const React = require('react-native');
const TodoApp = require('./components/todo-app');
var {
AppRegistry,
StyleSheet,
NavigatorIOS,
AlertIOS,
ListView,
TouchableHighlight,
Text,
TextInput,
View,
} = React;
var TodoItemSchema = {
name: 'Todo',
properties: [
{name: 'text', type: Realm.Types.STRING},
]
};
var TodoListSchmea = {
name: 'TodoList',
properties: [
{name: 'name', type: Realm.Types.STRING},
{name: 'items', type: Realm.Types.LIST, objectType: 'Todo'}
]
};
console.log(Realm.defaultPath);
var realm = new Realm({schema: [TodoItemSchema, TodoListSchmea]});
class Edit extends React.Component {
componentWillMount() {
this.setState({text: this.props.text});
}
save() {
realm.write(function () {
if (this.props.todoId == this.props.list.items.length) {
this.props.list.items.push({text: this.state.text});
}
else {
var todoItem = this.props.list.items[this.props.todoId];
todoItem.text = this.state.text;
}
}.bind(this));
// should not be needed once we have notifications
this.props.parent.updateDataSource();
this.props.navigator.pop();
}
render() {
return (
<View style={{flex:1, justifyContent: 'flex-start'}}>
<TextInput multiline={true} style={styles.textInput}
placeholder='Enter Todo' autoFocus={true}
onChangeText={(text) => this.setState({text})} value={this.state.text}/>
<TouchableHighlight
style={styles.button}
onPress={this.save.bind(this)}
underlayColor='#99d9f4'>
<Text style={styles.buttonText}>Save</Text>
</TouchableHighlight>
</View>
)
}
};
class TodoList extends React.Component {
componentWillMount() {
this.lists = realm.objects('TodoList');
if (this.lists.length < 1) {
realm.write(function() {
realm.create('TodoList', ['List', []]);
});
}
this.list = this.lists[0];
this.menu = this.menu.bind(this);
this.delete = this.delete.bind(this);
var dataSource = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
});
this.updateDataSource(dataSource);
}
updateDataSource(oldDataSource) {
if (!oldDataSource) {
oldDataSource = this.state.dataSource;
}
this.setState({dataSource: oldDataSource.cloneWithRows(this.list.items)});
}
menu(todo, todoID) {
AlertIOS.alert(
todo.text,
todoID,
[
{text: 'Complete', onPress: () => this.delete(todoID)},
{text: 'Edit', onPress: () => this.edit(todoID, todo.text)},
{text: 'Cancel'}
]
)
}
delete(todoID) {
var item = this.list.items[todoID];
realm.write(function() {
realm.delete(item);
})
this.updateDataSource();
}
edit(todoId, text) {
this.props.navigator.push({
title: text,
component: Edit,
passProps: {list: this.list, todoId: todoId, text: text, parent: this}
});
}
render() {
return (
<View style={styles.container}>
<ListView style={styles.listView} dataSource={this.state.dataSource} renderRow={(rowData, sectionID, rowID) =>
<TouchableHighlight style={styles.listItem} onPress={() => this.menu(rowData, rowID)}>
<Text>{rowData.text}</Text>
</TouchableHighlight>
}/>
<TouchableHighlight style={styles.button}
onPress={() => this.edit(this.list.items.length, "")}>
<Text style={styles.buttonText}>+</Text>
</TouchableHighlight>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+Control+Z for dev menu
</Text>
</View>
);
}
};
class Navigator extends React.Component {
render() {
return (
<NavigatorIOS initialRoute={{component: TodoList, title: 'Todo Items'}} style={{flex:1}}/>
);
}
};
AppRegistry.registerComponent('ReactExample', () => Navigator);
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'stretch',
backgroundColor: '#ffffff',
},
listItem: {
marginTop: 3,
padding: 6,
backgroundColor:'#ACACAC',
alignSelf: 'stretch',
flexDirection: 'row',
flex:1,
},
textInput: {
alignSelf: 'stretch',
borderWidth: 0.5,
borderColor: '#0f0f0f',
height: 200,
fontSize: 13,
margin: 6,
marginTop: 70,
padding: 4,
},
button: {
height: 36,
backgroundColor: '#48BBEC',
alignSelf: 'stretch',
justifyContent: 'center'
},
buttonText: {
alignSelf: 'center',
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
}
});
React.AppRegistry.registerComponent('ReactExample', () => TodoApp);