Merge pull request #102 from realm/sk-example-app
Improve ReactExample app
This commit is contained in:
commit
5d59040d3d
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -133,6 +133,13 @@
|
||||||
remoteGlobalIDString = 02B29A151B7CF7C9008A7E6B;
|
remoteGlobalIDString = 02B29A151B7CF7C9008A7E6B;
|
||||||
remoteInfo = RealmReact;
|
remoteInfo = RealmReact;
|
||||||
};
|
};
|
||||||
|
F6EA29001BDEEC4B00ECDC7B /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 83CBBA2D1A601D0E00E9B192;
|
||||||
|
remoteInfo = React;
|
||||||
|
};
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
@ -342,9 +349,9 @@
|
||||||
027798471BBB2F1000C96559 /* ReactExampleTests */,
|
027798471BBB2F1000C96559 /* ReactExampleTests */,
|
||||||
83CBBA001A601CBA00E9B192 /* Products */,
|
83CBBA001A601CBA00E9B192 /* Products */,
|
||||||
);
|
);
|
||||||
indentWidth = 2;
|
indentWidth = 4;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
tabWidth = 2;
|
tabWidth = 4;
|
||||||
};
|
};
|
||||||
83CBBA001A601CBA00E9B192 /* Products */ = {
|
83CBBA001A601CBA00E9B192 /* Products */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
|
@ -389,6 +396,7 @@
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
|
F6EA29011BDEEC4B00ECDC7B /* PBXTargetDependency */,
|
||||||
F636F6E31BCDB72D0023F35C /* PBXTargetDependency */,
|
F636F6E31BCDB72D0023F35C /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = ReactExample;
|
name = ReactExample;
|
||||||
|
@ -403,7 +411,7 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 0700;
|
LastUpgradeCheck = 0700;
|
||||||
ORGANIZATIONNAME = Facebook;
|
ORGANIZATIONNAME = Realm;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
027798451BBB2F1000C96559 = {
|
027798451BBB2F1000C96559 = {
|
||||||
CreatedOnToolsVersion = 7.0.1;
|
CreatedOnToolsVersion = 7.0.1;
|
||||||
|
@ -637,6 +645,11 @@
|
||||||
name = RealmReact;
|
name = RealmReact;
|
||||||
targetProxy = F636F6E21BCDB72D0023F35C /* PBXContainerItemProxy */;
|
targetProxy = F636F6E21BCDB72D0023F35C /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
F6EA29011BDEEC4B00ECDC7B /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
name = React;
|
||||||
|
targetProxy = F6EA29001BDEEC4B00ECDC7B /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
/**
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||||
* Copyright (c) 2015-present, Facebook, Inc.
|
* Proprietary and Confidential
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
@ -66,5 +61,4 @@
|
||||||
//XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
|
//XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||||
|
* Proprietary and Confidential
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Realm = require('realm');
|
||||||
|
|
||||||
|
module.exports = new Realm({
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
name: 'Todo',
|
||||||
|
properties: [
|
||||||
|
{name: 'done', type: Realm.Types.BOOL, default: false},
|
||||||
|
{name: 'text', type: Realm.Types.STRING, default: ''},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'TodoList',
|
||||||
|
properties: [
|
||||||
|
{name: 'name', type: Realm.Types.STRING},
|
||||||
|
{name: 'items', type: Realm.Types.LIST, objectType: 'Todo'},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||||
|
* Proprietary and Confidential
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const React = require('react-native');
|
||||||
|
|
||||||
|
module.exports = React.StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'stretch',
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
},
|
||||||
|
navigator: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
listItem: {
|
||||||
|
borderColor: "#c8c7cc",
|
||||||
|
borderBottomWidth: 0.5,
|
||||||
|
alignItems: 'stretch',
|
||||||
|
alignSelf: 'stretch',
|
||||||
|
flexDirection: 'row',
|
||||||
|
flex: 1,
|
||||||
|
height: 44,
|
||||||
|
},
|
||||||
|
listItemLeftSide: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: 36,
|
||||||
|
},
|
||||||
|
listItemCheckbox: {
|
||||||
|
borderColor: '#ccc',
|
||||||
|
borderWidth: 1,
|
||||||
|
textAlign: 'center',
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
lineHeight: 14,
|
||||||
|
},
|
||||||
|
listItemCount: {
|
||||||
|
borderColor: '#ccc',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 8,
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: 12,
|
||||||
|
width: 24,
|
||||||
|
height: 18,
|
||||||
|
lineHeight: 16,
|
||||||
|
},
|
||||||
|
listItemInput: {
|
||||||
|
fontFamily: 'System',
|
||||||
|
fontSize: 15,
|
||||||
|
flexDirection: 'column',
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
listItemText: {
|
||||||
|
fontFamily: 'System',
|
||||||
|
fontSize: 15,
|
||||||
|
flexDirection: 'column',
|
||||||
|
flex: 1,
|
||||||
|
lineHeight: 30,
|
||||||
|
},
|
||||||
|
listItemTextSpecial: {
|
||||||
|
fontStyle: 'italic',
|
||||||
|
},
|
||||||
|
listItemDelete: {
|
||||||
|
paddingLeft: 12,
|
||||||
|
paddingRight: 12,
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
instructions: {
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#333333',
|
||||||
|
marginBottom: 5,
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,125 @@
|
||||||
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||||
|
* Proprietary and Confidential
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const React = require('react-native');
|
||||||
|
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 {
|
||||||
|
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 extraItems = [
|
||||||
|
{name: 'Complete', items: realm.objects('Todo', 'done = true')},
|
||||||
|
{name: 'Incomplete', items: realm.objects('Todo', 'done = false')},
|
||||||
|
];
|
||||||
|
|
||||||
|
let route = {
|
||||||
|
title: 'My Todo Lists',
|
||||||
|
component: TodoListView,
|
||||||
|
passProps: {
|
||||||
|
ref: 'listView',
|
||||||
|
items: this.todoLists,
|
||||||
|
extraItems: extraItems,
|
||||||
|
onPressItem: (list) => this._onPressTodoList(list),
|
||||||
|
},
|
||||||
|
backButtonTitle: 'Lists',
|
||||||
|
rightButtonTitle: 'Add',
|
||||||
|
onRightButtonPress: () => this._addNewTodoList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavigatorIOS ref="nav" initialRoute={route} style={styles.navigator} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_addNewTodoItem(list) {
|
||||||
|
let items = list.items;
|
||||||
|
if (!this._shouldAddNewItem(items)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
realm.write(() => {
|
||||||
|
items.push({text: ''});
|
||||||
|
});
|
||||||
|
|
||||||
|
this._setEditingRow(items.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_addNewTodoList() {
|
||||||
|
let items = this.todoLists;
|
||||||
|
if (!this._shouldAddNewItem(items)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
realm.write(() => {
|
||||||
|
realm.create('TodoList', {name: '', items: []});
|
||||||
|
});
|
||||||
|
|
||||||
|
this._setEditingRow(items.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPressTodoList(list) {
|
||||||
|
let items = list.items;
|
||||||
|
|
||||||
|
let route = {
|
||||||
|
title: list.name,
|
||||||
|
component: TodoListView,
|
||||||
|
passProps: {
|
||||||
|
ref: 'listItemView',
|
||||||
|
items: items,
|
||||||
|
rowClass: TodoItem,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the items are mutable (i.e. List rather than Results).
|
||||||
|
if (items.push) {
|
||||||
|
Object.assign(route, {
|
||||||
|
rightButtonTitle: 'Add',
|
||||||
|
onRightButtonPress: () => this._addNewTodoItem(list),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refs.nav.push(route);
|
||||||
|
}
|
||||||
|
|
||||||
|
_shouldAddNewItem(items) {
|
||||||
|
let editingRow = this.currentListView.state.editingRow;
|
||||||
|
let editingItem = editingRow != null && items[editingRow];
|
||||||
|
|
||||||
|
// Don't allow adding a new item if the one being edited is empty.
|
||||||
|
return !editingItem || !!editingItem.text || !!editingItem.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
_setEditingRow(rowIndex) {
|
||||||
|
// Update the state on the currently displayed TodoList to edit this new item.
|
||||||
|
this.currentListView.setState({editingRow: rowIndex});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TodoApp;
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||||
|
* Proprietary and Confidential
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const React = require('react-native');
|
||||||
|
const TodoListItem = require('./todo-list-item');
|
||||||
|
const realm = require('./realm');
|
||||||
|
const styles = require('./styles');
|
||||||
|
|
||||||
|
const { Text, TouchableWithoutFeedback, View } = React;
|
||||||
|
|
||||||
|
class TodoItem extends TodoListItem {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this._onPressCheckbox = this._onPressCheckbox.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
get done() {
|
||||||
|
return this.props.item.done;
|
||||||
|
}
|
||||||
|
|
||||||
|
set done(done) {
|
||||||
|
this.props.item.done = done;
|
||||||
|
}
|
||||||
|
|
||||||
|
get text() {
|
||||||
|
return this.props.item.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
set text(text) {
|
||||||
|
this.props.item.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLeftSide() {
|
||||||
|
return (
|
||||||
|
<TouchableWithoutFeedback onPress={this._onPressCheckbox}>
|
||||||
|
<View style={styles.listItemLeftSide}>
|
||||||
|
<Text style={styles.listItemCheckbox}>
|
||||||
|
{this.done ? '✓' : ''}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPressCheckbox() {
|
||||||
|
realm.write(() => {
|
||||||
|
this.done = !this.done;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TodoItem;
|
|
@ -0,0 +1,119 @@
|
||||||
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||||
|
* Proprietary and Confidential
|
||||||
|
*/
|
||||||
|
|
||||||
|
'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(extraStyle) {
|
||||||
|
if (this.props.editing) {
|
||||||
|
return (
|
||||||
|
<TextInput
|
||||||
|
ref="input"
|
||||||
|
value={this.text}
|
||||||
|
placeholder="Todo…"
|
||||||
|
style={[styles.listItemInput, extraStyle]}
|
||||||
|
onChangeText={this._onChangeText}
|
||||||
|
onEndEditing={this.props.onEndEditing}
|
||||||
|
enablesReturnKeyAutomatically={true} />
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
style={[styles.listItemText, extraStyle]}
|
||||||
|
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;
|
|
@ -0,0 +1,157 @@
|
||||||
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||||
|
* Proprietary and Confidential
|
||||||
|
*/
|
||||||
|
|
||||||
|
'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({
|
||||||
|
sectionHeaderHasChanged: () => false,
|
||||||
|
rowHasChanged: (row1, row2) => row1 !== row2
|
||||||
|
});
|
||||||
|
|
||||||
|
this.state = {};
|
||||||
|
this.renderRow = this.renderRow.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
let items = this.props.items;
|
||||||
|
let editingRow = this.state.editingRow;
|
||||||
|
|
||||||
|
for (let i = items.length; i--;) {
|
||||||
|
if (i == editingRow) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this._deleteItemIfEmpty(items[i]) && i < editingRow) {
|
||||||
|
editingRow--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editingRow != this.state.editingRow) {
|
||||||
|
this.setState({editingRow});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
// Clone the items into a new Array to prevent unexpected errors from changes in length.
|
||||||
|
let sections = [Array.from(this.props.items)];
|
||||||
|
let extraItems = this.props.extraItems;
|
||||||
|
|
||||||
|
if (extraItems && extraItems.length) {
|
||||||
|
sections.push(extraItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dataSource = this.dataSource.cloneWithRowsAndSections(sections);
|
||||||
|
|
||||||
|
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;
|
||||||
|
let editing = false;
|
||||||
|
|
||||||
|
if (sectionIndex == 0) {
|
||||||
|
RowClass = this.props.rowClass || TodoListItem;
|
||||||
|
editing = this.state.editingRow == rowIndex;
|
||||||
|
} else if (sectionIndex == 1) {
|
||||||
|
RowClass = TodoListExtraItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RowClass
|
||||||
|
item={item}
|
||||||
|
editing={editing}
|
||||||
|
onPress={() => this._onPressRow(item, sectionIndex, rowIndex)}
|
||||||
|
onPressDelete={() => this._onPressDeleteRow(item)}
|
||||||
|
onEndEditing={() => this._onEndEditingRow(item, rowIndex)} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPressRow(item, sectionIndex, rowIndex) {
|
||||||
|
let onPressItem = this.props.onPressItem;
|
||||||
|
if (onPressItem) {
|
||||||
|
onPressItem(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no handler was provided, then default to editing the row.
|
||||||
|
if (sectionIndex == 0) {
|
||||||
|
this.setState({editingRow: rowIndex});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPressDeleteRow(item) {
|
||||||
|
this._deleteItem(item);
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onEndEditingRow(item, rowIndex) {
|
||||||
|
this._deleteItemIfEmpty(item);
|
||||||
|
|
||||||
|
if (this.state.editingRow == rowIndex) {
|
||||||
|
this.setState({editingRow: null});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_deleteItem(item) {
|
||||||
|
let items = item.items;
|
||||||
|
|
||||||
|
realm.write(() => {
|
||||||
|
// If the item is a TodoList, then delete all of its items.
|
||||||
|
if (items && items.length) {
|
||||||
|
realm.delete(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
realm.delete(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_deleteItemIfEmpty(item) {
|
||||||
|
// The item could be a TodoList or a Todo.
|
||||||
|
if (!item.name && !item.text) {
|
||||||
|
this._deleteItem(item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TodoListExtraItem extends TodoListItem {
|
||||||
|
renderText() {
|
||||||
|
return super.renderText(styles.listItemTextSpecial);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLeftSide() {
|
||||||
|
return (
|
||||||
|
<View style={styles.listItemLeftSide}>
|
||||||
|
<Text style={styles.listItemCount}>
|
||||||
|
{this.props.item.items.length}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRightSide() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TodoListView;
|
|
@ -1,10 +1,5 @@
|
||||||
/**
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||||
* Copyright (c) 2015-present, Facebook, Inc.
|
* Proprietary and Confidential
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
/**
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||||
* Copyright (c) 2015-present, Facebook, Inc.
|
* Proprietary and Confidential
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
|
|
|
@ -1,198 +1,10 @@
|
||||||
/**
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||||
* Sample React Native App
|
* Proprietary and Confidential
|
||||||
* https://github.com/facebook/react-native
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Realm = require('realm');
|
const React = require('react-native');
|
||||||
var React = require('react-native');
|
const TodoApp = require('./components/todo-app');
|
||||||
|
|
||||||
var {
|
React.AppRegistry.registerComponent('ReactExample', () => TodoApp);
|
||||||
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,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
Loading…
Reference in New Issue