Merge branch 'develop' into new.add-discusions-roomactionsview

This commit is contained in:
Gerzon Z 2021-10-05 14:37:34 -04:00 committed by GitHub
commit da7f954996
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 289 additions and 70 deletions

View File

@ -18,6 +18,10 @@ const PERMISSIONS = [
'archive-room', 'archive-room',
'auto-translate', 'auto-translate',
'create-invite-links', 'create-invite-links',
'create-c',
'create-p',
'create-d',
'start-discussion',
'create-team', 'create-team',
'delete-c', 'delete-c',
'delete-message', 'delete-message',

View File

@ -1390,9 +1390,10 @@ const RocketChat = {
* Returns an array of boolean for each permission from permissions arg * Returns an array of boolean for each permission from permissions arg
*/ */
async hasPermission(permissions, rid) { async hasPermission(permissions, rid) {
let roomRoles = [];
if (rid) {
const db = database.active; const db = database.active;
const subsCollection = db.get('subscriptions'); const subsCollection = db.get('subscriptions');
let roomRoles = [];
try { try {
// get the room from database // get the room from database
const room = await subsCollection.find(rid); const room = await subsCollection.find(rid);
@ -1402,6 +1403,7 @@ const RocketChat = {
console.log('hasPermission -> Room not found'); console.log('hasPermission -> Room not found');
return permissions.map(() => false); return permissions.map(() => false);
} }
}
try { try {
const shareUser = reduxStore.getState().share.user; const shareUser = reduxStore.getState().share.user;
@ -1547,11 +1549,13 @@ const RocketChat = {
messageId messageId
}); });
}, },
searchMessages(roomId, searchText) { searchMessages(roomId, searchText, count, offset) {
// RC 0.60.0 // RC 0.60.0
return this.sdk.get('chat.search', { return this.sdk.get('chat.search', {
roomId, roomId,
searchText searchText,
count,
offset
}); });
}, },
toggleFollowMessage(mid, follow) { toggleFollowMessage(mid, follow) {

View File

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native'; import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import I18n from '../i18n'; import I18n from '../i18n';
@ -23,25 +22,25 @@ const styles = StyleSheet.create({
} }
}); });
const AuthLoadingView = React.memo(({ theme, text }) => ( interface IAuthLoadingView {
theme: string;
text: string;
}
const AuthLoadingView = React.memo(({ theme, text }: IAuthLoadingView) => (
<View style={[styles.container, { backgroundColor: themes[theme].backgroundColor }]}> <View style={[styles.container, { backgroundColor: themes[theme].backgroundColor }]}>
<StatusBar /> <StatusBar />
{text && ( {text ? (
<> <>
<ActivityIndicator color={themes[theme].auxiliaryText} size='large' /> <ActivityIndicator color={themes[theme].auxiliaryText} size='large' />
<Text style={[styles.text, { color: themes[theme].bodyText }]}>{`${text}\n${I18n.t('Please_wait')}`}</Text> <Text style={[styles.text, { color: themes[theme].bodyText }]}>{`${text}\n${I18n.t('Please_wait')}`}</Text>
</> </>
)} ) : null}
</View> </View>
)); ));
const mapStateToProps = state => ({ const mapStateToProps = (state: any) => ({
text: state.app.text text: state.app.text
}); });
AuthLoadingView.propTypes = {
theme: PropTypes.string,
text: PropTypes.string
};
export default connect(mapStateToProps)(withTheme(AuthLoadingView)); export default connect(mapStateToProps)(withTheme(AuthLoadingView));

View File

