Improve app view flow

This commit is contained in:
Rodrigo Nascimento 2017-08-09 13:19:17 -03:00
parent e01a2d0aaf
commit 9f31e2606e
8 changed files with 203 additions and 108 deletions

View File

@ -1 +1,2 @@
__tests__ __tests__
node_modules

View File

@ -6,7 +6,10 @@ export default class KeyboardView extends React.PureComponent {
static propTypes = { static propTypes = {
style: KeyboardAvoidingView.propTypes.style, style: KeyboardAvoidingView.propTypes.style,
keyboardVerticalOffset: PropTypes.number, keyboardVerticalOffset: PropTypes.number,
children: PropTypes.array.isRequired children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
])
} }
render() { render() {

View File

@ -20,6 +20,27 @@ const RocketChat = {
export default RocketChat; export default RocketChat;
Meteor.Accounts.onLogin(() => {
Meteor.call('subscriptions/get', (err, data) => {
if (err) {
console.error(err);
}
realm.write(() => {
data.forEach((subscription) => {
// const subscription = {
// _id: item._id
// };
// if (typeof item.value === 'string') {
// subscription.value = item.value;
// }
subscription._server = { id: RocketChat.currentServer };
realm.create('subscriptions', subscription, true);
});
});
});
});
export function connect(cb) { export function connect(cb) {
const url = `${ RocketChat.currentServer }/websocket`; const url = `${ RocketChat.currentServer }/websocket`;
@ -52,14 +73,12 @@ export function connect(cb) {
Meteor.ddp.on('changed', (ddbMessage) => { Meteor.ddp.on('changed', (ddbMessage) => {
console.log('changed', ddbMessage); console.log('changed', ddbMessage);
if (ddbMessage.collection === 'stream-room-messages') { if (ddbMessage.collection === 'stream-room-messages') {
setTimeout(() => { realm.write(() => {
realm.write(() => { const message = ddbMessage.fields.args[0];
const message = ddbMessage.fields.args[0]; message.temp = false;
message.temp = false; message._server = { id: RocketChat.currentServer };
message._server = { id: RocketChat.currentServer }; realm.create('messages', message, true);
realm.create('messages', message, true); });
});
}, 1000);
} }
}); });
}); });

View File

@ -84,6 +84,6 @@ realm.write(() => {
const allSettins = realm.objects('settings'); const allSettins = realm.objects('settings');
realm.delete(allSettins); realm.delete(allSettins);
// realm.create('servers', {id: 'https://demo.rocket.chat', current: false}, true); // realm.create('servers', { id: 'https://demo.rocket.chat', current: false }, true);
// realm.create('servers', {id: 'http://localhost:3000', current: false}, true); // realm.create('servers', { id: 'http://localhost:3000', current: false }, true);
}); });

View File

