|
|
@ -1,14 +1,13 @@
|
|
|
|
import React from 'react';
|
|
|
|
import React from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
View, FlatList, BackHandler, ActivityIndicator, Text, ScrollView, Keyboard, LayoutAnimation
|
|
|
|
View, FlatList, BackHandler, ActivityIndicator, Text, ScrollView, Keyboard, LayoutAnimation, InteractionManager
|
|
|
|
} from 'react-native';
|
|
|
|
} from 'react-native';
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
import { isEqual } from 'lodash';
|
|
|
|
import { isEqual } from 'lodash';
|
|
|
|
import { SafeAreaView, NavigationEvents } from 'react-navigation';
|
|
|
|
import { SafeAreaView, NavigationEvents } from 'react-navigation';
|
|
|
|
import Orientation from 'react-native-orientation-locker';
|
|
|
|
import Orientation from 'react-native-orientation-locker';
|
|
|
|
|
|
|
|
|
|
|
|
import SearchBox from '../../containers/SearchBox';
|
|
|
|
|
|
|
|
import ConnectionBadge from '../../containers/ConnectionBadge';
|
|
|
|
import ConnectionBadge from '../../containers/ConnectionBadge';
|
|
|
|
import database, { safeAddListener } from '../../lib/realm';
|
|
|
|
import database, { safeAddListener } from '../../lib/realm';
|
|
|
|
import RocketChat from '../../lib/rocketchat';
|
|
|
|
import RocketChat from '../../lib/rocketchat';
|
|
|
@ -19,7 +18,6 @@ import log from '../../utils/log';
|
|
|
|
import I18n from '../../i18n';
|
|
|
|
import I18n from '../../i18n';
|
|
|
|
import SortDropdown from './SortDropdown';
|
|
|
|
import SortDropdown from './SortDropdown';
|
|
|
|
import ServerDropdown from './ServerDropdown';
|
|
|
|
import ServerDropdown from './ServerDropdown';
|
|
|
|
import Touch from '../../utils/touch';
|
|
|
|
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
toggleSortDropdown as toggleSortDropdownAction,
|
|
|
|
toggleSortDropdown as toggleSortDropdownAction,
|
|
|
|
openSearchHeader as openSearchHeaderAction,
|
|
|
|
openSearchHeader as openSearchHeaderAction,
|
|
|
@ -29,10 +27,10 @@ import {
|
|
|
|
import { appStart as appStartAction } from '../../actions';
|
|
|
|
import { appStart as appStartAction } from '../../actions';
|
|
|
|
import debounce from '../../utils/debounce';
|
|
|
|
import debounce from '../../utils/debounce';
|
|
|
|
import { isIOS, isAndroid } from '../../utils/deviceInfo';
|
|
|
|
import { isIOS, isAndroid } from '../../utils/deviceInfo';
|
|
|
|
import { CustomIcon } from '../../lib/Icons';
|
|
|
|
|
|
|
|
import RoomsListHeaderView from './Header';
|
|
|
|
import RoomsListHeaderView from './Header';
|
|
|
|
import { DrawerButton, CustomHeaderButtons, Item } from '../../containers/HeaderButton';
|
|
|
|
import { DrawerButton, CustomHeaderButtons, Item } from '../../containers/HeaderButton';
|
|
|
|
import StatusBar from '../../containers/StatusBar';
|
|
|
|
import StatusBar from '../../containers/StatusBar';
|
|
|
|
|
|
|
|
import ListHeader from './ListHeader';
|
|
|
|
|
|
|
|
|
|
|
|
const SCROLL_OFFSET = 56;
|
|
|
|
const SCROLL_OFFSET = 56;
|
|
|
|
|
|
|
|
|
|
|
@ -119,6 +117,8 @@ export default class RoomsListView extends LoggedView {
|
|
|
|
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
constructor(props) {
|
|
|
|
super('RoomsListView', props);
|
|
|
|
super('RoomsListView', props);
|
|
|
|
|
|
|
|
console.time(`${ this.constructor.name } init`);
|
|
|
|
|
|
|
|
console.time(`${ this.constructor.name } mount`);
|
|
|
|
|
|
|
|
|
|
|
|
this.data = [];
|
|
|
|
this.data = [];
|
|
|
|
this.state = {
|
|
|
|
this.state = {
|
|
|
@ -143,6 +143,7 @@ export default class RoomsListView extends LoggedView {
|
|
|
|
navigation.setParams({
|
|
|
|
navigation.setParams({
|
|
|
|
onPressItem: this._onPressItem, initSearchingAndroid: this.initSearchingAndroid, cancelSearchingAndroid: this.cancelSearchingAndroid
|
|
|
|
onPressItem: this._onPressItem, initSearchingAndroid: this.initSearchingAndroid, cancelSearchingAndroid: this.cancelSearchingAndroid
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
console.timeEnd(`${ this.constructor.name } mount`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
@ -240,16 +241,19 @@ export default class RoomsListView extends LoggedView {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
componentWillUnmount() {
|
|
|
|
this.removeListener(this.data);
|
|
|
|
if (this.data && this.data.removeAllListeners) {
|
|
|
|
this.removeListener(this.unread);
|
|
|
|
this.data.removeAllListeners();
|
|
|
|
this.removeListener(this.favorites);
|
|
|
|
}
|
|
|
|
this.removeListener(this.discussions);
|
|
|
|
if (this.getSubscriptions && this.getSubscriptions.stop) {
|
|
|
|
this.removeListener(this.channels);
|
|
|
|
this.getSubscriptions.stop();
|
|
|
|
this.removeListener(this.privateGroup);
|
|
|
|
}
|
|
|
|
this.removeListener(this.direct);
|
|
|
|
if (this.updateStateInteraction && this.updateStateInteraction.cancel) {
|
|
|
|
this.removeListener(this.livechat);
|
|
|
|
this.updateStateInteraction.cancel();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
console.countReset(`${ this.constructor.name }.render calls`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// eslint-disable-next-line react/sort-comp
|
|
|
|
internalSetState = (...args) => {
|
|
|
|
internalSetState = (...args) => {
|
|
|
|
const { navigation } = this.props;
|
|
|
|
const { navigation } = this.props;
|
|
|
|
if (isIOS && navigation.isFocused()) {
|
|
|
|
if (isIOS && navigation.isFocused()) {
|
|
|
@ -258,7 +262,11 @@ export default class RoomsListView extends LoggedView {
|
|
|
|
this.setState(...args);
|
|
|
|
this.setState(...args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
getSubscriptions = () => {
|
|
|
|
getSubscriptions = debounce(() => {
|
|
|
|
|
|
|
|
if (this.data && this.data.removeAllListeners) {
|
|
|
|
|
|
|
|
this.data.removeAllListeners();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
const {
|
|
|
|
server, sortBy, showUnread, showFavorites, groupByType
|
|
|
|
server, sortBy, showUnread, showFavorites, groupByType
|
|
|
|
} = this.props;
|
|
|
|
} = this.props;
|
|
|
@ -271,92 +279,57 @@ export default class RoomsListView extends LoggedView {
|
|
|
|
this.data = this.data.sorted('roomUpdatedAt', true);
|
|
|
|
this.data = this.data.sorted('roomUpdatedAt', true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let chats = [];
|
|
|
|
|
|
|
|
let unread = [];
|
|
|
|
|
|
|
|
let favorites = [];
|
|
|
|
|
|
|
|
let discussions = [];
|
|
|
|
|
|
|
|
let channels = [];
|
|
|
|
|
|
|
|
let privateGroup = [];
|
|
|
|
|
|
|
|
let direct = [];
|
|
|
|
|
|
|
|
let livechat = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// unread
|
|
|
|
// unread
|
|
|
|
if (showUnread) {
|
|
|
|
if (showUnread) {
|
|
|
|
this.unread = this.data.filtered('(unread > 0 || alert == true)');
|
|
|
|
this.unread = this.data.filtered('(unread > 0 || alert == true)');
|
|
|
|
unread = this.removeRealmInstance(this.unread);
|
|
|
|
|
|
|
|
safeAddListener(this.unread, debounce(() => this.internalSetState({ unread: this.removeRealmInstance(this.unread) }), 300));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
this.removeListener(unread);
|
|
|
|
this.unread = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// favorites
|
|
|
|
// favorites
|
|
|
|
if (showFavorites) {
|
|
|
|
if (showFavorites) {
|
|
|
|
this.favorites = this.data.filtered('f == true');
|
|
|
|
this.favorites = this.data.filtered('f == true');
|
|
|
|
favorites = this.removeRealmInstance(this.favorites);
|
|
|
|
|
|
|
|
safeAddListener(this.favorites, debounce(() => this.internalSetState({ favorites: this.removeRealmInstance(this.favorites) }), 300));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
this.removeListener(favorites);
|
|
|
|
this.favorites = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// type
|
|
|
|
// type
|
|
|
|
if (groupByType) {
|
|
|
|
if (groupByType) {
|
|
|
|
// discussions
|
|
|
|
|
|
|
|
this.discussions = this.data.filtered('prid != null');
|
|
|
|
this.discussions = this.data.filtered('prid != null');
|
|
|
|
discussions = this.removeRealmInstance(this.discussions);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// channels
|
|
|
|
|
|
|
|
this.channels = this.data.filtered('t == $0 AND prid == null', 'c');
|
|
|
|
this.channels = this.data.filtered('t == $0 AND prid == null', 'c');
|
|
|
|
channels = this.removeRealmInstance(this.channels);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// private
|
|
|
|
|
|
|
|
this.privateGroup = this.data.filtered('t == $0 AND prid == null', 'p');
|
|
|
|
this.privateGroup = this.data.filtered('t == $0 AND prid == null', 'p');
|
|
|
|
privateGroup = this.removeRealmInstance(this.privateGroup);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// direct
|
|
|
|
|
|
|
|
this.direct = this.data.filtered('t == $0 AND prid == null', 'd');
|
|
|
|
this.direct = this.data.filtered('t == $0 AND prid == null', 'd');
|
|
|
|
direct = this.removeRealmInstance(this.direct);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// livechat
|
|
|
|
|
|
|
|
this.livechat = this.data.filtered('t == $0 AND prid == null', 'l');
|
|
|
|
this.livechat = this.data.filtered('t == $0 AND prid == null', 'l');
|
|
|
|
livechat = this.removeRealmInstance(this.livechat);
|
|
|
|
} else if (showUnread) {
|
|
|
|
|
|
|
|
this.chats = this.data.filtered('(unread == 0 && alert == false)');
|
|
|
|
safeAddListener(this.discussions, debounce(() => this.internalSetState({ discussions: this.removeRealmInstance(this.discussions) }), 300));
|
|
|
|
|
|
|
|
safeAddListener(this.channels, debounce(() => this.internalSetState({ channels: this.removeRealmInstance(this.channels) }), 300));
|
|
|
|
|
|
|
|
safeAddListener(this.privateGroup, debounce(() => this.internalSetState({ privateGroup: this.removeRealmInstance(this.privateGroup) }), 300));
|
|
|
|
|
|
|
|
safeAddListener(this.direct, debounce(() => this.internalSetState({ direct: this.removeRealmInstance(this.direct) }), 300));
|
|
|
|
|
|
|
|
safeAddListener(this.livechat, debounce(() => this.internalSetState({ livechat: this.removeRealmInstance(this.livechat) }), 300));
|
|
|
|
|
|
|
|
this.removeListener(this.chats);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// chats
|
|
|
|
this.chats = this.data;
|
|
|
|
if (showUnread) {
|
|
|
|
|
|
|
|
this.chats = this.data.filtered('(unread == 0 && alert == false)');
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.chats = this.data;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
chats = this.removeRealmInstance(this.chats);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
safeAddListener(this.chats, debounce(() => this.internalSetState({ chats: this.removeRealmInstance(this.chats) }), 300));
|
|
|
|
|
|
|
|
this.removeListener(this.discussions);
|
|
|
|
|
|
|
|
this.removeListener(this.channels);
|
|
|
|
|
|
|
|
this.removeListener(this.privateGroup);
|
|
|
|
|
|
|
|
this.removeListener(this.direct);
|
|
|
|
|
|
|
|
this.removeListener(this.livechat);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
safeAddListener(this.data, this.updateState);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
|
|
|
|
|
|
// setState
|
|
|
|
// eslint-disable-next-line react/sort-comp
|
|
|
|
|
|
|
|
updateState = debounce(() => {
|
|
|
|
|
|
|
|
this.updateStateInteraction = InteractionManager.runAfterInteractions(() => {
|
|
|
|
this.internalSetState({
|
|
|
|
this.internalSetState({
|
|
|
|
chats, unread, favorites, discussions, channels, privateGroup, direct, livechat, loading: false
|
|
|
|
chats: this.getSnapshot(this.chats),
|
|
|
|
|
|
|
|
unread: this.getSnapshot(this.unread),
|
|
|
|
|
|
|
|
favorites: this.getSnapshot(this.favorites),
|
|
|
|
|
|
|
|
discussions: this.getSnapshot(this.discussions),
|
|
|
|
|
|
|
|
channels: this.getSnapshot(this.channels),
|
|
|
|
|
|
|
|
privateGroup: this.getSnapshot(this.privateGroup),
|
|
|
|
|
|
|
|
direct: this.getSnapshot(this.direct),
|
|
|
|
|
|
|
|
livechat: this.getSnapshot(this.livechat),
|
|
|
|
|
|
|
|
loading: false
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}, 300);
|
|
|
|
|
|
|
|
|
|
|
|
removeRealmInstance = (data) => {
|
|
|
|
getSnapshot = (data) => {
|
|
|
|
const array = Array.from(data);
|
|
|
|
if (data && data.length) {
|
|
|
|
return JSON.parse(JSON.stringify(array));
|
|
|
|
const array = Array.from(data);
|
|
|
|
}
|
|
|
|
return JSON.parse(JSON.stringify(array));
|
|
|
|
|
|
|
|
|
|
|
|
removeListener = (data) => {
|
|
|
|
|
|
|
|
if (data && data.removeAllListeners) {
|
|
|
|
|
|
|
|
data.removeAllListeners();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
initSearchingAndroid = () => {
|
|
|
|
initSearchingAndroid = () => {
|
|
|
@ -449,44 +422,19 @@ export default class RoomsListView extends LoggedView {
|
|
|
|
|
|
|
|
|
|
|
|
getScrollRef = ref => this.scroll = ref
|
|
|
|
getScrollRef = ref => this.scroll = ref
|
|
|
|
|
|
|
|
|
|
|
|
renderHeader = () => {
|
|
|
|
renderListHeader = () => {
|
|
|
|
const { search } = this.state;
|
|
|
|
const { search } = this.state;
|
|
|
|
if (search.length > 0) {
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.renderSort();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
renderSort = () => {
|
|
|
|
|
|
|
|
const { sortBy } = this.props;
|
|
|
|
const { sortBy } = this.props;
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<Touch
|
|
|
|
<ListHeader
|
|
|
|
key='rooms-list-view-sort'
|
|
|
|
searchLength={search.length}
|
|
|
|
onPress={this.toggleSort}
|
|
|
|
sortBy={sortBy}
|
|
|
|
style={styles.dropdownContainerHeader}
|
|
|
|
onChangeSearchText={this.search}
|
|
|
|
>
|
|
|
|
toggleSort={this.toggleSort}
|
|
|
|
<View style={styles.sortItemContainer}>
|
|
|
|
/>
|
|
|
|
<Text style={styles.sortToggleText}>{I18n.t('Sorting_by', { key: I18n.t(sortBy === 'alphabetical' ? 'name' : 'activity') })}</Text>
|
|
|
|
|
|
|
|
<CustomIcon style={styles.sortIcon} size={22} name='sort1' />
|
|
|
|
|
|
|
|
</View>
|
|
|
|
|
|
|
|
</Touch>
|
|
|
|
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
renderSearchBar = () => {
|
|
|
|
|
|
|
|
if (isIOS) {
|
|
|
|
|
|
|
|
return <SearchBox onChangeText={this.search} testID='rooms-list-view-search' key='rooms-list-view-search' />;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
renderListHeader = () => (
|
|
|
|
|
|
|
|
[
|
|
|
|
|
|
|
|
this.renderSearchBar(),
|
|
|
|
|
|
|
|
this.renderHeader()
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
renderItem = ({ item }) => {
|
|
|
|
renderItem = ({ item }) => {
|
|
|
|
const {
|
|
|
|
const {
|
|
|
|
userId, baseUrl, StoreLastMessage
|
|
|
|
userId, baseUrl, StoreLastMessage
|
|
|
@ -634,6 +582,7 @@ export default class RoomsListView extends LoggedView {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
render = () => {
|
|
|
|
render = () => {
|
|
|
|
|
|
|
|
console.count(`${ this.constructor.name }.render calls`);
|
|
|
|
const {
|
|
|
|
const {
|
|
|
|
sortBy, groupByType, showFavorites, showUnread, showServerDropdown, showSortDropdown
|
|
|
|
sortBy, groupByType, showFavorites, showUnread, showServerDropdown, showSortDropdown
|
|
|
|
} = this.props;
|
|
|
|
} = this.props;
|
|
|
@ -654,7 +603,7 @@ export default class RoomsListView extends LoggedView {
|
|
|
|
)
|
|
|
|
)
|
|
|
|
: null
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{showServerDropdown ? <ServerDropdown navigator={navigator} /> : null}
|
|
|
|
{showServerDropdown ? <ServerDropdown /> : null}
|
|
|
|
<ConnectionBadge />
|
|
|
|
<ConnectionBadge />
|
|
|
|
<NavigationEvents
|
|
|
|
<NavigationEvents
|
|
|
|
onDidFocus={() => BackHandler.addEventListener('hardwareBackPress', this.handleBackPress)}
|
|
|
|
onDidFocus={() => BackHandler.addEventListener('hardwareBackPress', this.handleBackPress)}
|
|
|
|