diff --git a/app/constants/settings.js b/app/constants/settings.js
index 8e8e9b8c8..f22949ea0 100644
--- a/app/constants/settings.js
+++ b/app/constants/settings.js
@@ -14,6 +14,9 @@ export default {
CROWD_Enable: {
type: 'valueAsBoolean'
},
+ FEDERATION_Enabled: {
+ type: 'valueAsBoolean'
+ },
LDAP_Enable: {
type: 'valueAsBoolean'
},
diff --git a/app/containers/Check.js b/app/containers/Check.js
new file mode 100644
index 000000000..30c9cbd31
--- /dev/null
+++ b/app/containers/Check.js
@@ -0,0 +1,18 @@
+import React from 'react';
+import { StyleSheet } from 'react-native';
+
+import { CustomIcon } from '../lib/Icons';
+import sharedStyles from '../views/Styles';
+
+const styles = StyleSheet.create({
+ icon: {
+ width: 22,
+ height: 22,
+ marginHorizontal: 15,
+ ...sharedStyles.textColorDescription
+ }
+});
+
+const Check = React.memo(() => );
+
+export default Check;
diff --git a/app/containers/SearchBox.js b/app/containers/SearchBox.js
index 65a41d3ee..87a3cd8e3 100644
--- a/app/containers/SearchBox.js
+++ b/app/containers/SearchBox.js
@@ -34,7 +34,7 @@ const styles = StyleSheet.create({
}
});
-const SearchBox = ({ onChangeText, testID }) => (
+const SearchBox = ({ onChangeText, onSubmitEditing, testID }) => (
@@ -49,6 +49,7 @@ const SearchBox = ({ onChangeText, testID }) => (
testID={testID}
underlineColorAndroid='transparent'
onChangeText={onChangeText}
+ onSubmitEditing={onSubmitEditing}
/>
@@ -56,6 +57,7 @@ const SearchBox = ({ onChangeText, testID }) => (
SearchBox.propTypes = {
onChangeText: PropTypes.func.isRequired,
+ onSubmitEditing: PropTypes.func,
testID: PropTypes.string
};
diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js
index 62b4f117a..a426f0ddb 100644
--- a/app/i18n/locales/en.js
+++ b/app/i18n/locales/en.js
@@ -142,9 +142,10 @@ export default {
DELETE: 'DELETE',
description: 'description',
Description: 'Description',
+ Directory: 'Directory',
+ Direct_Messages: 'Direct Messages',
Disable_notifications: 'Disable notifications',
Discussions: 'Discussions',
- Direct_Messages: 'Direct Messages',
Dont_Have_An_Account: 'Don\'t have an account?',
Do_you_really_want_to_key_this_room_question_mark: 'Do you really want to {{key}} this room?',
edit: 'edit',
@@ -294,6 +295,9 @@ export default {
saving_settings: 'saving settings',
Search_Messages: 'Search Messages',
Search: 'Search',
+ Search_by: 'Search by',
+ Search_global_users: 'Search for global users',
+ Search_global_users_description: 'If you turn-on, you can search for any user from others companies or servers.',
Select_Avatar: 'Select Avatar',
Select_Users: 'Select Users',
Send: 'Send',
@@ -348,6 +352,7 @@ export default {
Updating: 'Updating...',
Uploading: 'Uploading',
Upload_file_question_mark: 'Upload file?',
+ Users: 'Users',
User_added_by: 'User {{userAdded}} added by {{userBy}}',
User_has_been_key: 'User has been {{key}}!',
User_is_no_longer_role_by_: '{{user}} is no longer {{role}} by {{userBy}}',
diff --git a/app/i18n/locales/pt-BR.js b/app/i18n/locales/pt-BR.js
index 859b4f299..ef13d05cf 100644
--- a/app/i18n/locales/pt-BR.js
+++ b/app/i18n/locales/pt-BR.js
@@ -146,11 +146,12 @@ export default {
delete: 'excluir',
Delete: 'Excluir',
DELETE: 'EXCLUIR',
+ Direct_Messages: 'Mensagens Diretas',
+ Directory: 'Diretório',
description: 'descrição',
Description: 'Descrição',
Disable_notifications: 'Desabilitar notificações',
Discussions: 'Discussões',
- Direct_Messages: 'Mensagens Diretas',
Dont_Have_An_Account: 'Não tem uma conta?',
Do_you_really_want_to_key_this_room_question_mark: 'Você quer realmente {{key}} esta sala?',
edit: 'editar',
@@ -293,6 +294,9 @@ export default {
saving_settings: 'salvando configurações',
Search_Messages: 'Buscar Mensagens',
Search: 'Buscar',
+ Search_by: 'Buscar por',
+ Search_global_users: 'Busca por usuários globais',
+ Search_global_users_description: 'Caso ativado, busca por usuários de outras empresas ou servidores.',
Select_Avatar: 'Selecionar Avatar',
Select_Users: 'Selecionar Usuários',
Send: 'Enviar',
@@ -344,6 +348,7 @@ export default {
Updating: 'Atualizando...',
Uploading: 'Subindo arquivo',
Upload_file_question_mark: 'Enviar arquivo?',
+ Users: 'Usuários',
User_added_by: 'Usuário {{userAdded}} adicionado por {{userBy}}',
User_has_been_key: 'Usuário foi {{key}}!',
User_is_no_longer_role_by_: '{{user}} não pertence mais à {{role}} por {{userBy}}',
diff --git a/app/index.js b/app/index.js
index 9ee8cc9f8..33c491561 100644
--- a/app/index.js
+++ b/app/index.js
@@ -16,6 +16,7 @@ import AuthLoadingView from './views/AuthLoadingView';
import RoomsListView from './views/RoomsListView';
import RoomView from './views/RoomView';
import NewMessageView from './views/NewMessageView';
+import DirectoryView from './views/DirectoryView';
import LoginView from './views/LoginView';
import Navigation from './lib/Navigation';
import Sidebar from './views/SidebarView';
@@ -110,7 +111,8 @@ const ChatsStack = createStackNavigator({
SearchMessagesView,
SelectedUsersView,
ThreadMessagesView,
- MessagesView
+ MessagesView,
+ DirectoryView
}, {
defaultNavigationOptions: defaultHeader
});
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index 9b7e16e2c..3c7f622e5 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -5,7 +5,7 @@ import { Rocketchat as RocketchatClient } from '@rocket.chat/sdk';
import reduxStore from './createStore';
import defaultSettings from '../constants/settings';
import messagesStatus from '../constants/messagesStatus';
-import database, { safeAddListener } from './realm';
+import database from './realm';
import log from '../utils/log';
import { isIOS, getBundleId } from '../utils/deviceInfo';
import EventEmitter from '../utils/events';
@@ -57,23 +57,6 @@ const RocketChat = {
// RC 0.51.0
return this.sdk.methodCall(type ? 'createPrivateGroup' : 'createChannel', name, users, readOnly, {}, { broadcast });
},
- async createDirectMessageAndWait(username) {
- const room = await RocketChat.createDirectMessage(username);
- return new Promise((resolve) => {
- const data = database.objects('subscriptions')
- .filtered('rid = $1', room.rid);
-
- if (data.length) {
- return resolve(data[0]);
- }
- safeAddListener(data, () => {
- if (!data.length) { return; }
- data.removeAllListeners();
- resolve(data[0]);
- });
- });
- },
-
async getUserToken() {
try {
return await AsyncStorage.getItem(TOKEN_KEY);
@@ -849,6 +832,14 @@ const RocketChat = {
this.sdk.subscribe('stream-notify-logged', 'user-status');
}
}
+ },
+ getDirectory({
+ query, count, offset, sort
+ }) {
+ // RC 1.0
+ return this.sdk.get('directory', {
+ query, count, offset, sort
+ });
}
};
diff --git a/app/views/DirectoryView/DirectoryItem.js b/app/views/DirectoryView/DirectoryItem.js
new file mode 100644
index 000000000..620f5dae0
--- /dev/null
+++ b/app/views/DirectoryView/DirectoryItem.js
@@ -0,0 +1,63 @@
+import React from 'react';
+import { Text, View } from 'react-native';
+import PropTypes from 'prop-types';
+
+import Avatar from '../../containers/Avatar';
+import Touch from '../../utils/touch';
+import RoomTypeIcon from '../../containers/RoomTypeIcon';
+import styles from './styles';
+
+const DirectoryItemLabel = React.memo(({ text }) => {
+ if (!text) {
+ return null;
+ }
+ return {text};
+});
+
+const DirectoryItem = ({
+ title, description, avatar, onPress, testID, style, baseUrl, user, rightLabel, type
+}) => (
+
+
+
+
+
+
+ {title}
+
+ {description}
+
+
+
+
+);
+
+DirectoryItem.propTypes = {
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ avatar: PropTypes.string,
+ type: PropTypes.string,
+ user: PropTypes.shape({
+ id: PropTypes.string,
+ token: PropTypes.string
+ }),
+ baseUrl: PropTypes.string.isRequired,
+ onPress: PropTypes.func.isRequired,
+ testID: PropTypes.string.isRequired,
+ style: PropTypes.any,
+ rightLabel: PropTypes.string
+};
+
+DirectoryItemLabel.propTypes = {
+ text: PropTypes.string
+};
+
+export default DirectoryItem;
diff --git a/app/views/DirectoryView/Options.js b/app/views/DirectoryView/Options.js
new file mode 100644
index 000000000..841484152
--- /dev/null
+++ b/app/views/DirectoryView/Options.js
@@ -0,0 +1,121 @@
+import React, { PureComponent } from 'react';
+import {
+ View, Text, Animated, Easing, TouchableWithoutFeedback, Switch
+} from 'react-native';
+import PropTypes from 'prop-types';
+
+import Touch from '../../utils/touch';
+import styles from './styles';
+import { CustomIcon } from '../../lib/Icons';
+import Check from '../../containers/Check';
+import I18n from '../../i18n';
+
+const ANIMATION_DURATION = 200;
+const ANIMATION_PROPS = {
+ duration: ANIMATION_DURATION,
+ easing: Easing.inOut(Easing.quad),
+ useNativeDriver: true
+};
+
+export default class DirectoryOptions extends PureComponent {
+ static propTypes = {
+ type: PropTypes.string,
+ globalUsers: PropTypes.bool,
+ isFederationEnabled: PropTypes.bool,
+ close: PropTypes.func,
+ changeType: PropTypes.func,
+ toggleWorkspace: PropTypes.func
+ }
+
+ constructor(props) {
+ super(props);
+ this.animatedValue = new Animated.Value(0);
+ }
+
+ componentDidMount() {
+ Animated.timing(
+ this.animatedValue,
+ {
+ toValue: 1,
+ ...ANIMATION_PROPS
+ },
+ ).start();
+ }
+
+ close = () => {
+ const { close } = this.props;
+ Animated.timing(
+ this.animatedValue,
+ {
+ toValue: 0,
+ ...ANIMATION_PROPS
+ },
+ ).start(() => close());
+ }
+
+ renderItem = (itemType) => {
+ const { changeType, type: propType } = this.props;
+ let text = 'Users';
+ let icon = 'user';
+ if (itemType === 'channels') {
+ text = 'Channels';
+ icon = 'hashtag';
+ }
+
+ return (
+ changeType(itemType)}>
+
+
+ {I18n.t(text)}
+ {propType === itemType ? : null}
+
+
+ );
+ }
+
+ render() {
+ const translateY = this.animatedValue.interpolate({
+ inputRange: [0, 1],
+ outputRange: [-326, 0]
+ });
+ const backdropOpacity = this.animatedValue.interpolate({
+ inputRange: [0, 1],
+ outputRange: [0, 0.3]
+ });
+ const { globalUsers, toggleWorkspace, isFederationEnabled } = this.props;
+ return (
+
+
+
+
+
+
+
+ {I18n.t('Search_by')}
+
+
+
+ {this.renderItem('channels')}
+ {this.renderItem('users')}
+ {isFederationEnabled
+ ? (
+
+
+
+
+ {I18n.t('Search_global_users')}
+ {I18n.t('Search_global_users_description')}
+
+
+
+
+ )
+ : null}
+
+
+ );
+ }
+}
diff --git a/app/views/DirectoryView/index.js b/app/views/DirectoryView/index.js
new file mode 100644
index 000000000..60a12932e
--- /dev/null
+++ b/app/views/DirectoryView/index.js
@@ -0,0 +1,248 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+ View, FlatList, Text
+} from 'react-native';
+import { connect } from 'react-redux';
+import { SafeAreaView } from 'react-navigation';
+
+import RocketChat from '../../lib/rocketchat';
+import DirectoryItem from './DirectoryItem';
+import sharedStyles from '../Styles';
+import I18n from '../../i18n';
+import Touch from '../../utils/touch';
+import SearchBox from '../../containers/SearchBox';
+import { CustomIcon } from '../../lib/Icons';
+import StatusBar from '../../containers/StatusBar';
+import RCActivityIndicator from '../../containers/ActivityIndicator';
+import debounce from '../../utils/debounce';
+import log from '../../utils/log';
+import Options from './Options';
+import styles from './styles';
+
+@connect(state => ({
+ baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
+ user: {
+ id: state.login.user && state.login.user.id,
+ token: state.login.user && state.login.user.token
+ },
+ isFederationEnabled: state.settings.FEDERATION_Enabled
+}))
+export default class DirectoryView extends React.Component {
+ static navigationOptions = () => ({
+ title: I18n.t('Directory')
+ })
+
+ static propTypes = {
+ navigation: PropTypes.object,
+ baseUrl: PropTypes.string,
+ isFederationEnabled: PropTypes.bool,
+ user: PropTypes.shape({
+ id: PropTypes.string,
+ token: PropTypes.string
+ })
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ data: [],
+ loading: false,
+ text: '',
+ total: -1,
+ showOptionsDropdown: false,
+ globalUsers: true,
+ type: 'channels'
+ };
+ }
+
+ componentDidMount() {
+ this.load({});
+ }
+
+ onSearchChangeText = (text) => {
+ this.setState({ text });
+ }
+
+ onPressItem = (item) => {
+ const { navigation } = this.props;
+ try {
+ const onPressItem = navigation.getParam('onPressItem', () => {});
+ onPressItem(item);
+ } catch (error) {
+ console.log('DirectoryView -> onPressItem -> error', error);
+ }
+ }
+
+ // eslint-disable-next-line react/sort-comp
+ load = debounce(async({ newSearch = false }) => {
+ if (newSearch) {
+ this.setState({ data: [], total: -1, loading: false });
+ }
+
+ const {
+ loading, text, total, data: { length }
+ } = this.state;
+ if (loading || length === total) {
+ return;
+ }
+
+ this.setState({ loading: true });
+
+ try {
+ const { data, type, globalUsers } = this.state;
+ const query = { text, type, workspace: globalUsers ? 'all' : 'local' };
+ const directories = await RocketChat.getDirectory({
+ query,
+ offset: data.length,
+ count: 50,
+ sort: (type === 'users') ? { username: 1 } : { usersCount: -1 }
+ });
+ if (directories.success) {
+ this.setState({
+ data: [...data, ...directories.result],
+ loading: false,
+ total: directories.total
+ });
+ } else {
+ this.setState({ loading: false });
+ }
+ } catch (error) {
+ log('err_load_directory', error);
+ this.setState({ loading: false });
+ }
+ }, 200)
+
+ search = () => {
+ this.load({ newSearch: true });
+ }
+
+ changeType = (type) => {
+ this.setState({ type, data: [] }, () => this.search());
+ }
+
+ toggleWorkspace = () => {
+ this.setState(({ globalUsers }) => ({ globalUsers: !globalUsers, data: [] }), () => this.search());
+ }
+
+ toggleDropdown = () => {
+ this.setState(({ showOptionsDropdown }) => ({ showOptionsDropdown: !showOptionsDropdown }));
+ }
+
+ goRoom = async({ rid, name, t }) => {
+ const { navigation } = this.props;
+ await navigation.navigate('RoomsListView');
+ navigation.navigate('RoomView', { rid, name, t });
+ }
+
+ onPressItem = async(item) => {
+ const { type } = this.state;
+ if (type === 'users') {
+ const result = await RocketChat.createDirectMessage(item.username);
+ if (result.success) {
+ this.goRoom({ rid: result.room._id, name: item.username, t: 'd' });
+ }
+ } else {
+ this.goRoom({ rid: item._id, name: item.name, t: 'c' });
+ }
+ }
+
+ renderHeader = () => {
+ const { type } = this.state;
+ return (
+
+
+
+
+
+ {type === 'users' ? I18n.t('Users') : I18n.t('Channels')}
+
+
+
+
+ );
+ }
+
+ renderSeparator = () => ;
+
+ renderItem = ({ item, index }) => {
+ const { data, type } = this.state;
+ const { baseUrl, user } = this.props;
+
+ let style;
+ if (index === data.length - 1) {
+ style = sharedStyles.separatorBottom;
+ }
+
+ const commonProps = {
+ title: item.name,
+ onPress: () => this.onPressItem(item),
+ baseUrl,
+ testID: `federation-view-item-${ item.name }`,
+ style,
+ user
+ };
+
+ if (type === 'users') {
+ return (
+
+ );
+ }
+ return (
+
+ );
+ }
+
+ render = () => {
+ const {
+ data, loading, showOptionsDropdown, type, globalUsers
+ } = this.state;
+ const { isFederationEnabled } = this.props;
+ return (
+
+
+ item._id}
+ ListHeaderComponent={this.renderHeader}
+ renderItem={this.renderItem}
+ ItemSeparatorComponent={this.renderSeparator}
+ keyboardShouldPersistTaps='always'
+ ListFooterComponent={loading ? : null}
+ onEndReached={() => this.load({})}
+ />
+ {showOptionsDropdown
+ ? (
+
+ )
+ : null}
+
+ );
+ }
+}
diff --git a/app/views/DirectoryView/styles.js b/app/views/DirectoryView/styles.js
new file mode 100644
index 000000000..59e60da2b
--- /dev/null
+++ b/app/views/DirectoryView/styles.js
@@ -0,0 +1,151 @@
+import { StyleSheet } from 'react-native';
+
+import { COLOR_WHITE, COLOR_SEPARATOR, COLOR_PRIMARY } from '../../constants/colors';
+import { isIOS } from '../../utils/deviceInfo';
+import sharedStyles from '../Styles';
+
+export default StyleSheet.create({
+ safeAreaView: {
+ flex: 1,
+ backgroundColor: isIOS ? '#F7F8FA' : '#E1E5E8'
+ },
+ list: {
+ flex: 1
+ },
+ listContainer: {
+ paddingBottom: 30
+ },
+ separator: {
+ marginLeft: 60
+ },
+ toggleDropdownContainer: {
+ height: 47,
+ backgroundColor: COLOR_WHITE,
+ flexDirection: 'row',
+ alignItems: 'center'
+ },
+ toggleDropdownIcon: {
+ color: COLOR_PRIMARY,
+ marginLeft: 20,
+ marginRight: 17
+ },
+ toggleDropdownText: {
+ flex: 1,
+ color: COLOR_PRIMARY,
+ fontSize: 17,
+ ...sharedStyles.textRegular
+ },
+ toggleDropdownArrow: {
+ ...sharedStyles.textColorDescription,
+ marginRight: 15
+ },
+ dropdownContainer: {
+ backgroundColor: COLOR_WHITE,
+ width: '100%',
+ position: 'absolute',
+ top: 0
+ },
+ backdrop: {
+ ...StyleSheet.absoluteFill,
+ backgroundColor: '#000000'
+ },
+ dropdownContainerHeader: {
+ height: 47,
+ borderBottomWidth: StyleSheet.hairlineWidth,
+ borderColor: COLOR_SEPARATOR,
+ alignItems: 'center',
+ backgroundColor: isIOS ? COLOR_WHITE : '#54585E',
+ flexDirection: 'row'
+ },
+ dropdownItemButton: {
+ height: 57,
+ justifyContent: 'center'
+ },
+ dropdownItemContainer: {
+ flex: 1,
+ flexDirection: 'row',
+ alignItems: 'center'
+ },
+ dropdownItemText: {
+ fontSize: 18,
+ flex: 1,
+ ...sharedStyles.textColorNormal,
+ ...sharedStyles.textRegular
+ },
+ dropdownItemDescription: {
+ fontSize: 14,
+ flex: 1,
+ marginTop: 2,
+ ...sharedStyles.textColorDescription,
+ ...sharedStyles.textRegular
+ },
+ dropdownToggleText: {
+ fontSize: 15,
+ flex: 1,
+ marginLeft: 15,
+ ...sharedStyles.textColorDescription,
+ ...sharedStyles.textRegular
+ },
+ dropdownItemIcon: {
+ width: 22,
+ height: 22,
+ marginHorizontal: 15,
+ ...sharedStyles.textColorDescription
+ },
+ dropdownSeparator: {
+ height: StyleSheet.hairlineWidth,
+ backgroundColor: COLOR_SEPARATOR,
+ marginHorizontal: 15,
+ flex: 1
+ },
+ directoryItemButton: {
+ height: 54,
+ backgroundColor: COLOR_WHITE
+ },
+ directoryItemContainer: {
+ flex: 1,
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ paddingHorizontal: 15
+ },
+ directoryItemAvatar: {
+ marginRight: 12
+ },
+ directoryItemTextTitle: {
+ flexDirection: 'row',
+ alignItems: 'center'
+ },
+ directoryItemTextContainer: {
+ flex: 1,
+ flexDirection: 'column',
+ justifyContent: 'center'
+ },
+ directoryItemName: {
+ flex: 1,
+ fontSize: 17,
+ ...sharedStyles.textMedium,
+ ...sharedStyles.textColorNormal
+ },
+ directoryItemUsername: {
+ fontSize: 14,
+ ...sharedStyles.textRegular,
+ ...sharedStyles.textColorDescription
+ },
+ directoryItemLabel: {
+ fontSize: 14,
+ paddingLeft: 10,
+ ...sharedStyles.textRegular,
+ ...sharedStyles.textColorDescription
+ },
+ inverted: {
+ transform: [{ scaleY: -1 }]
+ },
+ globalUsersContainer: {
+ padding: 15
+ },
+ globalUsersTextContainer: {
+ flex: 1,
+ flexDirection: 'column'
+ }
+});
diff --git a/app/views/NewMessageView.js b/app/views/NewMessageView.js
index c2f495ea0..cfadd6094 100644
--- a/app/views/NewMessageView.js
+++ b/app/views/NewMessageView.js
@@ -40,7 +40,8 @@ const styles = StyleSheet.create({
},
createChannelIcon: {
color: COLOR_PRIMARY,
- marginHorizontal: 18
+ marginLeft: 18,
+ marginRight: 15
},
createChannelText: {
color: COLOR_PRIMARY,
diff --git a/app/views/RoomsListView/Check.js b/app/views/RoomsListView/Check.js
deleted file mode 100644
index 42685ba0a..000000000
--- a/app/views/RoomsListView/Check.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react';
-
-import { CustomIcon } from '../../lib/Icons';
-import styles from './styles';
-
-const Check = React.memo(() => );
-
-export default Check;
diff --git a/app/views/RoomsListView/ListHeader/Directory.js b/app/views/RoomsListView/ListHeader/Directory.js
new file mode 100644
index 000000000..0e83ec175
--- /dev/null
+++ b/app/views/RoomsListView/ListHeader/Directory.js
@@ -0,0 +1,30 @@
+import React from 'react';
+import { View, Text } from 'react-native';
+import PropTypes from 'prop-types';
+
+import { CustomIcon } from '../../../lib/Icons';
+import I18n from '../../../i18n';
+import Touch from '../../../utils/touch';
+import styles from '../styles';
+import DisclosureIndicator from '../../../containers/DisclosureIndicator';
+
+
+const Directory = React.memo(({ goDirectory }) => (
+
+
+
+ {I18n.t('Directory')}
+
+
+
+));
+
+Directory.propTypes = {
+ goDirectory: PropTypes.func
+};
+
+export default Directory;
diff --git a/app/views/RoomsListView/ListHeader/index.js b/app/views/RoomsListView/ListHeader/index.js
index 92743b39d..fd35f0b57 100644
--- a/app/views/RoomsListView/ListHeader/index.js
+++ b/app/views/RoomsListView/ListHeader/index.js
@@ -2,13 +2,15 @@ import React from 'react';
import PropTypes from 'prop-types';
import SearchBar from './SearchBar';
+import Directory from './Directory';
import Sort from './Sort';
const ListHeader = React.memo(({
- searchLength, sortBy, onChangeSearchText, toggleSort
+ searchLength, sortBy, onChangeSearchText, toggleSort, goDirectory
}) => (
+
));
@@ -17,7 +19,8 @@ ListHeader.propTypes = {
searchLength: PropTypes.number,
sortBy: PropTypes.string,
onChangeSearchText: PropTypes.func,
- toggleSort: PropTypes.func
+ toggleSort: PropTypes.func,
+ goDirectory: PropTypes.func
};
export default ListHeader;
diff --git a/app/views/RoomsListView/ServerDropdown.js b/app/views/RoomsListView/ServerDropdown.js
index 795344609..4bc8db9d1 100644
--- a/app/views/RoomsListView/ServerDropdown.js
+++ b/app/views/RoomsListView/ServerDropdown.js
@@ -16,7 +16,7 @@ import Touch from '../../utils/touch';
import RocketChat from '../../lib/rocketchat';
import I18n from '../../i18n';
import EventEmitter from '../../utils/events';
-import Check from './Check';
+import Check from '../../containers/Check';
const ROW_HEIGHT = 68;
const ANIMATION_DURATION = 200;
diff --git a/app/views/RoomsListView/SortDropdown.js b/app/views/RoomsListView/SortDropdown.js
index ea7efaefe..163b4d1e7 100644
--- a/app/views/RoomsListView/SortDropdown.js
+++ b/app/views/RoomsListView/SortDropdown.js
@@ -12,7 +12,7 @@ import { setPreference } from '../../actions/sortPreferences';
import log from '../../utils/log';
import I18n from '../../i18n';
import { CustomIcon } from '../../lib/Icons';
-import Check from './Check';
+import Check from '../../containers/Check';
const ANIMATION_DURATION = 200;
@@ -106,7 +106,7 @@ export default class Sort extends PureComponent {
render() {
const translateY = this.animatedValue.interpolate({
inputRange: [0, 1],
- outputRange: [-245, 41]
+ outputRange: [-326, 0]
});
const backdropOpacity = this.animatedValue.interpolate({
inputRange: [0, 1],
@@ -117,14 +117,24 @@ export default class Sort extends PureComponent {
} = this.props;
return (
- [
+
- ,
+
+
+
+ {I18n.t('Sorting_by', { key: I18n.t(sortBy === 'alphabetical' ? 'name' : 'activity') })}
+
+
+
@@ -161,18 +171,8 @@ export default class Sort extends PureComponent {
{showUnread ? : null}
- ,
-
-
- {I18n.t('Sorting_by', { key: I18n.t(sortBy === 'alphabetical' ? 'name' : 'activity') })}
-
-
-
- ]
+
+
);
}
}
diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js
index d3574c339..f29d62348 100644
--- a/app/views/RoomsListView/index.js
+++ b/app/views/RoomsListView/index.js
@@ -379,6 +379,11 @@ export default class RoomsListView extends React.Component {
}, 100);
}
+ goDirectory = () => {
+ const { navigation } = this.props;
+ navigation.navigate('DirectoryView');
+ }
+
getScrollRef = ref => this.scroll = ref
renderListHeader = () => {
@@ -390,6 +395,7 @@ export default class RoomsListView extends React.Component {
sortBy={sortBy}
onChangeSearchText={this.search}
toggleSort={this.toggleSort}
+ goDirectory={this.goDirectory}
/>
);
}
diff --git a/app/views/RoomsListView/styles.js b/app/views/RoomsListView/styles.js
index 95c111664..0c19c11ee 100644
--- a/app/views/RoomsListView/styles.js
+++ b/app/views/RoomsListView/styles.js
@@ -1,7 +1,7 @@
import { StyleSheet } from 'react-native';
import { isIOS } from '../../utils/deviceInfo';
import {
- COLOR_SEPARATOR, COLOR_TEXT, COLOR_PRIMARY, COLOR_WHITE
+ COLOR_SEPARATOR, COLOR_TEXT, COLOR_PRIMARY, COLOR_WHITE, COLOR_TEXT_DESCRIPTION
} from '../../constants/colors';
import sharedStyles from '../Styles';
@@ -147,5 +147,17 @@ export default StyleSheet.create({
height: StyleSheet.hairlineWidth,
backgroundColor: COLOR_SEPARATOR,
marginLeft: 72
+ },
+ directoryIcon: {
+ width: 22,
+ height: 22,
+ marginHorizontal: 15,
+ color: isIOS ? COLOR_PRIMARY : COLOR_TEXT_DESCRIPTION
+ },
+ directoryText: {
+ fontSize: 15,
+ flex: 1,
+ color: isIOS ? COLOR_PRIMARY : COLOR_TEXT_DESCRIPTION,
+ ...sharedStyles.textRegular
}
});