@ -1,3 +1,5 @@
import React from 'react';
import { Button } from 'react-native';
import { StackNavigator } from 'react-navigation'; import { StackNavigator } from 'react-navigation';
import LoginView from './views/login'; import LoginView from './views/login';
import NewServerView from './views/serverNew'; import NewServerView from './views/serverNew';
@ -5,26 +7,14 @@ import ListServerView from './views/serverList';
import RoomsListView from './views/roomsList'; import RoomsListView from './views/roomsList';
import RoomView from './views/room'; import RoomView from './views/room';
const navigationOptions = {
// headerStyle: {
// backgroundColor: '#c1272d'
// },
// headerTitleStyle: {
// color: '#fff'
// }
};
export default new StackNavigator({ const MainCardNavigator = StackNavigator({
ListServer: { Rooms: {
screen: ListServerView, screen: RoomsListView,
navigationOptions navigationOptions: ({ navigation }) => ({
headerLeft: <Button title='Servers' onPress={() => navigation.navigate('ListServerModal')} />
})
}, },
NewServer: {
screen: NewServerView,
navigationOptions
},
Login: { screen: LoginView },
Rooms: { screen: RoomsListView },
Room: { Room: {
screen: RoomView screen: RoomView
// navigationOptions: { // navigationOptions: {
@ -32,8 +22,41 @@ export default new StackNavigator({
// } // }
} }
}, { }, {
// initialRouteName: 'Room', initialRouteName: 'Rooms',
cardStyle: { cardStyle: {
backgroundColor: '#fff' backgroundColor: '#fff'
} }
}); });
export default new StackNavigator({
Main: {
screen: MainCardNavigator,
navigationOptions: {
header: null
}
},
Login: {
screen: LoginView,
navigationOptions: ({ navigation }) => ({
headerLeft: <Button title='Cancel' onPress={() => navigation.dispatch({ type: 'Navigation/BACK' })} />
})
},
ListServerModal: {
screen: ListServerView,
navigationOptions: ({ navigation }) => ({
headerLeft: <Button title='Close' onPress={() => navigation.dispatch({ type: 'Navigation/BACK' })} />
})
},
NewServerModal: {
screen: NewServerView,
navigationOptions: ({ navigation }) => ({
headerLeft: <Button title='Close' onPress={() => navigation.dispatch({ type: 'Navigation/BACK' })} />
})
}
}, {
initialRouteName: 'Main',
cardStyle: {
backgroundColor: '#fff'
},
mode: 'modal'
});

View File

@ -1,8 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { TextInput, StyleSheet } from 'react-native'; import { TextInput, StyleSheet } from 'react-native';
import realm from '../lib/realm'; import { loginWithPassword } from '../lib/meteor';
import { loginWithPassword, loadSubscriptions, Accounts } from '../lib/meteor';
import KeyboardView from '../components/KeyboardView'; import KeyboardView from '../components/KeyboardView';
@ -25,19 +24,13 @@ const styles = StyleSheet.create({
} }
}); });
Accounts.onLogin(() => {
loadSubscriptions(() => {
navigate('Rooms');
});
});
export default class LoginView extends React.Component { export default class LoginView extends React.Component {
static propTypes = { static propTypes = {
navigation: PropTypes.object.isRequired navigation: PropTypes.object.isRequired
} }
static navigationOptions = () => ({ static navigationOptions = () => ({
title: realm.objectForPrimaryKey('settings', 'Site_Name').value title: 'Login'
}); });
constructor(props) { constructor(props) {
@ -48,10 +41,10 @@ export default class LoginView extends React.Component {
password: '' password: ''
}; };
navigate = this.props.navigation.navigate;
this.submit = () => { this.submit = () => {
loginWithPassword({ username: this.state.username }, this.state.password); loginWithPassword({ username: this.state.username }, this.state.password, () => {
this.props.navigation.dispatch({ type: 'Navigation/BACK' });
});
}; };
} }

View File

@ -1,34 +1,87 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { View, FlatList, StyleSheet } from 'react-native'; import { Text, View, FlatList, StyleSheet } from 'react-native';
import Meteor from 'react-native-meteor';
import realm from '../lib/realm'; import realm from '../lib/realm';
import RocketChat from '../lib/meteor'; import RocketChat, { connect } from '../lib/meteor';
import RoomItem from '../components/RoomItem'; import RoomItem from '../components/RoomItem';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1 flex: 1,
alignItems: 'center',
justifyContent: 'center'
}, },
separator: { separator: {
height: 1, height: 1,
// width: "86%",
backgroundColor: '#CED0CE' backgroundColor: '#CED0CE'
// marginLeft: "14%" },
list: {
width: '100%'
},
emptyText: {
textAlign: 'center',
fontSize: 18,
color: '#ccc'
} }
}); });
let navigation;
Meteor.getData().on('loggingIn', () => {
setTimeout(() => {
if (Meteor._isLoggingIn === false && Meteor.userId() == null) {
console.log('loggingIn', Meteor.userId());
navigation.navigate('Login');
}
}, 100);
});
Meteor.Accounts.onLogin(() => {
console.log('onLogin');
});
export default class RoomsListView extends React.Component { export default class RoomsListView extends React.Component {
static propTypes = { static propTypes = {
navigation: PropTypes.object.isRequired navigation: PropTypes.object.isRequired
} }
static navigationOptions = () => ({
title: 'Rooms'
});
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = this.getState();
dataSource: realm.objects('subscriptions').filtered('_server.id = $0', RocketChat.currentServer).sorted('name') }
};
componentWillMount() {
realm.addListener('change', this.updateState);
navigation = this.props.navigation;
const currentServer = realm.objects('servers').filtered('current = true')[0];
if (currentServer) {
connect(() => {
// navigation.navigate('Login');
});
} else {
navigation.navigate('ListServerModal');
}
}
componentWillUnmount() {
realm.removeListener('change', this.updateState);
}
getState = () => ({
dataSource: realm.objects('subscriptions').filtered('_server.id = $0', RocketChat.currentServer).sorted('name')
})
updateState = () => {
this.setState(this.getState());
} }
_onPressItem = (id) => { _onPressItem = (id) => {
@ -48,9 +101,9 @@ export default class RoomsListView extends React.Component {
<View style={styles.separator} /> <View style={styles.separator} />
); );
render() { renderList = () => {
return ( if (this.state.dataSource.length) {
<View style={styles.container}> return (
<FlatList <FlatList
style={styles.list} style={styles.list}
data={this.state.dataSource} data={this.state.dataSource}
@ -58,6 +111,18 @@ export default class RoomsListView extends React.Component {
keyExtractor={item => item._id} keyExtractor={item => item._id}
ItemSeparatorComponent={this.renderSeparator} ItemSeparatorComponent={this.renderSeparator}
/> />
);
}
return (
<Text style={styles.emptyText}>No rooms</Text>
);
}
render() {
return (
<View style={styles.container}>
{this.renderList()}
</View> </View>
); );
} }

View File

@ -58,7 +58,7 @@ export default class ListServerView extends React.Component {
headerRight: ( headerRight: (
<Button <Button
title='Add' title='Add'
onPress={() => navigation.navigate('NewServer')} onPress={() => navigation.navigate('NewServerModal')}
/> />
) )
}); });
@ -70,69 +70,60 @@ export default class ListServerView extends React.Component {
}; };
} }
componentDidMount() { componentWillMount() {
const getState = () => { realm.addListener('change', this.updateState);
const sections = [{ zeroconf.on('update', this.updateState);
title: 'My servers',
data: realm.objects('servers')
}];
if (this.state.nearBy) {
const nearBy = Object.keys(this.state.nearBy)
.filter(key => this.state.nearBy[key].addresses);
if (nearBy.length) {
sections.push({
title: 'Nearby',
data: nearBy.map((key) => {
const server = this.state.nearBy[key];
const address = `http://${ server.addresses[0] }:${ server.port }`;
return {
id: address
};
})
});
}
}
return {
...this.state,
sections
};
};
const { navigation } = this.props;
if (navigation && navigation.state.params && navigation.state.params.newServer) {
return navigation.navigate('Login');
}
const currentServer = realm.objects('servers').filtered('current = true')[0];
if (currentServer) {
connect(() => {
navigation.navigate('Login');
});
}
zeroconf.on('update', () => {
this.state.nearBy = zeroconf.getServices();
this.setState(getState());
});
zeroconf.scan('http', 'tcp', 'local.'); zeroconf.scan('http', 'tcp', 'local.');
realm.addListener('change', () => this.setState(getState())); this.state = this.getState();
}
this.state = getState(); componentWillUnmount() {
zeroconf.stop();
return null; realm.removeListener('change', this.updateState);
zeroconf.removeListener('update', this.updateState);
} }
onPressItem(item) { onPressItem(item) {
const { navigate } = this.props.navigation;
RocketChat.currentServer = item.id; RocketChat.currentServer = item.id;
connect(() => { connect(() => {});
navigate('Login'); this.props.navigation.dispatch({ type: 'Navigation/BACK' });
}); }
getState = () => {
const sections = [{
title: 'My servers',
data: realm.objects('servers')
}];
this.state.nearBy = zeroconf.getServices();
if (this.state.nearBy) {
const nearBy = Object.keys(this.state.nearBy)
.filter(key => this.state.nearBy[key].addresses);
if (nearBy.length) {
sections.push({
title: 'Nearby',
data: nearBy.map((key) => {
const server = this.state.nearBy[key];
const address = `http://${ server.addresses[0] }:${ server.port }`;
return {
id: address
};
})
});
}
}
return {
...this.state,
sections
};
};
updateState = () => {
this.setState(this.getState());
} }
renderItem = ({ item }) => ( renderItem = ({ item }) => (