diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js
index 2593bd09a..4e44be0df 100644
--- a/app/actions/actionsTypes.js
+++ b/app/actions/actionsTypes.js
@@ -26,6 +26,7 @@ export const FORGOT_PASSWORD = createRequestTypes('FORGOT_PASSWORD', [
...defaultTypes,
'INIT'
]);
+export const USER = createRequestTypes('USER', ['SET']);
export const ROOMS = createRequestTypes('ROOMS');
export const ROOM = createRequestTypes('ROOM', ['ADD_USER_TYPING', 'REMOVE_USER_TYPING', 'SOMEONE_TYPING', 'OPEN', 'USER_TYPING']);
export const APP = createRequestTypes('APP', ['READY', 'INIT']);
diff --git a/app/actions/login.js b/app/actions/login.js
index 4c53c301e..d2a31cb55 100644
--- a/app/actions/login.js
+++ b/app/actions/login.js
@@ -118,3 +118,10 @@ export function forgotPasswordFailure(err) {
err
};
}
+
+export function setUser(action) {
+ return {
+ type: types.USER.SET,
+ ...action
+ };
+}
diff --git a/app/constants/colors.js b/app/constants/colors.js
index 145e665be..276ceda23 100644
--- a/app/constants/colors.js
+++ b/app/constants/colors.js
@@ -1,2 +1,8 @@
export const AVATAR_COLORS = ['#F44336', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5', '#2196F3', '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A', '#CDDC39', '#FFC107', '#FF9800', '#FF5722', '#795548', '#9E9E9E', '#607D8B'];
export const ESLINT_FIX = null;
+export const STATUS_COLORS = {
+ online: '#2de0a5',
+ busy: '#f5455c',
+ away: '#ffd21f',
+ offline: '#cbced1'
+};
diff --git a/app/containers/Header.js b/app/containers/Header.js
new file mode 100644
index 000000000..4ffa7d9e9
--- /dev/null
+++ b/app/containers/Header.js
@@ -0,0 +1,212 @@
+import React from 'react';
+import { Text, View, StyleSheet, Platform, TouchableOpacity, Dimensions } from 'react-native';
+import Icon from 'react-native-vector-icons/Ionicons';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import Modal from 'react-native-modal';
+import { SafeAreaView } from 'react-navigation';
+
+import DrawerMenuButton from '../presentation/DrawerMenuButton';
+import Avatar from './Avatar';
+import RocketChat from '../lib/rocketchat';
+import { STATUS_COLORS } from '../constants/colors';
+
+const TITLE_OFFSET = Platform.OS === 'ios' ? 70 : 56;
+
+let platformContainerStyles;
+if (Platform.OS === 'ios') {
+ platformContainerStyles = {
+ borderBottomWidth: StyleSheet.hairlineWidth,
+ borderBottomColor: 'rgba(0, 0, 0, .3)'
+ };
+} else {
+ platformContainerStyles = {
+ shadowColor: 'black',
+ shadowOpacity: 0.1,
+ shadowRadius: StyleSheet.hairlineWidth,
+ shadowOffset: {
+ height: StyleSheet.hairlineWidth
+ },
+ elevation: 4
+ };
+}
+
+const appBarHeight = Platform.OS === 'ios' ? 44 : 56;
+const { width } = Dimensions.get('window');
+const styles = StyleSheet.create({
+ container: {
+ backgroundColor: Platform.OS === 'ios' ? '#F7F7F7' : '#FFF',
+ height: appBarHeight,
+ ...platformContainerStyles
+ },
+ appBar: {
+ flex: 1
+ },
+ header: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ flex: 1
+ },
+ titleContainer: {
+ left: TITLE_OFFSET,
+ right: TITLE_OFFSET,
+ position: 'absolute',
+ alignItems: 'center',
+ justifyContent: Platform.OS === 'ios' ? 'center' : 'flex-start',
+ flexDirection: 'row'
+ },
+ status: {
+ borderRadius: 4,
+ width: 8,
+ height: 8,
+ marginRight: 10
+ },
+ avatar: {
+ marginRight: 10
+ },
+ title: {
+ fontWeight: 'bold'
+ },
+ left: {
+ left: 0,
+ position: 'absolute'
+ },
+ right: {
+ right: 0,
+ position: 'absolute'
+ },
+ modal: {
+ width: width - 60,
+ height: width - 60,
+ backgroundColor: '#F7F7F7',
+ borderRadius: 4,
+ flexDirection: 'column'
+ },
+ modalButton: {
+ flex: 1,
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: 'transparent',
+ borderBottomWidth: StyleSheet.hairlineWidth,
+ borderBottomColor: 'rgba(0, 0, 0, .3)',
+ paddingHorizontal: 20
+ }
+});
+
+@connect(state => ({
+ user: state.login.user,
+ Site_Url: state.settings.Site_Url
+}))
+export default class extends React.PureComponent {
+ static propTypes = {
+ navigation: PropTypes.object.isRequired,
+ user: PropTypes.object.isRequired,
+ Site_Url: PropTypes.string
+ }
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ isModalVisible: false
+ };
+ }
+
+ onPressModalButton(status) {
+ RocketChat.setUserPresenceDefaultStatus(status);
+ this.hideModal();
+ }
+
+ showModal() {
+ this.setState({ isModalVisible: true });
+ }
+
+ hideModal() {
+ this.setState({ isModalVisible: false });
+ }
+
+ createChannel() {
+ this.props.navigation.navigate('SelectUsers');
+ }
+
+ renderTitle() {
+ if (!this.props.user.username) {
+ return null;
+ }
+ return (
+ this.showModal()}>
+
+
+ {this.props.user.username}
+
+ );
+ }
+
+ renderRight() {
+ if (Platform.OS !== 'ios') {
+ return;
+ }
+ return (
+
+ this.createChannel()}
+ />
+
+ );
+ }
+
+ renderModalButton = (status, text) => {
+ const statusStyle = [styles.status, { backgroundColor: STATUS_COLORS[status] }];
+ const textStyle = { flex: 1, fontWeight: this.props.user.status === status ? 'bold' : 'normal' };
+ return (
+ this.onPressModalButton(status)}
+ >
+
+
+ {text || status.charAt(0).toUpperCase() + status.slice(1)}
+
+
+ );
+ };
+
+ render() {
+ return (
+
+
+
+
+
+
+ {this.renderTitle()}
+ {this.renderRight()}
+
+
+ this.hideModal()}
+ onBackdropPress={() => this.hideModal()}
+ >
+
+ {this.renderModalButton('online')}
+ {this.renderModalButton('busy')}
+ {this.renderModalButton('away')}
+ {this.renderModalButton('offline', 'Invisible')}
+
+
+
+ );
+ }
+}
diff --git a/app/containers/routes/AuthRoutes.js b/app/containers/routes/AuthRoutes.js
index d39bc8a6e..95cbd0a9d 100644
--- a/app/containers/routes/AuthRoutes.js
+++ b/app/containers/routes/AuthRoutes.js
@@ -4,6 +4,7 @@ import { StackNavigator, DrawerNavigator } from 'react-navigation';
import Sidebar from '../../containers/Sidebar';
import DrawerMenuButton from '../../presentation/DrawerMenuButton';
+import Header from '../../containers/Header';
import RoomsListView from '../../views/RoomsListView';
import RoomView from '../../views/RoomView';
@@ -20,7 +21,7 @@ const AuthRoutes = StackNavigator(
navigationOptions({ navigation }) {
return {
title: 'Rooms',
- [drawerIconPosition]:
+ header:
};
}
},
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index 885900b6d..4b2c6abee 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -9,6 +9,7 @@ import settingsType from '../constants/settings';
import realm from './realm';
import * as actions from '../actions';
import { someoneTyping } from '../actions/room';
+import { setUser } from '../actions/login';
import { disconnect, connectSuccess } from '../actions/connect';
export { Accounts } from 'react-native-meteor';
@@ -94,6 +95,9 @@ const RocketChat = {
});
}
}
+ if (ddpMessage.collection === 'users') {
+ return reduxStore.dispatch(setUser({ status: ddpMessage.fields.status || ddpMessage.fields.statusDefault }));
+ }
});
RocketChat.getSettings();
RocketChat.getPermissions();
@@ -432,6 +436,7 @@ const RocketChat = {
});
Meteor.subscribe('stream-notify-user', `${ login.user.id }/subscriptions-changed`, false);
Meteor.subscribe('stream-notify-user', `${ login.user.id }/rooms-changed`, false);
+ Meteor.subscribe('userData', null, false);
return data;
},
logout({ server }) {
@@ -526,6 +531,9 @@ const RocketChat = {
},
setUserPresenceOnline() {
return call('UserPresence:online');
+ },
+ setUserPresenceDefaultStatus(status) {
+ return call('UserPresence:setDefaultStatus', status);
}
};
diff --git a/app/reducers/login.js b/app/reducers/login.js
index 83b3187b6..37d72ef63 100644
--- a/app/reducers/login.js
+++ b/app/reducers/login.js
@@ -107,6 +107,14 @@ export default function login(state = initialState, action) {
failure: true,
error: action.err
};
+ case types.USER.SET:
+ return {
+ ...state,
+ user: {
+ ...state.user,
+ ...action
+ }
+ };
default:
return state;
}
diff --git a/app/views/RoomsListView.js b/app/views/RoomsListView.js
index a9277ec9c..ecf68643a 100644
--- a/app/views/RoomsListView.js
+++ b/app/views/RoomsListView.js
@@ -79,24 +79,6 @@ export default class RoomsListView extends React.Component {
server: PropTypes.string
}
- static navigationOptions = ({ navigation }) => {
- if (Platform.OS !== 'ios') {
- return;
- }
-
- const { params = {} } = navigation.state;
- const headerRight = (
- );
-
- return { headerRight };
- };
-
constructor(props) {
super(props);