@ -21,6 +21,7 @@ import { Review } from '../utils/review';
import { getUserSelector } from '../selectors/login'; import { getUserSelector } from '../selectors/login';
import { events, logEvent } from '../utils/log'; import { events, logEvent } from '../utils/log';
import SafeAreaView from '../containers/SafeAreaView'; import SafeAreaView from '../containers/SafeAreaView';
import RocketChat from '../lib/rocketchat';
import sharedStyles from './Styles'; import sharedStyles from './Styles';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -79,10 +80,13 @@ class CreateChannelView extends React.Component {
users: PropTypes.array.isRequired, users: PropTypes.array.isRequired,
user: PropTypes.shape({ user: PropTypes.shape({
id: PropTypes.string, id: PropTypes.string,
token: PropTypes.string token: PropTypes.string,
roles: PropTypes.array
}), }),
theme: PropTypes.string, theme: PropTypes.string,
teamId: PropTypes.string teamId: PropTypes.string,
createPublicChannelPermission: PropTypes.array,
createPrivateChannelPermission: PropTypes.array
}; };
constructor(props) { constructor(props) {
@ -96,14 +100,20 @@ class CreateChannelView extends React.Component {
readOnly: false, readOnly: false,
encrypted: false, encrypted: false,
broadcast: false, broadcast: false,
isTeam isTeam,
permissions: []
}; };
this.setHeader(); this.setHeader();
} }
componentDidMount() {
this.handleHasPermission();
}
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
const { channelName, type, readOnly, broadcast, encrypted } = this.state; const { channelName, type, readOnly, broadcast, encrypted, permissions } = this.state;
const { users, isFetching, encryptionEnabled, theme } = this.props; const { users, isFetching, encryptionEnabled, theme, createPublicChannelPermission, createPrivateChannelPermission } =
this.props;
if (nextProps.theme !== theme) { if (nextProps.theme !== theme) {
return true; return true;
} }
@ -122,18 +132,37 @@ class CreateChannelView extends React.Component {
if (nextState.broadcast !== broadcast) { if (nextState.broadcast !== broadcast) {
return true; return true;
} }
if (nextState.permissions !== permissions) {
return true;
}
if (nextProps.isFetching !== isFetching) { if (nextProps.isFetching !== isFetching) {
return true; return true;
} }
if (nextProps.encryptionEnabled !== encryptionEnabled) { if (nextProps.encryptionEnabled !== encryptionEnabled) {
return true; return true;
} }
if (!dequal(nextProps.createPublicChannelPermission, createPublicChannelPermission)) {
return true;
}
if (!dequal(nextProps.createPrivateChannelPermission, createPrivateChannelPermission)) {
return true;
}
if (!dequal(nextProps.users, users)) { if (!dequal(nextProps.users, users)) {
return true; return true;
} }
return false; return false;
} }
componentDidUpdate(prevProps) {
const { createPublicChannelPermission, createPrivateChannelPermission } = this.props;
if (
!dequal(createPublicChannelPermission, prevProps.createPublicChannelPermission) ||
!dequal(createPrivateChannelPermission, prevProps.createPrivateChannelPermission)
) {
this.handleHasPermission();
}
}
setHeader = () => { setHeader = () => {
const { navigation } = this.props; const { navigation } = this.props;
const { isTeam } = this.state; const { isTeam } = this.state;
@ -208,12 +237,21 @@ class CreateChannelView extends React.Component {
); );
}; };
handleHasPermission = async () => {
const { createPublicChannelPermission, createPrivateChannelPermission } = this.props;
const permissions = [createPublicChannelPermission, createPrivateChannelPermission];
const permissionsToCreate = await RocketChat.hasPermission(permissions);
this.setState({ permissions: permissionsToCreate });
};
renderType() { renderType() {
const { type, isTeam } = this.state; const { type, isTeam, permissions } = this.state;
const isDisabled = permissions.filter(r => r === true).length <= 1;
return this.renderSwitch({ return this.renderSwitch({
id: 'type', id: 'type',
value: type, value: permissions[1] ? type : false,
disabled: isDisabled,
label: isTeam ? 'Private_Team' : 'Private_Channel', label: isTeam ? 'Private_Team' : 'Private_Channel',
onValueChange: value => { onValueChange: value => {
logEvent(events.CR_TOGGLE_TYPE); logEvent(events.CR_TOGGLE_TYPE);
@ -373,7 +411,9 @@ const mapStateToProps = state => ({
isFetching: state.createChannel.isFetching, isFetching: state.createChannel.isFetching,
encryptionEnabled: state.encryption.enabled, encryptionEnabled: state.encryption.enabled,
users: state.selectedUsers.users, users: state.selectedUsers.users,
user: getUserSelector(state) user: getUserSelector(state),
createPublicChannelPermission: state.permissions['create-c'],
createPrivateChannelPermission: state.permissions['create-p']
}); });
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({

View File

@ -3,8 +3,9 @@ import PropTypes from 'prop-types';
import { FlatList, StyleSheet, Text, View } from 'react-native'; import { FlatList, StyleSheet, Text, View } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Q } from '@nozbe/watermelondb'; import { Q } from '@nozbe/watermelondb';
import { dequal } from 'dequal';
import * as List from '../containers/List'; import * as List from '../containers/List';
import Touch from '../utils/touch'; import Touch from '../utils/touch';
import database from '../lib/database'; import database from '../lib/database';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
@ -57,13 +58,19 @@ class NewMessageView extends React.Component {
baseUrl: PropTypes.string, baseUrl: PropTypes.string,
user: PropTypes.shape({ user: PropTypes.shape({
id: PropTypes.string, id: PropTypes.string,
token: PropTypes.string token: PropTypes.string,
roles: PropTypes.array
}), }),
create: PropTypes.func, create: PropTypes.func,
maxUsers: PropTypes.number, maxUsers: PropTypes.number,
theme: PropTypes.string, theme: PropTypes.string,
isMasterDetail: PropTypes.bool, isMasterDetail: PropTypes.bool,
serverVersion: PropTypes.string serverVersion: PropTypes.string,
createTeamPermission: PropTypes.array,
createDirectMessagePermission: PropTypes.array,
createPublicChannelPermission: PropTypes.array,
createPrivateChannelPermission: PropTypes.array,
createDiscussionPermission: PropTypes.array
}; };
constructor(props) { constructor(props) {
@ -71,7 +78,8 @@ class NewMessageView extends React.Component {
this.init(); this.init();
this.state = { this.state = {
search: [], search: [],
chats: [] chats: [],
permissions: []
}; };
} }
@ -90,6 +98,30 @@ class NewMessageView extends React.Component {
} }
}; };
componentDidMount() {
this.handleHasPermission();
}
componentDidUpdate(prevProps) {
const {
createTeamPermission,
createPublicChannelPermission,
createPrivateChannelPermission,
createDirectMessagePermission,
createDiscussionPermission
} = this.props;
if (
!dequal(createTeamPermission, prevProps.createTeamPermission) ||
!dequal(createPublicChannelPermission, prevProps.createPublicChannelPermission) ||
!dequal(createPrivateChannelPermission, prevProps.createPrivateChannelPermission) ||
!dequal(createDirectMessagePermission, prevProps.createDirectMessagePermission) ||
!dequal(createDiscussionPermission, prevProps.createDiscussionPermission)
) {
this.handleHasPermission();
}
}
onSearchChangeText(text) { onSearchChangeText(text) {
this.search(text); this.search(text);
} }
@ -161,20 +193,43 @@ class NewMessageView extends React.Component {
Navigation.navigate('CreateDiscussionView'); Navigation.navigate('CreateDiscussionView');
}; };
handleHasPermission = async () => {
const {
createTeamPermission,
createDirectMessagePermission,
createPublicChannelPermission,
createPrivateChannelPermission,
createDiscussionPermission
} = this.props;
const permissions = [
createPublicChannelPermission,
createPrivateChannelPermission,
createTeamPermission,
createDirectMessagePermission,
createDiscussionPermission
];
const permissionsToCreate = await RocketChat.hasPermission(permissions);
this.setState({ permissions: permissionsToCreate });
};
renderHeader = () => { renderHeader = () => {
const { maxUsers, theme, serverVersion } = this.props; const { maxUsers, theme, serverVersion } = this.props;
const { permissions } = this.state;
return ( return (
<View style={{ backgroundColor: themes[theme].auxiliaryBackground }}> <View style={{ backgroundColor: themes[theme].auxiliaryBackground }}>
<SearchBox onChangeText={text => this.onSearchChangeText(text)} testID='new-message-view-search' /> <SearchBox onChangeText={text => this.onSearchChangeText(text)} testID='new-message-view-search' />
<View style={styles.buttonContainer}> <View style={styles.buttonContainer}>
{this.renderButton({ {permissions[0] || permissions[1]
? this.renderButton({
onPress: this.createChannel, onPress: this.createChannel,
title: I18n.t('Create_Channel'), title: I18n.t('Create_Channel'),
icon: 'channel-public', icon: 'channel-public',
testID: 'new-message-view-create-channel', testID: 'new-message-view-create-channel',
first: true first: true
})} })
{compareServerVersion(serverVersion, '3.13.0', methods.greaterThanOrEqualTo) : null}
{compareServerVersion(serverVersion, '3.13.0', methods.greaterThanOrEqualTo) && permissions[2]
? this.renderButton({ ? this.renderButton({
onPress: this.createTeam, onPress: this.createTeam,
title: I18n.t('Create_Team'), title: I18n.t('Create_Team'),
@ -182,7 +237,7 @@ class NewMessageView extends React.Component {
testID: 'new-message-view-create-team' testID: 'new-message-view-create-team'
}) })
: null} : null}
{maxUsers > 2 {maxUsers > 2 && permissions[3]
? this.renderButton({ ? this.renderButton({
onPress: this.createGroupChat, onPress: this.createGroupChat,
title: I18n.t('Create_Direct_Messages'), title: I18n.t('Create_Direct_Messages'),
@ -190,12 +245,14 @@ class NewMessageView extends React.Component {
testID: 'new-message-view-create-direct-message' testID: 'new-message-view-create-direct-message'
}) })
: null} : null}
{this.renderButton({ {permissions[4]
? this.renderButton({
onPress: this.createDiscussion, onPress: this.createDiscussion,
title: I18n.t('Create_Discussion'), title: I18n.t('Create_Discussion'),
icon: 'discussions', icon: 'discussions',
testID: 'new-message-view-create-discussion' testID: 'new-message-view-create-discussion'
})} })
: null}
</View> </View>
</View> </View>
); );
@ -261,7 +318,12 @@ const mapStateToProps = state => ({
isMasterDetail: state.app.isMasterDetail, isMasterDetail: state.app.isMasterDetail,
baseUrl: state.server.server, baseUrl: state.server.server,
maxUsers: state.settings.DirectMesssage_maxUsers || 1, maxUsers: state.settings.DirectMesssage_maxUsers || 1,
user: getUserSelector(state) user: getUserSelector(state),
createTeamPermission: state.permissions['create-team'],
createDirectMessagePermission: state.permissions['create-d'],
createPublicChannelPermission: state.permissions['create-c'],
createPrivateChannelPermission: state.permissions['create-p'],
createDiscussionPermission: state.permissions['start-discussion']
}); });
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({

View File

@ -20,7 +20,8 @@ class RightButtonsContainer extends Component {
navigation: PropTypes.object, navigation: PropTypes.object,
isMasterDetail: PropTypes.bool, isMasterDetail: PropTypes.bool,
toggleFollowThread: PropTypes.func, toggleFollowThread: PropTypes.func,
joined: PropTypes.bool joined: PropTypes.bool,
encrypted: PropTypes.bool
}; };
constructor(props) { constructor(props) {
@ -137,11 +138,14 @@ class RightButtonsContainer extends Component {
goSearchView = () => { goSearchView = () => {
logEvent(events.ROOM_GO_SEARCH); logEvent(events.ROOM_GO_SEARCH);
const { rid, t, navigation, isMasterDetail } = this.props; const { rid, t, navigation, isMasterDetail, encrypted } = this.props;
if (isMasterDetail) { if (isMasterDetail) {
navigation.navigate('ModalStackNavigator', { screen: 'SearchMessagesView', params: { rid, showCloseModal: true } }); navigation.navigate('ModalStackNavigator', {
screen: 'SearchMessagesView',
params: { rid, showCloseModal: true, encrypted }
});
} else { } else {
navigation.navigate('SearchMessagesView', { rid, t }); navigation.navigate('SearchMessagesView', { rid, t, encrypted });
} }
}; };

View File

@ -362,6 +362,7 @@ class RoomView extends React.Component {
const t = room?.t; const t = room?.t;
const teamMain = room?.teamMain; const teamMain = room?.teamMain;
const teamId = room?.teamId; const teamId = room?.teamId;
const encrypted = room?.encrypted;
const { id: userId, token } = user; const { id: userId, token } = user;
const avatar = room?.name; const avatar = room?.name;
const visitor = room?.visitor; const visitor = room?.visitor;
@ -424,6 +425,7 @@ class RoomView extends React.Component {
teamMain={teamMain} teamMain={teamMain}
joined={joined} joined={joined}
t={t} t={t}
encrypted={encrypted}
navigation={navigation} navigation={navigation}
toggleFollowThread={this.toggleFollowThread} toggleFollowThread={this.toggleFollowThread}
/> />

View File

@ -89,7 +89,12 @@ const shouldUpdateProps = [
'refreshing', 'refreshing',
'queueSize', 'queueSize',
'inquiryEnabled', 'inquiryEnabled',
'encryptionBanner' 'encryptionBanner',
'createTeamPermission',
'createDirectMessagePermission',
'createPublicChannelPermission',
'createPrivateChannelPermission',
'createDiscussionPermission'
]; ];
const getItemLayout = (data, index) => ({ const getItemLayout = (data, index) => ({
length: ROW_HEIGHT, length: ROW_HEIGHT,
@ -106,7 +111,7 @@ class RoomsListView extends React.Component {
username: PropTypes.string, username: PropTypes.string,
token: PropTypes.string, token: PropTypes.string,
statusLivechat: PropTypes.string, statusLivechat: PropTypes.string,
roles: PropTypes.object roles: PropTypes.array
}), }),
server: PropTypes.string, server: PropTypes.string,
searchText: PropTypes.string, searchText: PropTypes.string,
@ -135,6 +140,11 @@ class RoomsListView extends React.Component {
queueSize: PropTypes.number, queueSize: PropTypes.number,
inquiryEnabled: PropTypes.bool, inquiryEnabled: PropTypes.bool,
encryptionBanner: PropTypes.string, encryptionBanner: PropTypes.string,
createTeamPermission: PropTypes.array,
createDirectMessagePermission: PropTypes.array,
createPublicChannelPermission: PropTypes.array,
createPrivateChannelPermission: PropTypes.array,
createDiscussionPermission: PropTypes.array,
initAdd: PropTypes.func initAdd: PropTypes.func
}; };
@ -152,7 +162,8 @@ class RoomsListView extends React.Component {
loading: true, loading: true,
chatsUpdate: [], chatsUpdate: [],
chats: [], chats: [],
item: {} item: {},
canCreateRoom: false
}; };
this.setHeader(); this.setHeader();
this.getSubscriptions(); this.getSubscriptions();
@ -160,6 +171,7 @@ class RoomsListView extends React.Component {
componentDidMount() { componentDidMount() {
const { navigation, closeServerDropdown } = this.props; const { navigation, closeServerDropdown } = this.props;
this.handleHasPermission();
this.mounted = true; this.mounted = true;
if (isTablet) { if (isTablet) {
@ -203,7 +215,7 @@ class RoomsListView extends React.Component {
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
const { chatsUpdate, searching, item } = this.state; const { chatsUpdate, searching, item, canCreateRoom } = this.state;
// eslint-disable-next-line react/destructuring-assignment // eslint-disable-next-line react/destructuring-assignment
const propsUpdated = shouldUpdateProps.some(key => nextProps[key] !== this.props[key]); const propsUpdated = shouldUpdateProps.some(key => nextProps[key] !== this.props[key]);
if (propsUpdated) { if (propsUpdated) {
@ -222,6 +234,10 @@ class RoomsListView extends React.Component {
return true; return true;
} }
if (nextState.canCreateRoom !== canCreateRoom) {
return true;
}
if (nextState.item?.rid !== item?.rid) { if (nextState.item?.rid !== item?.rid) {
return true; return true;
} }
@ -257,7 +273,20 @@ class RoomsListView extends React.Component {
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const { sortBy, groupByType, showFavorites, showUnread, rooms, isMasterDetail, insets } = this.props; const {
sortBy,
groupByType,
showFavorites,
showUnread,
rooms,
isMasterDetail,
insets,
createTeamPermission,
createPublicChannelPermission,
createPrivateChannelPermission,
createDirectMessagePermission,
createDiscussionPermission
} = this.props;
const { item } = this.state; const { item } = this.state;
if ( if (
@ -278,6 +307,17 @@ class RoomsListView extends React.Component {
if (insets.left !== prevProps.insets.left || insets.right !== prevProps.insets.right) { if (insets.left !== prevProps.insets.left || insets.right !== prevProps.insets.right) {
this.setHeader(); this.setHeader();
} }
if (
!dequal(createTeamPermission, prevProps.createTeamPermission) ||
!dequal(createPublicChannelPermission, prevProps.createPublicChannelPermission) ||
!dequal(createPrivateChannelPermission, prevProps.createPrivateChannelPermission) ||
!dequal(createDirectMessagePermission, prevProps.createDirectMessagePermission) ||
!dequal(createDiscussionPermission, prevProps.createDiscussionPermission)
) {
this.handleHasPermission();
this.setHeader();
}
} }
componentWillUnmount() { componentWillUnmount() {
@ -297,10 +337,31 @@ class RoomsListView extends React.Component {
console.countReset(`${this.constructor.name}.render calls`); console.countReset(`${this.constructor.name}.render calls`);
} }
handleHasPermission = async () => {
const {
createTeamPermission,
createDirectMessagePermission,
createPublicChannelPermission,
createPrivateChannelPermission,
createDiscussionPermission
} = this.props;
const permissions = [
createPublicChannelPermission,
createPrivateChannelPermission,
createTeamPermission,
createDirectMessagePermission,
createDiscussionPermission
];
const permissionsToCreate = await RocketChat.hasPermission(permissions);
const canCreateRoom = permissionsToCreate.filter(r => r === true).length > 0;
this.setState({ canCreateRoom }, () => this.setHeader());
};
getHeader = () => { getHeader = () => {
const { searching } = this.state; const { searching, canCreateRoom } = this.state;
const { navigation, isMasterDetail, insets } = this.props; const { navigation, isMasterDetail, insets } = this.props;
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: searching ? 0 : 3 }); const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: searching ? 0 : 3 });
return { return {
headerTitleAlign: 'left', headerTitleAlign: 'left',
headerLeft: () => headerLeft: () =>
@ -327,7 +388,9 @@ class RoomsListView extends React.Component {
headerRight: () => headerRight: () =>
searching ? null : ( searching ? null : (
<HeaderButton.Container> <HeaderButton.Container>
{canCreateRoom ? (
<HeaderButton.Item iconName='create' onPress={this.goToNewMessage} testID='rooms-list-view-create-channel' /> <HeaderButton.Item iconName='create' onPress={this.goToNewMessage} testID='rooms-list-view-create-channel' />
) : null}
<HeaderButton.Item iconName='search' onPress={this.initSearching} testID='rooms-list-view-search' /> <HeaderButton.Item iconName='search' onPress={this.initSearching} testID='rooms-list-view-search' />
<HeaderButton.Item iconName='directory' onPress={this.goDirectory} testID='rooms-list-view-directory' /> <HeaderButton.Item iconName='directory' onPress={this.goDirectory} testID='rooms-list-view-directory' />
</HeaderButton.Container> </HeaderButton.Container>
@ -963,7 +1026,12 @@ const mapStateToProps = state => ({
rooms: state.room.rooms, rooms: state.room.rooms,
queueSize: getInquiryQueueSelector(state).length, queueSize: getInquiryQueueSelector(state).length,
inquiryEnabled: state.inquiry.enabled, inquiryEnabled: state.inquiry.enabled,
encryptionBanner: state.encryption.banner encryptionBanner: state.encryption.banner,
createTeamPermission: state.permissions['create-team'],
createDirectMessagePermission: state.permissions['create-d'],
createPublicChannelPermission: state.permissions['create-c'],
createPrivateChannelPermission: state.permissions['create-p'],
createDiscussionPermission: state.permissions['start-discussion']
}); });
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({

View File

@ -24,8 +24,11 @@ import database from '../../lib/database';
import { sanitizeLikeString } from '../../lib/database/utils'; import { sanitizeLikeString } from '../../lib/database/utils';
import getThreadName from '../../lib/methods/getThreadName'; import getThreadName from '../../lib/methods/getThreadName';
import getRoomInfo from '../../lib/methods/getRoomInfo'; import getRoomInfo from '../../lib/methods/getRoomInfo';
import { isIOS } from '../../utils/deviceInfo';
import { compareServerVersion, methods } from '../../lib/utils';
import styles from './styles'; import styles from './styles';
const QUERY_SIZE = 50;
class SearchMessagesView extends React.Component { class SearchMessagesView extends React.Component {
static navigationOptions = ({ navigation, route }) => { static navigationOptions = ({ navigation, route }) => {
const options = { const options = {
@ -43,6 +46,7 @@ class SearchMessagesView extends React.Component {
route: PropTypes.object, route: PropTypes.object,
user: PropTypes.object, user: PropTypes.object,
baseUrl: PropTypes.string, baseUrl: PropTypes.string,
serverVersion: PropTypes.string,
customEmojis: PropTypes.object, customEmojis: PropTypes.object,
theme: PropTypes.string, theme: PropTypes.string,
useRealName: PropTypes.bool useRealName: PropTypes.bool
@ -55,6 +59,7 @@ class SearchMessagesView extends React.Component {
messages: [], messages: [],
searchText: '' searchText: ''
}; };
this.offset = 0;
this.rid = props.route.params?.rid; this.rid = props.route.params?.rid;
this.t = props.route.params?.t; this.t = props.route.params?.t;
this.encrypted = props.route.params?.encrypted; this.encrypted = props.route.params?.encrypted;
@ -88,6 +93,9 @@ class SearchMessagesView extends React.Component {
// Handle encrypted rooms search messages // Handle encrypted rooms search messages
searchMessages = async searchText => { searchMessages = async searchText => {
if (!searchText) {
return [];
}
// If it's a encrypted, room we'll search only on the local stored messages // If it's a encrypted, room we'll search only on the local stored messages
if (this.encrypted) { if (this.encrypted) {
const db = database.active; const db = database.active;
@ -103,25 +111,33 @@ class SearchMessagesView extends React.Component {
.fetch(); .fetch();
} }
// If it's not a encrypted room, search messages on the server // If it's not a encrypted room, search messages on the server
const result = await RocketChat.searchMessages(this.rid, searchText); const result = await RocketChat.searchMessages(this.rid, searchText, QUERY_SIZE, this.offset);
if (result.success) { if (result.success) {
return result.messages; return result.messages;
} }
}; };
search = debounce(async searchText => { getMessages = async (searchText, debounced) => {
this.setState({ searchText, loading: true, messages: [] });
try { try {
const messages = await this.searchMessages(searchText); const messages = await this.searchMessages(searchText);
this.setState({ this.setState(prevState => ({
messages: messages || [], messages: debounced ? messages : [...prevState.messages, ...messages],
loading: false loading: false
}); }));
} catch (e) { } catch (e) {
this.setState({ loading: false }); this.setState({ loading: false });
log(e); log(e);
} }
};
search = searchText => {
this.offset = 0;
this.setState({ searchText, loading: true, messages: [] });
this.searchDebounced(searchText);
};
searchDebounced = debounce(async searchText => {
await this.getMessages(searchText, true);
}, 1000); }, 1000);
getCustomEmoji = name => { getCustomEmoji = name => {
@ -168,6 +184,23 @@ class SearchMessagesView extends React.Component {
} }
}; };
onEndReached = async () => {
const { serverVersion } = this.props;
const { searchText, messages, loading } = this.state;
if (
messages.length < this.offset ||
this.encrypted ||
loading ||
compareServerVersion(serverVersion, '3.17.0', methods.lowerThan)
) {
return;
}
this.setState({ loading: true });
this.offset += QUERY_SIZE;
await this.getMessages(searchText);
};
renderEmpty = () => { renderEmpty = () => {
const { theme } = this.props; const { theme } = this.props;
return ( return (
@ -212,8 +245,10 @@ class SearchMessagesView extends React.Component {
renderItem={this.renderItem} renderItem={this.renderItem}
style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]} style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]}
keyExtractor={item => item._id} keyExtractor={item => item._id}
onEndReached={this.load} onEndReached={this.onEndReached}
ListFooterComponent={loading ? <ActivityIndicator theme={theme} /> : null} ListFooterComponent={loading ? <ActivityIndicator theme={theme} /> : null}
onEndReachedThreshold={0.5}
removeClippedSubviews={isIOS}
{...scrollPersistTaps} {...scrollPersistTaps}
/> />
); );
@ -243,6 +278,7 @@ class SearchMessagesView extends React.Component {
} }
const mapStateToProps = state => ({ const mapStateToProps = state => ({
serverVersion: state.server.version,
baseUrl: state.server.server, baseUrl: state.server.server,
user: getUserSelector(state), user: getUserSelector(state),
useRealName: state.settings.UI_Use_Real_Name, useRealName: state.settings.UI_Use_Real_Name,