diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap
index e881064aa..4b04cc4a8 100644
--- a/__tests__/__snapshots__/Storyshots.test.js.snap
+++ b/__tests__/__snapshots__/Storyshots.test.js.snap
@@ -4994,137 +4994,6 @@ exports[`Storyshots Message list message 1`] = `
`;
-exports[`Storyshots RoomItem list roomitem 1`] = `
-
-
-
- Basic
-
- View
-
- User
-
- View
- View
-
- Type
-
- View
- View
- View
- View
- View
-
- Alerts
-
- View
- View
- View
- View
- View
- View
- View
- View
- View
-
- Last Message
-
- View
- View
- View
- View
- View
- View
-
-
-`;
-
exports[`Storyshots UiKitMessage list uikitmessage 1`] = `
0 || item.alert === true); // either its unread count > 0 or its alert
+ return !isUnread;
+ },
+
isGroupChat(room) {
return (room.uids && room.uids.length > 2) || (room.usernames && room.usernames.length > 2);
},
diff --git a/app/presentation/RoomItem/index.js b/app/presentation/RoomItem/index.js
index 1b3ee93f2..487c22430 100644
--- a/app/presentation/RoomItem/index.js
+++ b/app/presentation/RoomItem/index.js
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { View, Text } from 'react-native';
import { connect } from 'react-redux';
@@ -16,82 +16,79 @@ import { themes } from '../../constants/colors';
export { ROW_HEIGHT };
const attrs = [
- 'name',
- 'unread',
- 'userMentions',
- 'showLastMessage',
- 'useRealName',
- 'alert',
- 'type',
'width',
- 'isRead',
- 'favorite',
'status',
'connected',
'theme',
- 'isFocused'
+ 'isFocused',
+ 'forceUpdate',
+ 'showLastMessage'
];
-const arePropsEqual = (oldProps, newProps) => {
- const { _updatedAt: _updatedAtOld } = oldProps;
- const { _updatedAt: _updatedAtNew } = newProps;
- if (_updatedAtOld && _updatedAtNew && _updatedAtOld.toISOString() !== _updatedAtNew.toISOString()) {
- return false;
- }
- return attrs.every(key => oldProps[key] === newProps[key]);
-};
+const arePropsEqual = (oldProps, newProps) => attrs.every(key => oldProps[key] === newProps[key]);
const RoomItem = React.memo(({
+ item,
onPress,
width,
- favorite,
toggleFav,
- isRead,
- rid,
toggleRead,
hideChannel,
testID,
- unread,
- userMentions,
- name,
- _updatedAt,
- alert,
- type,
avatarSize,
baseUrl,
userId,
username,
token,
id,
- prid,
showLastMessage,
- hideUnreadStatus,
- lastMessage,
status,
- avatar,
useRealName,
getUserPresence,
- isGroupChat,
connected,
theme,
- isFocused
+ isFocused,
+ getRoomTitle,
+ getRoomAvatar,
+ getIsGroupChat,
+ getIsRead
}) => {
+ const [, setForceUpdate] = useState(1);
+
useEffect(() => {
- if (connected && type === 'd' && id) {
+ if (connected && item.t === 'd' && id) {
getUserPresence(id);
}
}, [connected]);
- const date = lastMessage && formatDate(lastMessage.ts);
+ useEffect(() => {
+ if (item?.observe) {
+ const observable = item.observe();
+ const subscription = observable?.subscribe?.(() => {
+ setForceUpdate(prevForceUpdate => prevForceUpdate + 1);
+ });
+
+ return () => {
+ subscription?.unsubscribe?.();
+ };
+ }
+ }, []);
+
+ const name = getRoomTitle(item);
+ const avatar = getRoomAvatar(item);
+ const isGroupChat = getIsGroupChat(item);
+ const isRead = getIsRead(item);
+ const _onPress = () => onPress(item);
+ const date = item.lastMessage?.ts && formatDate(item.lastMessage.ts);
let accessibilityLabel = name;
- if (unread === 1) {
- accessibilityLabel += `, ${ unread } ${ I18n.t('alert') }`;
- } else if (unread > 1) {
- accessibilityLabel += `, ${ unread } ${ I18n.t('alerts') }`;
+ if (item.unread === 1) {
+ accessibilityLabel += `, ${ item.unread } ${ I18n.t('alert') }`;
+ } else if (item.unread > 1) {
+ accessibilityLabel += `, ${ item.unread } ${ I18n.t('alerts') }`;
}
- if (userMentions > 0) {
+ if (item.userMentions > 0) {
accessibilityLabel += `, ${ I18n.t('you_were_mentioned') }`;
}
@@ -101,16 +98,16 @@ const RoomItem = React.memo(({
return (
@@ -121,7 +118,7 @@ const RoomItem = React.memo(({
{name}
- {_updatedAt ? (
+ {item.roomUpdatedAt ? (
@@ -203,17 +200,10 @@ const RoomItem = React.memo(({
}, arePropsEqual);
RoomItem.propTypes = {
- type: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
+ item: PropTypes.object.isRequired,
baseUrl: PropTypes.string.isRequired,
showLastMessage: PropTypes.bool,
- _updatedAt: PropTypes.string,
- lastMessage: PropTypes.object,
- alert: PropTypes.bool,
- unread: PropTypes.number,
- userMentions: PropTypes.number,
id: PropTypes.string,
- prid: PropTypes.string,
onPress: PropTypes.func,
userId: PropTypes.string,
username: PropTypes.string,
@@ -221,27 +211,29 @@ RoomItem.propTypes = {
avatarSize: PropTypes.number,
testID: PropTypes.string,
width: PropTypes.number,
- favorite: PropTypes.bool,
- isRead: PropTypes.bool,
- rid: PropTypes.string,
status: PropTypes.string,
toggleFav: PropTypes.func,
toggleRead: PropTypes.func,
hideChannel: PropTypes.func,
- avatar: PropTypes.bool,
- hideUnreadStatus: PropTypes.bool,
useRealName: PropTypes.bool,
getUserPresence: PropTypes.func,
connected: PropTypes.bool,
- isGroupChat: PropTypes.bool,
theme: PropTypes.string,
- isFocused: PropTypes.bool
+ isFocused: PropTypes.bool,
+ getRoomTitle: PropTypes.func,
+ getRoomAvatar: PropTypes.func,
+ getIsGroupChat: PropTypes.func,
+ getIsRead: PropTypes.func
};
RoomItem.defaultProps = {
avatarSize: 48,
status: 'offline',
- getUserPresence: () => {}
+ getUserPresence: () => {},
+ getRoomTitle: () => 'title',
+ getRoomAvatar: () => '',
+ getIsGroupChat: () => false,
+ getIsRead: () => false
};
const mapStateToProps = (state, ownProps) => {
diff --git a/app/views/RoomView/List.js b/app/views/RoomView/List.js
index d0dc7c88d..209ec18bb 100644
--- a/app/views/RoomView/List.js
+++ b/app/views/RoomView/List.js
@@ -1,7 +1,6 @@
import React from 'react';
import { FlatList, RefreshControl } from 'react-native';
import PropTypes from 'prop-types';
-import orderBy from 'lodash/orderBy';
import { Q } from '@nozbe/watermelondb';
import moment from 'moment';
import isEqual from 'lodash/isEqual';
@@ -15,9 +14,10 @@ import EmptyRoom from './EmptyRoom';
import { isIOS } from '../../utils/deviceInfo';
import { animateNextTransition } from '../../utils/layoutAnimation';
import ActivityIndicator from '../../containers/ActivityIndicator';
-import debounce from '../../utils/debounce';
import { themes } from '../../constants/colors';
+const QUERY_SIZE = 50;
+
class List extends React.Component {
static propTypes = {
onEndReached: PropTypes.func,
@@ -47,7 +47,8 @@ class List extends React.Component {
super(props);
console.time(`${ this.constructor.name } init`);
console.time(`${ this.constructor.name } mount`);
-
+ this.count = 0;
+ this.needsFetch = false;
this.mounted = false;
this.state = {
loading: true,
@@ -56,7 +57,7 @@ class List extends React.Component {
refreshing: false,
animated: false
};
- this.init();
+ this.query();
this.unsubscribeFocus = props.navigation.addListener('focus', () => {
if (this.mounted) {
this.setState({ animated: true });
@@ -72,72 +73,6 @@ class List extends React.Component {
console.timeEnd(`${ this.constructor.name } mount`);
}
- // eslint-disable-next-line react/sort-comp
- async init() {
- const { rid, tmid } = this.props;
- const db = database.active;
-
- // handle servers with version < 3.0.0
- let { hideSystemMessages = [] } = this.props;
- if (!Array.isArray(hideSystemMessages)) {
- hideSystemMessages = [];
- }
-
- if (tmid) {
- try {
- this.thread = await db.collections
- .get('threads')
- .find(tmid);
- } catch (e) {
- console.log(e);
- }
- this.messagesObservable = db.collections
- .get('thread_messages')
- .query(Q.where('rid', tmid), Q.or(Q.where('t', Q.notIn(hideSystemMessages)), Q.where('t', Q.eq(null))))
- .observe();
- } else if (rid) {
- this.messagesObservable = db.collections
- .get('messages')
- .query(Q.where('rid', rid), Q.or(Q.where('t', Q.notIn(hideSystemMessages)), Q.where('t', Q.eq(null))))
- .observe();
- }
-
- if (rid) {
- this.unsubscribeMessages();
- this.messagesSubscription = this.messagesObservable
- .subscribe((data) => {
- if (tmid && this.thread) {
- data = [this.thread, ...data];
- }
- const messages = orderBy(data, ['ts'], ['desc']);
- if (this.mounted) {
- this.setState({ messages }, () => this.update());
- } else {
- this.state.messages = messages;
- }
- this.readThreads();
- });
- }
- }
-
- // eslint-disable-next-line react/sort-comp
- reload = () => {
- this.unsubscribeMessages();
- this.init();
- }
-
- readThreads = async() => {
- const { tmid } = this.props;
-
- if (tmid) {
- try {
- await RocketChat.readThreads(tmid);
- } catch {
- // Do nothing
- }
- }
- }
-
shouldComponentUpdate(nextProps, nextState) {
const { loading, end, refreshing } = this.state;
const { hideSystemMessages, theme } = this.props;
@@ -177,7 +112,7 @@ class List extends React.Component {
console.countReset(`${ this.constructor.name }.render calls`);
}
- onEndReached = debounce(async() => {
+ fetchData = async() => {
const {
loading, end, messages, latest = messages[messages.length - 1]?.ts
} = this.state;
@@ -196,12 +131,99 @@ class List extends React.Component {
result = await RocketChat.loadMessagesForRoom({ rid, t, latest });
}
- this.setState({ end: result.length < 50, loading: false, latest: result[result.length - 1]?.ts }, () => this.loadMoreMessages(result));
+ this.setState({ end: result.length < QUERY_SIZE, loading: false, latest: result[result.length - 1]?.ts }, () => this.loadMoreMessages(result));
} catch (e) {
this.setState({ loading: false });
log(e);
}
- }, 300)
+ }
+
+ query = async() => {
+ this.count += QUERY_SIZE;
+ const { rid, tmid } = this.props;
+ const db = database.active;
+
+ // handle servers with version < 3.0.0
+ let { hideSystemMessages = [] } = this.props;
+ if (!Array.isArray(hideSystemMessages)) {
+ hideSystemMessages = [];
+ }
+
+ if (tmid) {
+ try {
+ this.thread = await db.collections
+ .get('threads')
+ .find(tmid);
+ } catch (e) {
+ console.log(e);
+ }
+ this.messagesObservable = db.collections
+ .get('thread_messages')
+ .query(
+ Q.where('rid', tmid),
+ Q.experimentalSortBy('ts', Q.desc),
+ Q.experimentalSkip(0),
+ Q.experimentalTake(this.count)
+ )
+ .observe();
+ } else if (rid) {
+ this.messagesObservable = db.collections
+ .get('messages')
+ .query(
+ Q.where('rid', rid),
+ Q.experimentalSortBy('ts', Q.desc),
+ Q.experimentalSkip(0),
+ Q.experimentalTake(this.count)
+ )
+ .observe();
+ }
+
+ if (rid) {
+ this.unsubscribeMessages();
+ this.messagesSubscription = this.messagesObservable
+ .subscribe((messages) => {
+ if (messages.length <= this.count) {
+ this.needsFetch = true;
+ }
+ if (tmid && this.thread) {
+ messages = [...messages, this.thread];
+ }
+ messages = messages.filter(m => !m.t || !hideSystemMessages?.includes(m.t));
+
+ if (this.mounted) {
+ this.setState({ messages }, () => this.update());
+ } else {
+ this.state.messages = messages;
+ }
+ this.readThreads();
+ });
+ }
+ }
+
+ reload = () => {
+ this.count = 0;
+ this.query();
+ }
+
+ readThreads = async() => {
+ const { tmid } = this.props;
+
+ if (tmid) {
+ try {
+ await RocketChat.readThreads(tmid);
+ } catch {
+ // Do nothing
+ }
+ }
+ }
+
+ onEndReached = async() => {
+ if (this.needsFetch) {
+ this.needsFetch = false;
+ await this.fetchData();
+ }
+ this.query();
+ }
loadMoreMessages = (result) => {
const { end } = this.state;
@@ -305,7 +327,7 @@ class List extends React.Component {
removeClippedSubviews={isIOS}
initialNumToRender={7}
onEndReached={this.onEndReached}
- onEndReachedThreshold={5}
+ onEndReachedThreshold={0.5}
maxToRenderPerBatch={5}
windowSize={10}
ListFooterComponent={this.renderFooter}
diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js
index 0b6afd18f..4a54117dd 100644
--- a/app/views/RoomView/index.js
+++ b/app/views/RoomView/index.js
@@ -206,12 +206,10 @@ class RoomView extends React.Component {
const { appState, insets } = this.props;
if (appState === 'foreground' && appState !== prevProps.appState && this.rid) {
- this.onForegroundInteraction = InteractionManager.runAfterInteractions(() => {
- // Fire List.init() just to keep observables working
- if (this.list && this.list.current) {
- this.list.current.init();
- }
- });
+ // Fire List.query() just to keep observables working
+ if (this.list && this.list.current) {
+ this.list.current?.query?.();
+ }
}
// If it's not direct message
if (this.t !== 'd') {
@@ -267,9 +265,6 @@ class RoomView extends React.Component {
if (this.didMountInteraction && this.didMountInteraction.cancel) {
this.didMountInteraction.cancel();
}
- if (this.onForegroundInteraction && this.onForegroundInteraction.cancel) {
- this.onForegroundInteraction.cancel();
- }
if (this.willBlurListener && this.willBlurListener.remove) {
this.willBlurListener.remove();
}
diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js
index 232ea3228..d2bd6cced 100644
--- a/app/views/RoomsListView/index.js
+++ b/app/views/RoomsListView/index.js
@@ -9,7 +9,7 @@ import {
RefreshControl
} from 'react-native';
import { connect } from 'react-redux';
-import { isEqual, orderBy } from 'lodash';
+import isEqual from 'react-fast-compare';
import Orientation from 'react-native-orientation-locker';
import { Q } from '@nozbe/watermelondb';
import { withSafeAreaInsets } from 'react-native-safe-area-context';
@@ -71,6 +71,7 @@ const DISCUSSIONS_HEADER = 'Discussions';
const CHANNELS_HEADER = 'Channels';
const DM_HEADER = 'Direct_Messages';
const GROUPS_HEADER = 'Private_Groups';
+const QUERY_SIZE = 20;
const filterIsUnread = s => (s.unread > 0 || s.alert) && !s.hideUnreadStatus;
const filterIsFavorite = s => s.f;
@@ -140,11 +141,12 @@ class RoomsListView extends React.Component {
this.gotSubscriptions = false;
this.animated = false;
+ this.count = 0;
this.state = {
searching: false,
search: [],
loading: true,
- allChats: [],
+ chatsOrder: [],
chats: [],
item: {}
};
@@ -211,7 +213,7 @@ class RoomsListView extends React.Component {
}
shouldComponentUpdate(nextProps, nextState) {
- const { allChats, searching, item } = this.state;
+ const { chatsOrder, searching, item } = this.state;
// eslint-disable-next-line react/destructuring-assignment
const propsUpdated = shouldUpdateProps.some(key => nextProps[key] !== this.props[key]);
if (propsUpdated) {
@@ -219,7 +221,7 @@ class RoomsListView extends React.Component {
}
// Compare changes only once
- const chatsNotEqual = !isEqual(nextState.allChats, allChats);
+ const chatsNotEqual = !isEqual(nextState.chatsOrder, chatsOrder);
// If they aren't equal, set to update if focused
if (chatsNotEqual) {
@@ -290,7 +292,7 @@ class RoomsListView extends React.Component {
&& prevProps.showUnread === showUnread
)
) {
- this.getSubscriptions(true);
+ this.getSubscriptions();
} else if (
appState === 'foreground'
&& appState !== prevProps.appState
@@ -309,9 +311,7 @@ class RoomsListView extends React.Component {
}
componentWillUnmount() {
- if (this.querySubscription && this.querySubscription.unsubscribe) {
- this.querySubscription.unsubscribe();
- }
+ this.unsubscribeQuery();
if (this.unsubscribeFocus) {
this.unsubscribeFocus();
}
@@ -396,17 +396,8 @@ class RoomsListView extends React.Component {
return allData;
}
- getSubscriptions = async(force = false) => {
- if (this.gotSubscriptions && !force) {
- return;
- }
- this.gotSubscriptions = true;
-
- if (this.querySubscription && this.querySubscription.unsubscribe) {
- this.querySubscription.unsubscribe();
- }
-
- this.setState({ loading: true });
+ getSubscriptions = async() => {
+ this.unsubscribeQuery();
const {
sortBy,
@@ -416,41 +407,49 @@ class RoomsListView extends React.Component {
} = this.props;
const db = database.active;
- const observable = await db.collections
- .get('subscriptions')
- .query(
- Q.where('archived', false),
- Q.where('open', true)
- )
- .observeWithColumns(['room_updated_at', 'unread', 'alert', 'user_mentions', 'f', 't']);
+ let observable;
+
+ const defaultWhereClause = [
+ Q.where('archived', false),
+ Q.where('open', true)
+ ];
+
+ if (sortBy === 'alphabetical') {
+ defaultWhereClause.push(Q.experimentalSortBy(`${ this.useRealName ? 'fname' : 'name' }`, Q.asc));
+ } else {
+ defaultWhereClause.push(Q.experimentalSortBy('room_updated_at', Q.desc));
+ }
+
+ // When we're grouping by something
+ if (this.isGrouping) {
+ observable = await db.collections
+ .get('subscriptions')
+ .query(...defaultWhereClause)
+ .observe();
+
+ // When we're NOT grouping
+ } else {
+ this.count += QUERY_SIZE;
+ observable = await db.collections
+ .get('subscriptions')
+ .query(
+ ...defaultWhereClause,
+ Q.experimentalSkip(0),
+ Q.experimentalTake(this.count)
+ )
+ .observe();
+ }
+
this.querySubscription = observable.subscribe((data) => {
let tempChats = [];
- let chats = [];
- if (sortBy === 'alphabetical') {
- chats = orderBy(data, [`${ this.useRealName ? 'fname' : 'name' }`], ['asc']);
- } else {
- chats = orderBy(data, ['roomUpdatedAt'], ['desc']);
- }
+ let chats = data;
- // it's better to map and test all subs altogether then testing them individually
- const allChats = data.map(item => ({
- alert: item.alert,
- unread: item.unread,
- userMentions: item.userMentions,
- isRead: this.getIsRead(item),
- favorite: item.f,
- lastMessage: item.lastMessage,
- name: this.getRoomTitle(item),
- _updatedAt: item.roomUpdatedAt,
- key: item._id,
- rid: item.rid,
- type: item.t,
- prid: item.prid,
- uids: item.uids,
- usernames: item.usernames,
- visitor: item.visitor
- }));
+ /**
+ * We trigger re-render only when chats order changes
+ * RoomItem handles its own re-render
+ */
+ const chatsOrder = data.map(item => item.rid);
// unread
if (showUnread) {
@@ -484,12 +483,18 @@ class RoomsListView extends React.Component {
this.internalSetState({
chats: tempChats,
- allChats,
+ chatsOrder,
loading: false
});
});
}
+ unsubscribeQuery = () => {
+ if (this.querySubscription && this.querySubscription.unsubscribe) {
+ this.querySubscription.unsubscribe();
+ }
+ }
+
initSearching = () => {
const { openSearchHeader } = this.props;
this.internalSetState({ searching: true }, () => {
@@ -548,10 +553,19 @@ class RoomsListView extends React.Component {
getRoomAvatar = item => RocketChat.getRoomAvatar(item)
+ isGroupChat = item => RocketChat.isGroupChat(item)
+
+ isRead = item => RocketChat.isRead(item)
+
getUserPresence = uid => RocketChat.getUserPresence(uid)
getUidDirectMessage = room => RocketChat.getUidDirectMessage(room);
+ get isGrouping() {
+ const { showUnread, showFavorites, groupByType } = this.props;
+ return showUnread || showFavorites || groupByType;
+ }
+
onPressItem = (item = {}) => {
const { navigation, isMasterDetail } = this.props;
if (!navigation.isFocused()) {
@@ -743,6 +757,13 @@ class RoomsListView extends React.Component {
roomsRequest({ allData: true });
}
+ onEndReached = () => {
+ // Run only when we're not grouping by anything
+ if (!this.isGrouping) {
+ this.getSubscriptions();
+ }
+ }
+
getScrollRef = ref => (this.scroll = ref);
renderListHeader = () => {
@@ -774,12 +795,6 @@ class RoomsListView extends React.Component {
);
}
- getIsRead = (item) => {
- let isUnread = item.archived !== true && item.open === true; // item is not archived and not opened
- isUnread = isUnread && (item.unread > 0 || item.alert === true); // either its unread count > 0 or its alert
- return !isUnread;
- };
-
renderItem = ({ item }) => {
if (item.separator) {
return this.renderSectionHeader(item.rid);
@@ -800,32 +815,19 @@ class RoomsListView extends React.Component {
width
} = this.props;
const id = this.getUidDirectMessage(item);
- const isGroupChat = RocketChat.isGroupChat(item);
return (
this.onPressItem(item)}
+ onPress={this.onPressItem}
testID={`rooms-list-view-item-${ item.name }`}
width={isMasterDetail ? MAX_SIDEBAR_WIDTH : width}
toggleFav={this.toggleFav}
@@ -833,7 +835,10 @@ class RoomsListView extends React.Component {
hideChannel={this.hideChannel}
useRealName={useRealName}
getUserPresence={this.getUserPresence}
- isGroupChat={isGroupChat}
+ getRoomTitle={this.getRoomTitle}
+ getRoomAvatar={this.getRoomAvatar}
+ getIsGroupChat={this.isGroupChat}
+ getIsRead={this.isRead}
visitor={item.visitor}
isFocused={currentItem?.rid === item.rid}
/>
@@ -880,6 +885,8 @@ class RoomsListView extends React.Component {
/>
)}
windowSize={9}
+ onEndReached={this.onEndReached}
+ onEndReachedThreshold={0.5}
/>
);
};
diff --git a/app/views/ShareListView/index.js b/app/views/ShareListView/index.js
index 7e81998cb..2be4ee122 100644
--- a/app/views/ShareListView/index.js
+++ b/app/views/ShareListView/index.js
@@ -7,7 +7,7 @@ import ShareExtension from 'rn-extensions-share';
import * as FileSystem from 'expo-file-system';
import { connect } from 'react-redux';
import * as mime from 'react-native-mime-types';
-import { isEqual, orderBy } from 'lodash';
+import isEqual from 'react-fast-compare';
import { Q } from '@nozbe/watermelondb';
import database from '../../lib/database';
@@ -32,7 +32,6 @@ const permission = {
message: I18n.t('Read_External_Permission_Message')
};
-const LIMIT = 50;
const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
const keyExtractor = item => item.rid;
@@ -47,7 +46,7 @@ class ShareListView extends React.Component {
constructor(props) {
super(props);
- this.data = [];
+ this.chats = [];
this.state = {
searching: false,
searchText: '',
@@ -186,22 +185,36 @@ class ShareListView extends React.Component {
this.setState(...args);
}
- getSubscriptions = async(server) => {
+ query = (text) => {
const db = database.active;
+ const defaultWhereClause = [
+ Q.where('archived', false),
+ Q.where('open', true),
+ Q.experimentalSkip(0),
+ Q.experimentalTake(50),
+ Q.experimentalSortBy('room_updated_at', Q.desc)
+ ];
+ if (text) {
+ return db.collections
+ .get('subscriptions')
+ .query(
+ ...defaultWhereClause,
+ Q.or(
+ Q.where('name', Q.like(`%${ Q.sanitizeLikeString(text) }%`)),
+ Q.where('fname', Q.like(`%${ Q.sanitizeLikeString(text) }%`))
+ )
+ ).fetch();
+ }
+ return db.collections.get('subscriptions').query(...defaultWhereClause).fetch();
+ }
+
+ getSubscriptions = async(server) => {
const serversDB = database.servers;
if (server) {
- this.data = await db.collections
- .get('subscriptions')
- .query(
- Q.where('archived', false),
- Q.where('open', true)
- ).fetch();
- this.data = orderBy(this.data, ['roomUpdatedAt'], ['desc']);
-
+ this.chats = await this.query();
const serversCollection = serversDB.collections.get('servers');
this.servers = await serversCollection.query().fetch();
- this.chats = this.data.slice(0, LIMIT);
let serverInfo = {};
try {
serverInfo = await serversCollection.find(server);
@@ -210,8 +223,8 @@ class ShareListView extends React.Component {
}
this.internalSetState({
- chats: this.chats ? this.chats.slice() : [],
- servers: this.servers ? this.servers.slice() : [],
+ chats: this.chats ?? [],
+ servers: this.servers ?? [],
loading: false,
serverInfo
});
@@ -253,10 +266,10 @@ class ShareListView extends React.Component {
});
}
- search = (text) => {
- const result = this.data.filter(item => item.name.includes(text)) || [];
+ search = async(text) => {
+ const result = await this.query(text);
this.internalSetState({
- searchResults: result.slice(0, LIMIT),
+ searchResults: result,
searchText: text
});
}
@@ -297,9 +310,26 @@ class ShareListView extends React.Component {
}
renderItem = ({ item }) => {
+ const { serverInfo } = this.state;
+ const { useRealName } = serverInfo;
const {
userId, token, server, theme
} = this.props;
+ let description;
+ switch (item.t) {
+ case 'c':
+ description = item.topic || item.description;
+ break;
+ case 'p':
+ description = item.topic || item.description;
+ break;
+ case 'd':
+ description = useRealName ? item.name : item.fname;
+ break;
+ default:
+ description = item.fname;
+ break;
+ }
return (
this.shareMessage(item)}
testID={`share-extension-item-${ item.name }`}
diff --git a/package.json b/package.json
index 8b741c790..1f7dd4f17 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
},
"dependencies": {
"@codler/react-native-keyboard-aware-scroll-view": "^1.0.1",
- "@nozbe/watermelondb": "0.16.2",
+ "@nozbe/watermelondb": "^0.18.0",
"@react-native-community/art": "^1.2.0",
"@react-native-community/async-storage": "1.11.0",
"@react-native-community/cameraroll": "4.0.0",
@@ -61,6 +61,7 @@
"pretty-bytes": "^5.3.0",
"prop-types": "15.7.2",
"react": "16.13.1",
+ "react-fast-compare": "^3.2.0",
"react-native": "^0.63.1",
"react-native-animatable": "^1.3.3",
"react-native-appearance": "0.3.4",
diff --git a/patches/@nozbe+watermelondb+0.16.2.patch b/patches/@nozbe+watermelondb+0.16.2.patch
deleted file mode 100644
index 6cbdb5507..000000000
--- a/patches/@nozbe+watermelondb+0.16.2.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-diff --git a/node_modules/@nozbe/watermelondb/native/ios/WatermelonDB.xcodeproj/project.pbxproj b/node_modules/@nozbe/watermelondb/native/ios/WatermelonDB.xcodeproj/project.pbxproj
-index 63e6ef9..45c092b 100644
---- a/node_modules/@nozbe/watermelondb/native/ios/WatermelonDB.xcodeproj/project.pbxproj
-+++ b/node_modules/@nozbe/watermelondb/native/ios/WatermelonDB.xcodeproj/project.pbxproj
-@@ -374,6 +374,7 @@
- "$(SRCROOT)/../../../../node_modules/react-native/Libraries/**",
- "$(SRCROOT)/../../../../../ios/Pods/Headers/Public/React-Core/**",
- "$(SRCROOT)/../../../../../../native/ios/Pods/Headers/Public/React-Core",
-+ "$(SRCROOT)/../../../../../ios/Pods/Headers/Public/React-jsi/**",
- );
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
- LD_RUNPATH_SEARCH_PATHS = (
-@@ -426,6 +427,7 @@
- "$(SRCROOT)/../../../../node_modules/react-native/Libraries/**",
- "$(SRCROOT)/../../../../../ios/Pods/Headers/Public/React-Core/**",
- "$(SRCROOT)/../../../../../../native/ios/Pods/Headers/Public/React-Core",
-+ "$(SRCROOT)/../../../../../ios/Pods/Headers/Public/React-jsi/**",
- );
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
- LD_RUNPATH_SEARCH_PATHS = (
diff --git a/storybook/stories/index.js b/storybook/stories/index.js
index cc5a4068f..882416c6c 100644
--- a/storybook/stories/index.js
+++ b/storybook/stories/index.js
@@ -1,10 +1,10 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import React from 'react';
-import { Provider } from 'react-redux';
-import { createStore, combineReducers } from 'redux';
+// import { Provider } from 'react-redux';
+// import { createStore, combineReducers } from 'redux';
import { storiesOf } from '@storybook/react-native';
-import RoomItem from './RoomItem';
+// import RoomItem from './RoomItem';
import Message from './Message';
import UiKitMessage from './UiKitMessage';
import UiKitModal from './UiKitModal';
@@ -24,17 +24,17 @@ const user = {
// Change here to see themed storybook
const theme = 'light';
-const reducers = combineReducers({
- settings: () => ({}),
- login: () => ({
- user: {
- username: 'diego.mello'
- }
- }),
- meteor: () => ({ connected: true }),
- activeUsers: () => ({ abc: { status: 'online', statusText: 'dog' } })
-});
-const store = createStore(reducers);
+// const reducers = combineReducers({
+// settings: () => ({}),
+// login: () => ({
+// user: {
+// username: 'diego.mello'
+// }
+// }),
+// meteor: () => ({ connected: true }),
+// activeUsers: () => ({ abc: { status: 'online', statusText: 'dog' } })
+// });
+// const store = createStore(reducers);
const messageDecorator = story => (
(
);
-storiesOf('RoomItem', module)
- .addDecorator(story => {story()})
- .add('list roomitem', () => );
+// storiesOf('RoomItem', module)
+// .addDecorator(story => {story()})
+// .add('list roomitem', () => );
storiesOf('Message', module)
.addDecorator(messageDecorator)
.add('list message', () => );
diff --git a/yarn.lock b/yarn.lock
index a60ebfcfa..8ea560782 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1917,13 +1917,19 @@
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
-"@nozbe/watermelondb@0.16.2":
- version "0.16.2"
- resolved "https://registry.yarnpkg.com/@nozbe/watermelondb/-/watermelondb-0.16.2.tgz#9c29c426bedb3d3af5d38304344bb49d60ddd1af"
- integrity sha512-LLOEl13bVCiLsZf8QCHt5KUmuks7QnMtsXuhBB2rSb1vBDjc3mG2HmkH/eTzbgJnGIdFzH/XtoVUHlS/ll7Log==
+"@nozbe/sqlite@3.31.1":
+ version "3.31.1"
+ resolved "https://registry.yarnpkg.com/@nozbe/sqlite/-/sqlite-3.31.1.tgz#ffd394ad7c188c6b73f89fd6e1ccb849a1b96dba"
+ integrity sha512-z5+GdcHZl9OQ1g0pnygORAnwCYUlYw/gQxdW/8rS0HxD2Gnn/k3DBQOvqQIH4Z3Z3KWVMbGUYhcH1v4SqTAdwg==
+
+"@nozbe/watermelondb@^0.18.0":
+ version "0.18.0"
+ resolved "https://registry.yarnpkg.com/@nozbe/watermelondb/-/watermelondb-0.18.0.tgz#f174d8a4b9e8665bb9e8a7825a682905a43cd92c"
+ integrity sha512-jybGScFR+b0wp8QDNJw9cfd7Qfu51SegivjIniX6dXV/KZxjjhQ+IJxUB6bp2f2tWJIQcxC5e9syctLsrh/PiQ==
dependencies:
+ "@nozbe/sqlite" "3.31.1"
lodash.clonedeep "^4.5.0"
- lokijs "git+https://github.com/Nozbe/LokiJS.git#d08f660"
+ lokijs "git+https://github.com/Nozbe/LokiJS.git#fabe503"
rambdax "2.15.0"
rxjs "^6.2.2"
rxjs-compat "^6.3.2"
@@ -10206,9 +10212,9 @@ logkitty@^0.7.1:
dayjs "^1.8.15"
yargs "^15.1.0"
-"lokijs@git+https://github.com/Nozbe/LokiJS.git#d08f660":
- version "1.5.7"
- resolved "git+https://github.com/Nozbe/LokiJS.git#d08f660794be558529f5ba049fe2868d4f243ec4"
+"lokijs@git+https://github.com/Nozbe/LokiJS.git#fabe503":
+ version "1.5.9"
+ resolved "git+https://github.com/Nozbe/LokiJS.git#fabe503e4fc7887b76b0e4892b28fbd0753da27d"
lolex@^5.0.0:
version "5.1.2"
@@ -12573,6 +12579,11 @@ react-fast-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.1.1.tgz#0becf31e3812fa70dc231e259f40d892d4767900"
integrity sha512-SCsAORWK59BvauR2L1BTdjQbJcSGJJz03U0awektk2hshLKrITDDFTlgGCqIZpTDlPC/NFlZee6xTMzXPVLiHw==
+react-fast-compare@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
+ integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
+
react-focus-lock@^2.1.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.3.1.tgz#9d5d85899773609c7eefa4fc54fff6a0f5f2fc47"