From 549c2ceff7cf747b523e7fa77686566ba4c30800 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Wed, 7 Oct 2015 16:20:05 -0700 Subject: [PATCH 01/11] Refactor and re-style example app --- examples/ReactExample/.eslintrc | 20 ++ examples/ReactExample/components/realm.js | 21 ++ examples/ReactExample/components/styles.js | 34 +++ examples/ReactExample/components/todo-app.js | 51 +++++ examples/ReactExample/components/todo-item.js | 77 +++++++ examples/ReactExample/components/todo-list.js | 70 +++++++ examples/ReactExample/index.ios.js | 198 +----------------- 7 files changed, 276 insertions(+), 195 deletions(-) create mode 100644 examples/ReactExample/.eslintrc create mode 100644 examples/ReactExample/components/realm.js create mode 100644 examples/ReactExample/components/styles.js create mode 100644 examples/ReactExample/components/todo-app.js create mode 100644 examples/ReactExample/components/todo-item.js create mode 100644 examples/ReactExample/components/todo-list.js diff --git a/examples/ReactExample/.eslintrc b/examples/ReactExample/.eslintrc new file mode 100644 index 00000000..98b5f8ba --- /dev/null +++ b/examples/ReactExample/.eslintrc @@ -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 + } +} diff --git a/examples/ReactExample/components/realm.js b/examples/ReactExample/components/realm.js new file mode 100644 index 00000000..7a62e345 --- /dev/null +++ b/examples/ReactExample/components/realm.js @@ -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'}, + ] + }, + ], +}); diff --git a/examples/ReactExample/components/styles.js b/examples/ReactExample/components/styles.js new file mode 100644 index 00000000..d02ea704 --- /dev/null +++ b/examples/ReactExample/components/styles.js @@ -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, + } +}); diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js new file mode 100644 index 00000000..afebfc09 --- /dev/null +++ b/examples/ReactExample/components/todo-app.js @@ -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 ( + + ); + } + + _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; diff --git a/examples/ReactExample/components/todo-item.js b/examples/ReactExample/components/todo-item.js new file mode 100644 index 00000000..1ca68343 --- /dev/null +++ b/examples/ReactExample/components/todo-item.js @@ -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 = ( + + ); + } else { + contents = ( + + {this.props.item.text} + + ); + } + + return ( + + {contents} + + ); + } + + _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; diff --git a/examples/ReactExample/components/todo-list.js b/examples/ReactExample/components/todo-list.js new file mode 100644 index 00000000..c292f2d9 --- /dev/null +++ b/examples/ReactExample/components/todo-list.js @@ -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 ( + + + + Press Cmd+R to reload,{'\n'} + Cmd+D for dev menu + + + ); + } + + _renderRow(item, sectionIndex, rowIndex) { + return ( + 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; diff --git a/examples/ReactExample/index.ios.js b/examples/ReactExample/index.ios.js index 4fd74391..e051fe32 100644 --- a/examples/ReactExample/index.ios.js +++ b/examples/ReactExample/index.ios.js @@ -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 ( - - this.setState({text})} value={this.state.text}/> - - Save - - - ) - } -}; - -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 ( - - - this.menu(rowData, rowID)}> - {rowData.text} - - }/> - this.edit(this.list.items.length, "")}> - + - - - Press Cmd+R to reload,{'\n'} - Cmd+Control+Z for dev menu - - - ); - } -}; - -class Navigator extends React.Component { - render() { - return ( - - ); - } -}; -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); From f89c44697a530f4d5e344c2db659e27859520710 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Mon, 26 Oct 2015 12:10:40 -0700 Subject: [PATCH 02/11] Add checkboxes next to todo items in Example app --- examples/ReactExample/components/realm.js | 3 ++- examples/ReactExample/components/styles.js | 25 ++++++++++++++++--- .../components/todo-item-checkbox.js | 22 ++++++++++++++++ examples/ReactExample/components/todo-item.js | 19 +++++++++++--- 4 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 examples/ReactExample/components/todo-item-checkbox.js diff --git a/examples/ReactExample/components/realm.js b/examples/ReactExample/components/realm.js index 7a62e345..d1b172b7 100644 --- a/examples/ReactExample/components/realm.js +++ b/examples/ReactExample/components/realm.js @@ -7,7 +7,8 @@ module.exports = new Realm({ { name: 'Todo', properties: [ - {name: 'text', type: Realm.Types.STRING}, + {name: 'done', type: Realm.Types.BOOL, default: false}, + {name: 'text', type: Realm.Types.STRING, default: ''}, ] }, { diff --git a/examples/ReactExample/components/styles.js b/examples/ReactExample/components/styles.js index d02ea704..798b9eef 100644 --- a/examples/ReactExample/components/styles.js +++ b/examples/ReactExample/components/styles.js @@ -10,21 +10,40 @@ module.exports = React.StyleSheet.create({ backgroundColor: '#ffffff', }, listItem: { - padding: 12, + paddingRight: 12, borderColor: "#c8c7cc", borderBottomWidth: 0.5, - alignItems: 'center', + alignItems: 'stretch', alignSelf: 'stretch', flexDirection: 'row', flex: 1, height: 44, }, + listItemCheckboxContainer: { + paddingLeft: 12, + paddingRight: 4, + flexDirection: 'column', + justifyContent: 'center', + }, + listItemCheckbox: { + borderColor: "#000", + borderWidth: 0.5, + marginRight: 8, + width: 16, + height: 16, + }, + listItemInput: { + fontFamily: 'System', + fontSize: 15, + flexDirection: 'column', + flex: 1, + }, listItemText: { fontFamily: 'System', fontSize: 15, flexDirection: 'column', flex: 1, - lineHeight: 16, + lineHeight: 30, }, instructions: { textAlign: 'center', diff --git a/examples/ReactExample/components/todo-item-checkbox.js b/examples/ReactExample/components/todo-item-checkbox.js new file mode 100644 index 00000000..6cfbd3cf --- /dev/null +++ b/examples/ReactExample/components/todo-item-checkbox.js @@ -0,0 +1,22 @@ +'use strict'; + +const React = require('react-native'); +const styles = require('./styles'); + +const { Text, TouchableWithoutFeedback, View } = React; + +class TodoItemCheckbox extends React.Component { + render() { + return ( + + + + {this.props.checked ? 'βœ“' : ''} + + + + ); + } +} + +module.exports = TodoItemCheckbox; diff --git a/examples/ReactExample/components/todo-item.js b/examples/ReactExample/components/todo-item.js index 1ca68343..710fd537 100644 --- a/examples/ReactExample/components/todo-item.js +++ b/examples/ReactExample/components/todo-item.js @@ -1,6 +1,7 @@ 'use strict'; const React = require('react-native'); +const TodoItemCheckbox = require('./todo-item-checkbox'); const realm = require('./realm'); const styles = require('./styles'); @@ -11,6 +12,7 @@ class TodoItem extends React.Component { super(props); this._onChangeText = this._onChangeText.bind(this); + this._onPressCheckbox = this._onPressCheckbox.bind(this); } componentDidMount() { @@ -23,15 +25,16 @@ class TodoItem extends React.Component { } render() { + let item = this.props.item; let contents; if (this.props.editing) { contents = ( @@ -42,13 +45,14 @@ class TodoItem extends React.Component { style={styles.listItemText} onPress={this.props.onPress} suppressHighlighting={true}> - {this.props.item.text} + {item.text} ); } return ( + {contents} ); @@ -62,6 +66,15 @@ class TodoItem extends React.Component { this.forceUpdate(); } + _onPressCheckbox() { + let item = this.props.item; + realm.write(() => { + item.done = !item.done; + }); + + this.forceUpdate(); + } + _focusInputIfNecessary() { if (!this.props.editing) { return; From 8c680ffbf6300af56abf425598f6ddeedf7d1281 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Mon, 26 Oct 2015 17:13:33 -0700 Subject: [PATCH 03/11] Add delete buttons for todo items in Example app --- examples/ReactExample/components/styles.js | 7 ++++++- .../components/todo-item-delete.js | 20 +++++++++++++++++++ examples/ReactExample/components/todo-item.js | 7 +++++++ examples/ReactExample/components/todo-list.js | 9 +++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 examples/ReactExample/components/todo-item-delete.js diff --git a/examples/ReactExample/components/styles.js b/examples/ReactExample/components/styles.js index 798b9eef..47bab8a4 100644 --- a/examples/ReactExample/components/styles.js +++ b/examples/ReactExample/components/styles.js @@ -10,7 +10,6 @@ module.exports = React.StyleSheet.create({ backgroundColor: '#ffffff', }, listItem: { - paddingRight: 12, borderColor: "#c8c7cc", borderBottomWidth: 0.5, alignItems: 'stretch', @@ -45,6 +44,12 @@ module.exports = React.StyleSheet.create({ flex: 1, lineHeight: 30, }, + listItemDelete: { + paddingLeft: 12, + paddingRight: 12, + flexDirection: 'column', + justifyContent: 'center', + }, instructions: { textAlign: 'center', color: '#333333', diff --git a/examples/ReactExample/components/todo-item-delete.js b/examples/ReactExample/components/todo-item-delete.js new file mode 100644 index 00000000..4a260d4b --- /dev/null +++ b/examples/ReactExample/components/todo-item-delete.js @@ -0,0 +1,20 @@ +'use strict'; + +const React = require('react-native'); +const styles = require('./styles'); + +const { Text, TouchableWithoutFeedback, View } = React; + +class TodoItemDelete extends React.Component { + render() { + return ( + + + 𐄂 + + + ); + } +} + +module.exports = TodoItemDelete; diff --git a/examples/ReactExample/components/todo-item.js b/examples/ReactExample/components/todo-item.js index 710fd537..988b7240 100644 --- a/examples/ReactExample/components/todo-item.js +++ b/examples/ReactExample/components/todo-item.js @@ -2,6 +2,7 @@ const React = require('react-native'); const TodoItemCheckbox = require('./todo-item-checkbox'); +const TodoItemDelete = require('./todo-item-delete'); const realm = require('./realm'); const styles = require('./styles'); @@ -26,6 +27,7 @@ class TodoItem extends React.Component { render() { let item = this.props.item; + let deleteButton; let contents; if (this.props.editing) { @@ -48,12 +50,17 @@ class TodoItem extends React.Component { {item.text} ); + + deleteButton = ( + + ); } return ( {contents} + {deleteButton} ); } diff --git a/examples/ReactExample/components/todo-list.js b/examples/ReactExample/components/todo-list.js index c292f2d9..af06dacc 100644 --- a/examples/ReactExample/components/todo-list.js +++ b/examples/ReactExample/components/todo-list.js @@ -39,6 +39,7 @@ class TodoList extends React.Component { item={item} editing={this.state.editingRow == rowIndex} onPress={() => this._onPressRow(rowIndex)} + onPressDelete={() => this._onPressDeleteRow(rowIndex)} onEndEditing={() => this._onEndEditingRow(rowIndex)} /> ); } @@ -53,6 +54,14 @@ class TodoList extends React.Component { 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; From e90715140baef585927c44a6f95e4353827beb84 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Mon, 26 Oct 2015 17:15:40 -0700 Subject: [PATCH 04/11] Make libReact a target dependency of ReactExample Was experiencing a bug where the packager would startup for ReactTests rather than ReactExample. This fixes that. --- .../ReactExample.xcodeproj/project.pbxproj | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples/ReactExample/ReactExample.xcodeproj/project.pbxproj b/examples/ReactExample/ReactExample.xcodeproj/project.pbxproj index 8d07b0c8..f380c05b 100644 --- a/examples/ReactExample/ReactExample.xcodeproj/project.pbxproj +++ b/examples/ReactExample/ReactExample.xcodeproj/project.pbxproj @@ -133,6 +133,13 @@ remoteGlobalIDString = 02B29A151B7CF7C9008A7E6B; remoteInfo = RealmReact; }; + F6EA29001BDEEC4B00ECDC7B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 83CBBA2D1A601D0E00E9B192; + remoteInfo = React; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -389,6 +396,7 @@ buildRules = ( ); dependencies = ( + F6EA29011BDEEC4B00ECDC7B /* PBXTargetDependency */, F636F6E31BCDB72D0023F35C /* PBXTargetDependency */, ); name = ReactExample; @@ -637,6 +645,11 @@ name = RealmReact; targetProxy = F636F6E21BCDB72D0023F35C /* PBXContainerItemProxy */; }; + F6EA29011BDEEC4B00ECDC7B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = React; + targetProxy = F6EA29001BDEEC4B00ECDC7B /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ From 6fc21109918e4087b7d0ea86a9c5101deeba67c5 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 27 Oct 2015 01:52:26 -0700 Subject: [PATCH 05/11] Example app can now have multiple todo lists --- examples/ReactExample/components/styles.js | 10 +- examples/ReactExample/components/todo-app.js | 63 +++++++--- .../components/todo-item-checkbox.js | 22 ---- .../components/todo-item-delete.js | 20 --- examples/ReactExample/components/todo-item.js | 87 ++++--------- .../ReactExample/components/todo-list-item.js | 115 ++++++++++++++++++ examples/ReactExample/components/todo-list.js | 79 ------------ .../ReactExample/components/todo-listview.js | 97 +++++++++++++++ 8 files changed, 289 insertions(+), 204 deletions(-) delete mode 100644 examples/ReactExample/components/todo-item-checkbox.js delete mode 100644 examples/ReactExample/components/todo-item-delete.js create mode 100644 examples/ReactExample/components/todo-list-item.js delete mode 100644 examples/ReactExample/components/todo-list.js create mode 100644 examples/ReactExample/components/todo-listview.js diff --git a/examples/ReactExample/components/styles.js b/examples/ReactExample/components/styles.js index 47bab8a4..d31ea264 100644 --- a/examples/ReactExample/components/styles.js +++ b/examples/ReactExample/components/styles.js @@ -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, }, diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js index afebfc09..e817d8c0 100644 --- a/examples/ReactExample/components/todo-app.js +++ b/examples/ReactExample/components/todo-app.js @@ -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 ( - + ); } - _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}); } } diff --git a/examples/ReactExample/components/todo-item-checkbox.js b/examples/ReactExample/components/todo-item-checkbox.js deleted file mode 100644 index 6cfbd3cf..00000000 --- a/examples/ReactExample/components/todo-item-checkbox.js +++ /dev/null @@ -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 ( - - - - {this.props.checked ? 'βœ“' : ''} - - - - ); - } -} - -module.exports = TodoItemCheckbox; diff --git a/examples/ReactExample/components/todo-item-delete.js b/examples/ReactExample/components/todo-item-delete.js deleted file mode 100644 index 4a260d4b..00000000 --- a/examples/ReactExample/components/todo-item-delete.js +++ /dev/null @@ -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 ( - - - 𐄂 - - - ); - } -} - -module.exports = TodoItemDelete; diff --git a/examples/ReactExample/components/todo-item.js b/examples/ReactExample/components/todo-item.js index 988b7240..d02667b5 100644 --- a/examples/ReactExample/components/todo-item.js +++ b/examples/ReactExample/components/todo-item.js @@ -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 = ( - - ); - } else { - contents = ( - - {item.text} - - ); - - deleteButton = ( - - ); - } + set text(text) { + this.props.item.text = text; + } + renderLeftSide() { return ( - - - {contents} - {deleteButton} - + + + + {this.done ? 'βœ“' : ''} + + + ); } - _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; diff --git a/examples/ReactExample/components/todo-list-item.js b/examples/ReactExample/components/todo-list-item.js new file mode 100644 index 00000000..c8a39b32 --- /dev/null +++ b/examples/ReactExample/components/todo-list-item.js @@ -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 ( + + {this.renderLeftSide()} + {this.renderText()} + {this.renderRightSide()} + + ); + } + + renderLeftSide() { + return ( + + {this.done ? 'βœ“' : '⁃'} + + ); + } + + renderRightSide() { + // Only show the delete button while not editing the text. + return this.props.editing ? null : this.renderDelete(); + } + + renderText() { + if (this.props.editing) { + return ( + + ); + } else { + return ( + + {this.text} + + ); + } + } + + renderDelete() { + return ( + + + 𐄂 + + + ); + } + + _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; diff --git a/examples/ReactExample/components/todo-list.js b/examples/ReactExample/components/todo-list.js deleted file mode 100644 index af06dacc..00000000 --- a/examples/ReactExample/components/todo-list.js +++ /dev/null @@ -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 ( - - - - Press Cmd+R to reload,{'\n'} - Cmd+D for dev menu - - - ); - } - - _renderRow(item, sectionIndex, rowIndex) { - return ( - 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; diff --git a/examples/ReactExample/components/todo-listview.js b/examples/ReactExample/components/todo-listview.js new file mode 100644 index 00000000..00eab958 --- /dev/null +++ b/examples/ReactExample/components/todo-listview.js @@ -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 ( + + + + Press Cmd+R to reload,{'\n'} + Cmd+D for dev menu + + + ); + } + + renderRow(item, sectionIndex, rowIndex) { + let RowClass = this.props.rowClass || TodoListItem; + + return ( + 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; From ab33d47a946e8add0579fef67939f089fa008b65 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 27 Oct 2015 03:08:18 -0700 Subject: [PATCH 06/11] ReactExample: add "smart lists" --- examples/ReactExample/components/styles.js | 3 + examples/ReactExample/components/todo-app.js | 27 +++++-- .../ReactExample/components/todo-list-item.js | 6 +- .../ReactExample/components/todo-listview.js | 71 +++++++++++++++---- 4 files changed, 87 insertions(+), 20 deletions(-) diff --git a/examples/ReactExample/components/styles.js b/examples/ReactExample/components/styles.js index d31ea264..05bac112 100644 --- a/examples/ReactExample/components/styles.js +++ b/examples/ReactExample/components/styles.js @@ -46,6 +46,9 @@ module.exports = React.StyleSheet.create({ flex: 1, lineHeight: 30, }, + listItemTextSpecial: { + fontStyle: 'italic', + }, listItemDelete: { paddingLeft: 12, paddingRight: 12, diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js index e817d8c0..92b8268d 100644 --- a/examples/ReactExample/components/todo-app.js +++ b/examples/ReactExample/components/todo-app.js @@ -30,14 +30,21 @@ class TodoApp extends React.Component { } 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(), }; @@ -64,17 +71,27 @@ class TodoApp extends React.Component { } _onPressTodoList(list) { - this.refs.nav.push({ + let items = list.items; + + let route = { title: list.name, component: TodoListView, passProps: { ref: 'listItemView', - items: list.items, + items: items, rowClass: TodoItem, }, - rightButtonTitle: 'Add', - onRightButtonPress: () => this._addNewTodoItem(list), - }); + }; + + // 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); } _setEditingRow(rowIndex) { diff --git a/examples/ReactExample/components/todo-list-item.js b/examples/ReactExample/components/todo-list-item.js index c8a39b32..c93655ff 100644 --- a/examples/ReactExample/components/todo-list-item.js +++ b/examples/ReactExample/components/todo-list-item.js @@ -58,14 +58,14 @@ class TodoListItem extends React.Component { return this.props.editing ? null : this.renderDelete(); } - renderText() { + renderText(extraStyle) { if (this.props.editing) { return ( @@ -73,7 +73,7 @@ class TodoListItem extends React.Component { } else { return ( {this.text} diff --git a/examples/ReactExample/components/todo-listview.js b/examples/ReactExample/components/todo-listview.js index 00eab958..41004576 100644 --- a/examples/ReactExample/components/todo-listview.js +++ b/examples/ReactExample/components/todo-listview.js @@ -12,6 +12,7 @@ class TodoListView extends React.Component { super(props); this.dataSource = new ListView.DataSource({ + sectionHeaderHasChanged: () => false, rowHasChanged: (row1, row2) => row1 !== row2 }); @@ -34,8 +35,14 @@ class TodoListView extends React.Component { 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); + 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 ( @@ -49,32 +56,41 @@ class TodoListView extends React.Component { } renderRow(item, sectionIndex, rowIndex) { - let RowClass = this.props.rowClass || TodoListItem; + 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 ( this._onPressRow(item, rowIndex)} - onPressDelete={() => this._onPressDeleteRow(item, rowIndex)} + editing={editing} + onPress={() => this._onPressRow(item, sectionIndex, rowIndex)} + onPressDelete={() => this._onPressDeleteRow(item)} onEndEditing={() => this._onEndEditingRow(item, rowIndex)} /> ); } - _onPressRow(item, rowIndex) { + _onPressRow(item, sectionIndex, rowIndex) { let onPressItem = this.props.onPressItem; if (onPressItem) { - onPressItem(item, rowIndex); + onPressItem(item); return; } // If no handler was provided, then default to editing the row. - this.setState({editingRow: rowIndex}); + if (sectionIndex == 0) { + this.setState({editingRow: rowIndex}); + } } _onPressDeleteRow(item) { - realm.write(() => realm.delete(item)); - + this._deleteItem(item); this.forceUpdate(); } @@ -86,12 +102,43 @@ class TodoListView extends React.Component { } } + _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) { - realm.write(() => realm.delete(item)); + this._deleteItem(item); } } } +class TodoListExtraItem extends TodoListItem { + renderText() { + return super.renderText(styles.listItemTextSpecial); + } + + renderLeftSide() { + return ( + + {this.props.item.items.length} + + ); + } + + renderRightSide() { + return null; + } +} + module.exports = TodoListView; From 922bf1d0f73a7650446ffd72f6ca404e739d611b Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 27 Oct 2015 14:23:17 -0700 Subject: [PATCH 07/11] Improve look of checkbox and smart list badges --- examples/ReactExample/components/styles.js | 16 ++++++++++++++-- examples/ReactExample/components/todo-item.js | 6 +++--- .../ReactExample/components/todo-listview.js | 4 +++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/examples/ReactExample/components/styles.js b/examples/ReactExample/components/styles.js index 05bac112..e685b5b6 100644 --- a/examples/ReactExample/components/styles.js +++ b/examples/ReactExample/components/styles.js @@ -28,10 +28,22 @@ module.exports = React.StyleSheet.create({ width: 36, }, listItemCheckbox: { - borderColor: "#000", - borderWidth: 0.5, + 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', diff --git a/examples/ReactExample/components/todo-item.js b/examples/ReactExample/components/todo-item.js index d02667b5..d9f88ba5 100644 --- a/examples/ReactExample/components/todo-item.js +++ b/examples/ReactExample/components/todo-item.js @@ -34,9 +34,9 @@ class TodoItem extends TodoListItem { return ( - - {this.done ? 'βœ“' : ''} - + + {this.done ? 'βœ“' : ''} + ); diff --git a/examples/ReactExample/components/todo-listview.js b/examples/ReactExample/components/todo-listview.js index 41004576..35b0c4c1 100644 --- a/examples/ReactExample/components/todo-listview.js +++ b/examples/ReactExample/components/todo-listview.js @@ -131,7 +131,9 @@ class TodoListExtraItem extends TodoListItem { renderLeftSide() { return ( - {this.props.item.items.length} + + {this.props.item.items.length} + ); } From 5edeefbb179b88383d4ea9ee03cc2848bd240456 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 27 Oct 2015 16:19:30 -0700 Subject: [PATCH 08/11] Add beta licenses to example app files --- .../ReactExample/ReactExampleTests/ReactExampleTests.m | 9 ++------- examples/ReactExample/components/realm.js | 4 ++++ examples/ReactExample/components/styles.js | 4 ++++ examples/ReactExample/components/todo-app.js | 4 ++++ examples/ReactExample/components/todo-item.js | 4 ++++ examples/ReactExample/components/todo-list-item.js | 4 ++++ examples/ReactExample/components/todo-listview.js | 4 ++++ examples/ReactExample/iOS/AppDelegate.h | 9 ++------- examples/ReactExample/iOS/AppDelegate.m | 9 ++------- examples/ReactExample/index.ios.js | 4 ++++ 10 files changed, 34 insertions(+), 21 deletions(-) diff --git a/examples/ReactExample/ReactExampleTests/ReactExampleTests.m b/examples/ReactExample/ReactExampleTests/ReactExampleTests.m index e9cbbd6c..546e5131 100644 --- a/examples/ReactExample/ReactExampleTests/ReactExampleTests.m +++ b/examples/ReactExample/ReactExampleTests/ReactExampleTests.m @@ -1,10 +1,5 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * 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. +/* Copyright 2015 Realm Inc - All Rights Reserved + * Proprietary and Confidential */ #import diff --git a/examples/ReactExample/components/realm.js b/examples/ReactExample/components/realm.js index d1b172b7..7ab84d75 100644 --- a/examples/ReactExample/components/realm.js +++ b/examples/ReactExample/components/realm.js @@ -1,3 +1,7 @@ +/* Copyright 2015 Realm Inc - All Rights Reserved + * Proprietary and Confidential + */ + 'use strict'; const Realm = require('realm'); diff --git a/examples/ReactExample/components/styles.js b/examples/ReactExample/components/styles.js index e685b5b6..3d6c1240 100644 --- a/examples/ReactExample/components/styles.js +++ b/examples/ReactExample/components/styles.js @@ -1,3 +1,7 @@ +/* Copyright 2015 Realm Inc - All Rights Reserved + * Proprietary and Confidential + */ + 'use strict'; const React = require('react-native'); diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js index 92b8268d..38f979ed 100644 --- a/examples/ReactExample/components/todo-app.js +++ b/examples/ReactExample/components/todo-app.js @@ -1,3 +1,7 @@ +/* Copyright 2015 Realm Inc - All Rights Reserved + * Proprietary and Confidential + */ + 'use strict'; const React = require('react-native'); diff --git a/examples/ReactExample/components/todo-item.js b/examples/ReactExample/components/todo-item.js index d9f88ba5..4b6d1623 100644 --- a/examples/ReactExample/components/todo-item.js +++ b/examples/ReactExample/components/todo-item.js @@ -1,3 +1,7 @@ +/* Copyright 2015 Realm Inc - All Rights Reserved + * Proprietary and Confidential + */ + 'use strict'; const React = require('react-native'); diff --git a/examples/ReactExample/components/todo-list-item.js b/examples/ReactExample/components/todo-list-item.js index c93655ff..b81bf570 100644 --- a/examples/ReactExample/components/todo-list-item.js +++ b/examples/ReactExample/components/todo-list-item.js @@ -1,3 +1,7 @@ +/* Copyright 2015 Realm Inc - All Rights Reserved + * Proprietary and Confidential + */ + 'use strict'; const React = require('react-native'); diff --git a/examples/ReactExample/components/todo-listview.js b/examples/ReactExample/components/todo-listview.js index 35b0c4c1..59aed8b8 100644 --- a/examples/ReactExample/components/todo-listview.js +++ b/examples/ReactExample/components/todo-listview.js @@ -1,3 +1,7 @@ +/* Copyright 2015 Realm Inc - All Rights Reserved + * Proprietary and Confidential + */ + 'use strict'; const React = require('react-native'); diff --git a/examples/ReactExample/iOS/AppDelegate.h b/examples/ReactExample/iOS/AppDelegate.h index a9654d5e..b9dfb705 100644 --- a/examples/ReactExample/iOS/AppDelegate.h +++ b/examples/ReactExample/iOS/AppDelegate.h @@ -1,10 +1,5 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * 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. +/* Copyright 2015 Realm Inc - All Rights Reserved + * Proprietary and Confidential */ #import diff --git a/examples/ReactExample/iOS/AppDelegate.m b/examples/ReactExample/iOS/AppDelegate.m index 77dc2f61..80331c4f 100644 --- a/examples/ReactExample/iOS/AppDelegate.m +++ b/examples/ReactExample/iOS/AppDelegate.m @@ -1,10 +1,5 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * 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. +/* Copyright 2015 Realm Inc - All Rights Reserved + * Proprietary and Confidential */ #import "AppDelegate.h" diff --git a/examples/ReactExample/index.ios.js b/examples/ReactExample/index.ios.js index e051fe32..c506bc04 100644 --- a/examples/ReactExample/index.ios.js +++ b/examples/ReactExample/index.ios.js @@ -1,3 +1,7 @@ +/* Copyright 2015 Realm Inc - All Rights Reserved + * Proprietary and Confidential + */ + 'use strict'; const React = require('react-native'); From af9e7e8b4cd4c0c42c40a8aa4057064ad083fd66 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Wed, 28 Oct 2015 10:53:30 -0700 Subject: [PATCH 09/11] Update ReactExample Objective-C to 4-space indentation --- .../ReactExample.xcodeproj/project.pbxproj | 6 +- .../ReactExampleTests/ReactExampleTests.m | 63 ++++++++--------- examples/ReactExample/iOS/AppDelegate.m | 70 +++++++++---------- examples/ReactExample/iOS/main.m | 6 +- 4 files changed, 72 insertions(+), 73 deletions(-) diff --git a/examples/ReactExample/ReactExample.xcodeproj/project.pbxproj b/examples/ReactExample/ReactExample.xcodeproj/project.pbxproj index f380c05b..8aee7818 100644 --- a/examples/ReactExample/ReactExample.xcodeproj/project.pbxproj +++ b/examples/ReactExample/ReactExample.xcodeproj/project.pbxproj @@ -349,9 +349,9 @@ 027798471BBB2F1000C96559 /* ReactExampleTests */, 83CBBA001A601CBA00E9B192 /* Products */, ); - indentWidth = 2; + indentWidth = 4; sourceTree = ""; - tabWidth = 2; + tabWidth = 4; }; 83CBBA001A601CBA00E9B192 /* Products */ = { isa = PBXGroup; @@ -411,7 +411,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 0700; - ORGANIZATIONNAME = Facebook; + ORGANIZATIONNAME = Realm; TargetAttributes = { 027798451BBB2F1000C96559 = { CreatedOnToolsVersion = 7.0.1; diff --git a/examples/ReactExample/ReactExampleTests/ReactExampleTests.m b/examples/ReactExample/ReactExampleTests/ReactExampleTests.m index 546e5131..faac8843 100644 --- a/examples/ReactExample/ReactExampleTests/ReactExampleTests.m +++ b/examples/ReactExample/ReactExampleTests/ReactExampleTests.m @@ -19,47 +19,46 @@ - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test { - if (test(view)) { - return YES; - } - for (UIView *subview in [view subviews]) { - if ([self findSubviewInView:subview matching:test]) { - return YES; + if (test(view)) { + return YES; } - } - return NO; + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; } - (void)testLaunched { - UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; - BOOL foundElement = NO; + UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; - __block NSString *redboxError = nil; - RCTSetLogFunction(^(RCTLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message) { - if (level >= RCTLogLevelError) { - redboxError = message; + __block NSString *redboxError = nil; + RCTSetLogFunction(^(RCTLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message) { + if (level >= RCTLogLevelError) { + redboxError = message; + } + }); + + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + + foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; } - }); - while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + RCTSetLogFunction(RCTDefaultLogFunction); - foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { - if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { - return YES; - } - return NO; - }]; - } - - RCTSetLogFunction(RCTDefaultLogFunction); - - XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); - //XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + //XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); } - @end diff --git a/examples/ReactExample/iOS/AppDelegate.m b/examples/ReactExample/iOS/AppDelegate.m index 80331c4f..adaf8f33 100644 --- a/examples/ReactExample/iOS/AppDelegate.m +++ b/examples/ReactExample/iOS/AppDelegate.m @@ -10,47 +10,47 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - NSURL *jsCodeLocation; + NSURL *jsCodeLocation; - /** - * Loading JavaScript code - uncomment the one you want. - * - * OPTION 1 - * Load from development server. Start the server from the repository root: - * - * $ npm start - * - * To run on device, change `localhost` to the IP address of your computer - * (you can get this by typing `ifconfig` into the terminal and selecting the - * `inet` value under `en0:`) and make sure your computer and iOS device are - * on the same Wi-Fi network. - */ + /** + * Loading JavaScript code - uncomment the one you want. + * + * OPTION 1 + * Load from development server. Start the server from the repository root: + * + * $ npm start + * + * To run on device, change `localhost` to the IP address of your computer + * (you can get this by typing `ifconfig` into the terminal and selecting the + * `inet` value under `en0:`) and make sure your computer and iOS device are + * on the same Wi-Fi network. + */ - jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"]; + jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"]; - /** - * OPTION 2 - * Load from pre-bundled file on disk. To re-generate the static bundle - * from the root of your project directory, run - * - * $ react-native bundle --minify - * - * see http://facebook.github.io/react-native/docs/runningondevice.html - */ + /** + * OPTION 2 + * Load from pre-bundled file on disk. To re-generate the static bundle + * from the root of your project directory, run + * + * $ react-native bundle --minify + * + * see http://facebook.github.io/react-native/docs/runningondevice.html + */ -// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; - RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation - moduleName:@"ReactExample" - initialProperties:nil - launchOptions:launchOptions]; + RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation + moduleName:@"ReactExample" + initialProperties:nil + launchOptions:launchOptions]; - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [[UIViewController alloc] init]; - rootViewController.view = rootView; - self.window.rootViewController = rootViewController; - [self.window makeKeyAndVisible]; - return YES; + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + UIViewController *rootViewController = [[UIViewController alloc] init]; + rootViewController.view = rootView; + self.window.rootViewController = rootViewController; + [self.window makeKeyAndVisible]; + return YES; } @end diff --git a/examples/ReactExample/iOS/main.m b/examples/ReactExample/iOS/main.m index 3d767fcb..e7af16f9 100644 --- a/examples/ReactExample/iOS/main.m +++ b/examples/ReactExample/iOS/main.m @@ -12,7 +12,7 @@ #import "AppDelegate.h" int main(int argc, char * argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } } From 2ee0e2f608535cee2a9faec77105398be205614b Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Wed, 28 Oct 2015 11:23:37 -0700 Subject: [PATCH 10/11] ReactExample: fix bug with pressing Add twice --- examples/ReactExample/components/todo-app.js | 24 ++++++++++++++++--- .../ReactExample/components/todo-listview.js | 21 ++++++++++------ 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js index 38f979ed..fc7174cb 100644 --- a/examples/ReactExample/components/todo-app.js +++ b/examples/ReactExample/components/todo-app.js @@ -59,19 +59,29 @@ class TodoApp extends React.Component { } _addNewTodoItem(list) { + let items = list.items; + if (!this._shouldAddNewItem(items)) { + return; + } + realm.write(() => { - list.items.push({text: ''}); + items.push({text: ''}); }); - this._setEditingRow(list.items.length - 1); + this._setEditingRow(items.length - 1); } _addNewTodoList() { + let items = this.todoLists; + if (!this._shouldAddNewItem(items)) { + return; + } + realm.write(() => { realm.create('TodoList', {name: '', items: []}); }); - this._setEditingRow(this.todoLists.length - 1); + this._setEditingRow(items.length - 1); } _onPressTodoList(list) { @@ -98,6 +108,14 @@ class TodoApp extends React.Component { 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}); diff --git a/examples/ReactExample/components/todo-listview.js b/examples/ReactExample/components/todo-listview.js index 59aed8b8..ed483994 100644 --- a/examples/ReactExample/components/todo-listview.js +++ b/examples/ReactExample/components/todo-listview.js @@ -24,16 +24,21 @@ class TodoListView extends React.Component { this.renderRow = this.renderRow.bind(this); } - componentWillUpdate(nextProps, nextState) { + componentDidUpdate() { + let items = this.props.items; 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); + 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}); } } @@ -123,7 +128,9 @@ class TodoListView extends React.Component { // The item could be a TodoList or a Todo. if (!item.name && !item.text) { this._deleteItem(item); + return true; } + return false; } } From c42dceb7a82e052fdd08f8990be3cebce1b8f9c0 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Wed, 28 Oct 2015 11:25:54 -0700 Subject: [PATCH 11/11] ReactExample: Change placeholder text --- examples/ReactExample/components/todo-list-item.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ReactExample/components/todo-list-item.js b/examples/ReactExample/components/todo-list-item.js index b81bf570..6a01222c 100644 --- a/examples/ReactExample/components/todo-list-item.js +++ b/examples/ReactExample/components/todo-list-item.js @@ -68,7 +68,7 @@ class TodoListItem extends React.Component {