mirror of
https://github.com/status-im/realm-js.git
synced 2025-01-22 20:41:18 +00:00
Example app can now have multiple todo lists
This commit is contained in:
parent
e90715140b
commit
6fc2110991
@ -9,6 +9,9 @@ module.exports = React.StyleSheet.create({
|
||||
alignItems: 'stretch',
|
||||
backgroundColor: '#ffffff',
|
||||
},
|
||||
navigator: {
|
||||
flex: 1,
|
||||
},
|
||||
listItem: {
|
||||
borderColor: "#c8c7cc",
|
||||
borderBottomWidth: 0.5,
|
||||
@ -18,16 +21,15 @@ module.exports = React.StyleSheet.create({
|
||||
flex: 1,
|
||||
height: 44,
|
||||
},
|
||||
listItemCheckboxContainer: {
|
||||
paddingLeft: 12,
|
||||
paddingRight: 4,
|
||||
listItemLeftSide: {
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: 36,
|
||||
},
|
||||
listItemCheckbox: {
|
||||
borderColor: "#000",
|
||||
borderWidth: 0.5,
|
||||
marginRight: 8,
|
||||
width: 16,
|
||||
height: 16,
|
||||
},
|
||||
|
@ -1,50 +1,85 @@
|
||||
'use strict';
|
||||
|
||||
const React = require('react-native');
|
||||
const TodoList = require('./todo-list');
|
||||
const TodoItem = require('./todo-item');
|
||||
const TodoListView = require('./todo-listview');
|
||||
const realm = require('./realm');
|
||||
const styles = require('./styles');
|
||||
|
||||
const { NavigatorIOS } = React;
|
||||
|
||||
class TodoApp extends React.Component {
|
||||
componentWillMount() {
|
||||
let todoLists = realm.objects('TodoList');
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
let todoLists = realm.objects('TodoList');
|
||||
if (todoLists.length < 1) {
|
||||
realm.write(() => {
|
||||
realm.create('TodoList', {name: 'Todo List', items: []});
|
||||
});
|
||||
}
|
||||
|
||||
// This is a Results object, which will live-update.
|
||||
this.todoLists = todoLists;
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
get currentListView() {
|
||||
let refs = this.refs.nav.refs;
|
||||
return refs.listItemView || refs.listView;
|
||||
}
|
||||
|
||||
render() {
|
||||
let list = this.todoLists[0];
|
||||
|
||||
let route = {
|
||||
title: list.name,
|
||||
component: TodoList,
|
||||
title: 'My Todo Lists',
|
||||
component: TodoListView,
|
||||
passProps: {
|
||||
ref: 'todoList',
|
||||
list: list,
|
||||
ref: 'listView',
|
||||
items: this.todoLists,
|
||||
onPressItem: (list) => this._onPressTodoList(list),
|
||||
},
|
||||
rightButtonTitle: 'Add',
|
||||
onRightButtonPress: () => this._addNewItem(list)
|
||||
onRightButtonPress: () => this._addNewTodoList(),
|
||||
};
|
||||
|
||||
return (
|
||||
<NavigatorIOS ref="nav" initialRoute={route} style={{flex: 1}} />
|
||||
<NavigatorIOS ref="nav" initialRoute={route} style={styles.navigator} />
|
||||
);
|
||||
}
|
||||
|
||||
_addNewItem(list) {
|
||||
_addNewTodoItem(list) {
|
||||
realm.write(() => {
|
||||
list.items.push({text: ''});
|
||||
});
|
||||
|
||||
let todoList = this.refs.nav.refs.todoList;
|
||||
todoList.setState({editingRow: list.items.length - 1});
|
||||
this._setEditingRow(list.items.length - 1);
|
||||
}
|
||||
|
||||
_addNewTodoList() {
|
||||
realm.write(() => {
|
||||
realm.create('TodoList', {name: '', items: []});
|
||||
});
|
||||
|
||||
this._setEditingRow(this.todoLists.length - 1);
|
||||
}
|
||||
|
||||
_onPressTodoList(list) {
|
||||
this.refs.nav.push({
|
||||
title: list.name,
|
||||
component: TodoListView,
|
||||
passProps: {
|
||||
ref: 'listItemView',
|
||||
items: list.items,
|
||||
rowClass: TodoItem,
|
||||
},
|
||||
rightButtonTitle: 'Add',
|
||||
onRightButtonPress: () => this._addNewTodoItem(list),
|
||||
});
|
||||
}
|
||||
|
||||
_setEditingRow(rowIndex) {
|
||||
// Update the state on the currently displayed TodoList to edit this new item.
|
||||
this.currentListView.setState({editingRow: rowIndex});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,22 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const React = require('react-native');
|
||||
const styles = require('./styles');
|
||||
|
||||
const { Text, TouchableWithoutFeedback, View } = React;
|
||||
|
||||
class TodoItemCheckbox extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={this.props.onPress}>
|
||||
<View style={styles.listItemCheckboxContainer}>
|
||||
<View style={styles.listItemCheckbox}>
|
||||
<Text>{this.props.checked ? '✓' : ''}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TodoItemCheckbox;
|
@ -1,20 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const React = require('react-native');
|
||||
const styles = require('./styles');
|
||||
|
||||
const { Text, TouchableWithoutFeedback, View } = React;
|
||||
|
||||
class TodoItemDelete extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={this.props.onPress}>
|
||||
<View style={styles.listItemDelete}>
|
||||
<Text>𐄂</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TodoItemDelete;
|
@ -1,97 +1,54 @@
|
||||
'use strict';
|
||||
|
||||
const React = require('react-native');
|
||||
const TodoItemCheckbox = require('./todo-item-checkbox');
|
||||
const TodoItemDelete = require('./todo-item-delete');
|
||||
const TodoListItem = require('./todo-list-item');
|
||||
const realm = require('./realm');
|
||||
const styles = require('./styles');
|
||||
|
||||
const { Text, TextInput, View } = React;
|
||||
const { Text, TouchableWithoutFeedback, View } = React;
|
||||
|
||||
class TodoItem extends React.Component {
|
||||
class TodoItem extends TodoListItem {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._onChangeText = this._onChangeText.bind(this);
|
||||
this._onPressCheckbox = this._onPressCheckbox.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// The autoFocus prop on TextInput was not working for us :(
|
||||
this._focusInputIfNecessary();
|
||||
get done() {
|
||||
return this.props.item.done;
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this._focusInputIfNecessary();
|
||||
set done(done) {
|
||||
this.props.item.done = done;
|
||||
}
|
||||
|
||||
render() {
|
||||
let item = this.props.item;
|
||||
let deleteButton;
|
||||
let contents;
|
||||
get text() {
|
||||
return this.props.item.text;
|
||||
}
|
||||
|
||||
if (this.props.editing) {
|
||||
contents = (
|
||||
<TextInput
|
||||
ref="input"
|
||||
value={item.text}
|
||||
placeholder="Call Mom"
|
||||
style={styles.listItemInput}
|
||||
onChangeText={this._onChangeText}
|
||||
onEndEditing={this.props.onEndEditing}
|
||||
enablesReturnKeyAutomatically={true} />
|
||||
);
|
||||
} else {
|
||||
contents = (
|
||||
<Text
|
||||
style={styles.listItemText}
|
||||
onPress={this.props.onPress}
|
||||
suppressHighlighting={true}>
|
||||
{item.text}
|
||||
</Text>
|
||||
);
|
||||
|
||||
deleteButton = (
|
||||
<TodoItemDelete onPress={this.props.onPressDelete} />
|
||||
);
|
||||
}
|
||||
set text(text) {
|
||||
this.props.item.text = text;
|
||||
}
|
||||
|
||||
renderLeftSide() {
|
||||
return (
|
||||
<View style={styles.listItem}>
|
||||
<TodoItemCheckbox checked={item.done} onPress={this._onPressCheckbox} />
|
||||
{contents}
|
||||
{deleteButton}
|
||||
</View>
|
||||
<TouchableWithoutFeedback onPress={this._onPressCheckbox}>
|
||||
<View style={styles.listItemLeftSide}>
|
||||
<View style={styles.listItemCheckbox}>
|
||||
<Text>{this.done ? '✓' : ''}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
}
|
||||
|
||||
_onChangeText(text) {
|
||||
realm.write(() => {
|
||||
this.props.item.text = text;
|
||||
});
|
||||
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
_onPressCheckbox() {
|
||||
let item = this.props.item;
|
||||
realm.write(() => {
|
||||
item.done = !item.done;
|
||||
this.done = !this.done;
|
||||
});
|
||||
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
_focusInputIfNecessary() {
|
||||
if (!this.props.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
let input = this.refs.input;
|
||||
if (!input.isFocused()) {
|
||||
input.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TodoItem;
|
||||
|
115
examples/ReactExample/components/todo-list-item.js
Normal file
115
examples/ReactExample/components/todo-list-item.js
Normal file
@ -0,0 +1,115 @@
|
||||
'use strict';
|
||||
|
||||
const React = require('react-native');
|
||||
const realm = require('./realm');
|
||||
const styles = require('./styles');
|
||||
|
||||
const { Text, TextInput, TouchableWithoutFeedback, View } = React;
|
||||
|
||||
class TodoListItem extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._onChangeText = this._onChangeText.bind(this);
|
||||
}
|
||||
|
||||
get done() {
|
||||
let items = this.props.item.items;
|
||||
return items.length > 0 && Array.prototype.every.call(items, (item) => item.done);
|
||||
}
|
||||
|
||||
get text() {
|
||||
return this.props.item.name;
|
||||
}
|
||||
|
||||
set text(text) {
|
||||
this.props.item.name = text;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// The autoFocus prop on TextInput was not working for us :(
|
||||
this._focusInputIfNecessary();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this._focusInputIfNecessary();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.listItem}>
|
||||
{this.renderLeftSide()}
|
||||
{this.renderText()}
|
||||
{this.renderRightSide()}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
renderLeftSide() {
|
||||
return (
|
||||
<View style={styles.listItemLeftSide}>
|
||||
<Text>{this.done ? '✓' : '⁃'}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
renderRightSide() {
|
||||
// Only show the delete button while not editing the text.
|
||||
return this.props.editing ? null : this.renderDelete();
|
||||
}
|
||||
|
||||
renderText() {
|
||||
if (this.props.editing) {
|
||||
return (
|
||||
<TextInput
|
||||
ref="input"
|
||||
value={this.text}
|
||||
placeholder="Call Mom"
|
||||
style={styles.listItemInput}
|
||||
onChangeText={this._onChangeText}
|
||||
onEndEditing={this.props.onEndEditing}
|
||||
enablesReturnKeyAutomatically={true} />
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Text
|
||||
style={styles.listItemText}
|
||||
onPress={this.props.onPress}
|
||||
suppressHighlighting={true}>
|
||||
{this.text}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderDelete() {
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={this.props.onPressDelete}>
|
||||
<View style={styles.listItemDelete}>
|
||||
<Text>𐄂</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
}
|
||||
|
||||
_onChangeText(text) {
|
||||
realm.write(() => {
|
||||
this.text = text;
|
||||
});
|
||||
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
_focusInputIfNecessary() {
|
||||
if (!this.props.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
let input = this.refs.input;
|
||||
if (!input.isFocused()) {
|
||||
input.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TodoListItem;
|
@ -1,79 +0,0 @@
|
||||
'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)}
|
||||
onPressDelete={() => this._onPressDeleteRow(rowIndex)}
|
||||
onEndEditing={() => this._onEndEditingRow(rowIndex)} />
|
||||
);
|
||||
}
|
||||
|
||||
_onPressRow(rowIndex) {
|
||||
let editingRow = this.state.editingRow;
|
||||
|
||||
if (editingRow != null && editingRow != rowIndex) {
|
||||
this._onEndEditingRow(editingRow);
|
||||
}
|
||||
|
||||
this.setState({editingRow: rowIndex});
|
||||
}
|
||||
|
||||
_onPressDeleteRow(rowIndex) {
|
||||
let items = this.props.list.items;
|
||||
|
||||
realm.write(() => items.splice(rowIndex, 1));
|
||||
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
_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;
|
97
examples/ReactExample/components/todo-listview.js
Normal file
97
examples/ReactExample/components/todo-listview.js
Normal file
@ -0,0 +1,97 @@
|
||||
'use strict';
|
||||
|
||||
const React = require('react-native');
|
||||
const TodoListItem = require('./todo-list-item');
|
||||
const realm = require('./realm');
|
||||
const styles = require('./styles');
|
||||
|
||||
const { ListView, Text, View } = React;
|
||||
|
||||
class TodoListView 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);
|
||||
}
|
||||
|
||||
componentWillUpdate(nextProps, nextState) {
|
||||
let editingRow = this.state.editingRow;
|
||||
|
||||
if (editingRow != null && editingRow != nextState.editingRow) {
|
||||
let item = this.props.items[editingRow];
|
||||
|
||||
// The item may have already been deleted.
|
||||
if (item) {
|
||||
this._deleteItemIfEmpty(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
// Clone the items into a new Array to prevent unexpected errors from changes in length.
|
||||
let items = Array.from(this.props.items);
|
||||
let dataSource = this.dataSource.cloneWithRows(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) {
|
||||
let RowClass = this.props.rowClass || TodoListItem;
|
||||
|
||||
return (
|
||||
<RowClass
|
||||
item={item}
|
||||
editing={this.state.editingRow == rowIndex}
|
||||
onPress={() => this._onPressRow(item, rowIndex)}
|
||||
onPressDelete={() => this._onPressDeleteRow(item, rowIndex)}
|
||||
onEndEditing={() => this._onEndEditingRow(item, rowIndex)} />
|
||||
);
|
||||
}
|
||||
|
||||
_onPressRow(item, rowIndex) {
|
||||
let onPressItem = this.props.onPressItem;
|
||||
if (onPressItem) {
|
||||
onPressItem(item, rowIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
// If no handler was provided, then default to editing the row.
|
||||
this.setState({editingRow: rowIndex});
|
||||
}
|
||||
|
||||
_onPressDeleteRow(item) {
|
||||
realm.write(() => realm.delete(item));
|
||||
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
_onEndEditingRow(item, rowIndex) {
|
||||
this._deleteItemIfEmpty(item);
|
||||
|
||||
if (this.state.editingRow == rowIndex) {
|
||||
this.setState({editingRow: null});
|
||||
}
|
||||
}
|
||||
|
||||
_deleteItemIfEmpty(item) {
|
||||
// The item could be a TodoList or a Todo.
|
||||
if (!item.name && !item.text) {
|
||||
realm.write(() => realm.delete(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TodoListView;
|
Loading…
x
Reference in New Issue
Block a user