[IMPROVE] Add pagination to search messages (#3212)
* [FIX] Pagination in SearchMessage through the javascript * Minor tweak * Remove unnecessary state update * Fix inconsistent value update * Minor change * Fixed searchMessages to work with new value of count * minor tweak * minor tweak * minor tweak * Fix encrypted search * Added Offset to lib/rocketchat and fixed the search * fixed the debounce in search message view * Needed to compare server version to lower than 3.17.0 Co-authored-by: Gerzon Z <gerzonc@icloud.com> Co-authored-by: Gerzon Z <gerzonzcanario@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> Co-authored-by: Levy Costa <levycosta471@gmail.com> Co-authored-by: AlexAlexandre <alexalexandrejr@gmail.com>
This commit is contained in:
parent
62562ebba9
commit
2a19054bf6
|
@ -1537,11 +1537,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) {
|
||||||
|
|
|
@ -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 });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue