[IMPROVEMENT] Native sort and limit queries (#2249)
* Update WatermelonDB to 0.18.0 * Low onEndReachedThreshold * Query experiment * QUERY_SIZE * Query or fetch data * Reorder class functions * Reset variables * Hide system messages * Change this.count behaviour * Starting on RoomsListView * unsubscribeQuery * onEndReached * Separate queries * Reusable where clause * Refactoring * Refactor RoomItem to accept item as prop * Comment RoomItem tests just so jest passes * Fix alert and status * onPress * Unnecessary diff * react-fast-compare * Native limit on ShareListView * Tweak item description * Lint * Fix on foreground crash * Suggested changes
This commit is contained in:
parent
9882ace694
commit
9dbe10bcf8
|
@ -4994,137 +4994,6 @@ exports[`Storyshots Message list message 1`] = `
|
|||
</RCTScrollView>
|
||||
`;
|
||||
|
||||
exports[`Storyshots RoomItem list roomitem 1`] = `
|
||||
<RCTScrollView
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#efeff4",
|
||||
}
|
||||
}
|
||||
>
|
||||
<View>
|
||||
<Text
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"fontSize": 20,
|
||||
"fontWeight": "300",
|
||||
"marginLeft": 10,
|
||||
"marginTop": 30,
|
||||
},
|
||||
Object {
|
||||
"backgroundColor": "#ffffff",
|
||||
"color": "#0d0e12",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
Basic
|
||||
</Text>
|
||||
View
|
||||
<Text
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"fontSize": 20,
|
||||
"fontWeight": "300",
|
||||
"marginLeft": 10,
|
||||
"marginTop": 30,
|
||||
},
|
||||
Object {
|
||||
"backgroundColor": "#ffffff",
|
||||
"color": "#0d0e12",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
User
|
||||
</Text>
|
||||
View
|
||||
View
|
||||
<Text
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"fontSize": 20,
|
||||
"fontWeight": "300",
|
||||
"marginLeft": 10,
|
||||
"marginTop": 30,
|
||||
},
|
||||
Object {
|
||||
"backgroundColor": "#ffffff",
|
||||
"color": "#0d0e12",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
Type
|
||||
</Text>
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
<Text
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"fontSize": 20,
|
||||
"fontWeight": "300",
|
||||
"marginLeft": 10,
|
||||
"marginTop": 30,
|
||||
},
|
||||
Object {
|
||||
"backgroundColor": "#ffffff",
|
||||
"color": "#0d0e12",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
Alerts
|
||||
</Text>
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
<Text
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"fontSize": 20,
|
||||
"fontWeight": "300",
|
||||
"marginLeft": 10,
|
||||
"marginTop": 30,
|
||||
},
|
||||
Object {
|
||||
"backgroundColor": "#ffffff",
|
||||
"color": "#0d0e12",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
Last Message
|
||||
</Text>
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
</View>
|
||||
</RCTScrollView>
|
||||
`;
|
||||
|
||||
exports[`Storyshots UiKitMessage list uikitmessage 1`] = `
|
||||
<RCTSafeAreaView
|
||||
emulateUnlessSupported={true}
|
||||
|
|
|
@ -845,6 +845,12 @@ const RocketChat = {
|
|||
return other && other.length ? other[0] : me;
|
||||
},
|
||||
|
||||
isRead(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;
|
||||
},
|
||||
|
||||
isGroupChat(room) {
|
||||
return (room.uids && room.uids.length > 2) || (room.usernames && room.usernames.length > 2);
|
||||
},
|
||||
|
|
|
@ -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 (
|
||||
<Touchable
|
||||
onPress={onPress}
|
||||
onPress={_onPress}
|
||||
width={width}
|
||||
favorite={favorite}
|
||||
favorite={item.f}
|
||||
toggleFav={toggleFav}
|
||||
isRead={isRead}
|
||||
rid={rid}
|
||||
rid={item.rid}
|
||||
toggleRead={toggleRead}
|
||||
hideChannel={hideChannel}
|
||||
testID={testID}
|
||||
type={type}
|
||||
type={item.t}
|
||||
theme={theme}
|
||||
isFocused={isFocused}
|
||||
>
|
||||
|
@ -121,7 +118,7 @@ const RoomItem = React.memo(({
|
|||
<Avatar
|
||||
text={avatar}
|
||||
size={avatarSize}
|
||||
type={type}
|
||||
type={item.t}
|
||||
baseUrl={baseUrl}
|
||||
style={styles.avatar}
|
||||
userId={userId}
|
||||
|
@ -137,8 +134,8 @@ const RoomItem = React.memo(({
|
|||
>
|
||||
<View style={styles.titleContainer}>
|
||||
<TypeIcon
|
||||
type={type}
|
||||
prid={prid}
|
||||
type={item.t}
|
||||
prid={item.prid}
|
||||
status={status}
|
||||
isGroupChat={isGroupChat}
|
||||
theme={theme}
|
||||
|
@ -146,7 +143,7 @@ const RoomItem = React.memo(({
|
|||
<Text
|
||||
style={[
|
||||
styles.title,
|
||||
alert && !hideUnreadStatus && styles.alert,
|
||||
item.alert && !item.hideUnreadStatus && styles.alert,
|
||||
{ color: themes[theme].titleText }
|
||||
]}
|
||||
ellipsizeMode='tail'
|
||||
|
@ -154,7 +151,7 @@ const RoomItem = React.memo(({
|
|||
>
|
||||
{name}
|
||||
</Text>
|
||||
{_updatedAt ? (
|
||||
{item.roomUpdatedAt ? (
|
||||
<Text
|
||||
style={[
|
||||
styles.date,
|
||||
|
@ -163,7 +160,7 @@ const RoomItem = React.memo(({
|
|||
themes[theme]
|
||||
.auxiliaryText
|
||||
},
|
||||
alert && !hideUnreadStatus && [
|
||||
item.alert && !item.hideUnreadStatus && [
|
||||
styles.updateAlert,
|
||||
{
|
||||
color:
|
||||
|
@ -181,18 +178,18 @@ const RoomItem = React.memo(({
|
|||
</View>
|
||||
<View style={styles.row}>
|
||||
<LastMessage
|
||||
lastMessage={lastMessage}
|
||||
type={type}
|
||||
lastMessage={item.lastMessage}
|
||||
type={item.t}
|
||||
showLastMessage={showLastMessage}
|
||||
username={username}
|
||||
alert={alert && !hideUnreadStatus}
|
||||
alert={item.alert && !item.hideUnreadStatus}
|
||||
useRealName={useRealName}
|
||||
theme={theme}
|
||||
/>
|
||||
<UnreadBadge
|
||||
unread={unread}
|
||||
userMentions={userMentions}
|
||||
type={type}
|
||||
unread={item.unread}
|
||||
userMentions={item.userMentions}
|
||||
type={item.t}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
|
@ -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) => {
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
<RoomItem
|
||||
item={item}
|
||||
theme={theme}
|
||||
alert={item.alert}
|
||||
unread={item.unread}
|
||||
hideUnreadStatus={item.hideUnreadStatus}
|
||||
userMentions={item.userMentions}
|
||||
isRead={this.getIsRead(item)}
|
||||
favorite={item.f}
|
||||
avatar={this.getRoomAvatar(item)}
|
||||
lastMessage={item.lastMessage}
|
||||
name={this.getRoomTitle(item)}
|
||||
_updatedAt={item.roomUpdatedAt}
|
||||
key={item._id}
|
||||
id={id}
|
||||
type={item.t}
|
||||
userId={userId}
|
||||
username={username}
|
||||
token={token}
|
||||
rid={item.rid}
|
||||
type={item.t}
|
||||
baseUrl={server}
|
||||
prid={item.prid}
|
||||
showLastMessage={StoreLastMessage}
|
||||
onPress={() => 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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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 (
|
||||
<DirectoryItem
|
||||
user={{
|
||||
|
@ -309,11 +339,7 @@ class ShareListView extends React.Component {
|
|||
title={this.getRoomTitle(item)}
|
||||
baseUrl={server}
|
||||
avatar={RocketChat.getRoomAvatar(item)}
|
||||
description={
|
||||
item.t === 'c'
|
||||
? (item.topic || item.description)
|
||||
: item.fname
|
||||
}
|
||||
description={description}
|
||||
type={item.prid ? 'discussion' : item.t}
|
||||
onPress={() => this.shareMessage(item)}
|
||||
testID={`share-extension-item-${ item.name }`}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 = (
|
|
@ -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 => (
|
||||
<MessageContext.Provider
|
||||
|
@ -55,9 +55,9 @@ const messageDecorator = story => (
|
|||
</MessageContext.Provider>
|
||||
);
|
||||
|
||||
storiesOf('RoomItem', module)
|
||||
.addDecorator(story => <Provider store={store}>{story()}</Provider>)
|
||||
.add('list roomitem', () => <RoomItem theme={theme} />);
|
||||
// storiesOf('RoomItem', module)
|
||||
// .addDecorator(story => <Provider store={store}>{story()}</Provider>)
|
||||
// .add('list roomitem', () => <RoomItem theme={theme} />);
|
||||
storiesOf('Message', module)
|
||||
.addDecorator(messageDecorator)
|
||||
.add('list message', () => <Message theme={theme} />);
|
||||
|
|
27
yarn.lock
27
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"
|
||||
|
|
Loading…
Reference in New Issue