diff --git a/app/containers/SearchBox.js b/app/containers/SearchBox.js index afdb5867..7c3e337e 100644 --- a/app/containers/SearchBox.js +++ b/app/containers/SearchBox.js @@ -37,7 +37,7 @@ const styles = StyleSheet.create({ ...sharedStyles.textRegular }, cancel: { - marginRight: 10 + marginRight: 15 }, cancelText: { ...sharedStyles.textRegular, diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index b2e8edcd..634cbb81 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -565,18 +565,28 @@ const RocketChat = { RocketChat.spotlight(searchText, usernames, { users: filterUsers, rooms: filterRooms }), new Promise((resolve, reject) => this.oldPromise = reject) ]); - - data = data.concat(users.map(user => ({ - ...user, - rid: user.username, - name: user.username, - t: 'd', - search: true - })), rooms.map(room => ({ - rid: room._id, - ...room, - search: true - }))); + if (filterUsers) { + data = data.concat(users.map(user => ({ + ...user, + rid: user.username, + name: user.username, + t: 'd', + search: true + }))); + } + if (filterRooms) { + rooms.forEach((room) => { + // Check if it exists on local database + const index = data.findIndex(item => item.rid === room._id); + if (index === -1) { + data.push({ + rid: room._id, + ...room, + search: true + }); + } + }); + } } delete this.oldPromise; return data; diff --git a/app/views/RoomsListView/Header/index.js b/app/views/RoomsListView/Header/index.js index 294cf9eb..badcb59a 100644 --- a/app/views/RoomsListView/Header/index.js +++ b/app/views/RoomsListView/Header/index.js @@ -38,6 +38,7 @@ class RoomsListHeaderView extends PureComponent { } } + // eslint-disable-next-line react/sort-comp handleCommands = ({ event }) => { if (handleCommandOpenServerDropdown(event)) { this.onPress(); @@ -79,7 +80,7 @@ class RoomsListHeaderView extends PureComponent { connecting={connecting} isFetching={isFetching} onPress={this.onPress} - onSearchChangeText={text => this.onSearchChangeText(text)} + onSearchChangeText={this.onSearchChangeText} /> ); } diff --git a/app/views/RoomsListView/ListHeader/Directory.js b/app/views/RoomsListView/ListHeader/Directory.js index 477f1a6c..339a94a6 100644 --- a/app/views/RoomsListView/ListHeader/Directory.js +++ b/app/views/RoomsListView/ListHeader/Directory.js @@ -10,7 +10,10 @@ import DisclosureIndicator from '../../../containers/DisclosureIndicator'; import { themes } from '../../../constants/colors'; import { withTheme } from '../../../theme'; -const Directory = React.memo(({ goDirectory, theme }) => { +const Directory = React.memo(({ goDirectory, theme, searching }) => { + if (searching > 0) { + return null; + } const color = { color: themes[theme].headerSecondaryText }; return ( { }); Directory.propTypes = { + searching: PropTypes.bool, goDirectory: PropTypes.func, theme: PropTypes.string }; diff --git a/app/views/RoomsListView/ListHeader/SearchBar.js b/app/views/RoomsListView/ListHeader/SearchBar.js index d1839379..6446d4cf 100644 --- a/app/views/RoomsListView/ListHeader/SearchBar.js +++ b/app/views/RoomsListView/ListHeader/SearchBar.js @@ -5,7 +5,9 @@ import SearchBox from '../../../containers/SearchBox'; import { isIOS } from '../../../utils/deviceInfo'; import { withTheme } from '../../../theme'; -const SearchBar = React.memo(({ theme, onChangeSearchText, inputRef }) => { +const SearchBar = React.memo(({ + theme, onChangeSearchText, inputRef, searching, onCancelSearchPress, onSearchFocus +}) => { if (isIOS) { return ( { testID='rooms-list-view-search' inputRef={inputRef} theme={theme} + hasCancel={searching} + onCancelPress={onCancelSearchPress} + onFocus={onSearchFocus} /> ); } @@ -21,8 +26,11 @@ const SearchBar = React.memo(({ theme, onChangeSearchText, inputRef }) => { SearchBar.propTypes = { theme: PropTypes.string, + searching: PropTypes.bool, inputRef: PropTypes.func, - onChangeSearchText: PropTypes.func + onChangeSearchText: PropTypes.func, + onCancelSearchPress: PropTypes.func, + onSearchFocus: PropTypes.func }; export default withTheme(SearchBar); diff --git a/app/views/RoomsListView/ListHeader/Sort.js b/app/views/RoomsListView/ListHeader/Sort.js index f5ec8820..e0ca2d10 100644 --- a/app/views/RoomsListView/ListHeader/Sort.js +++ b/app/views/RoomsListView/ListHeader/Sort.js @@ -11,9 +11,9 @@ import { withTheme } from '../../../theme'; const Sort = React.memo(({ - searchLength, sortBy, toggleSort, theme + searching, sortBy, toggleSort, theme }) => { - if (searchLength > 0) { + if (searching > 0) { return null; } return ( @@ -36,7 +36,7 @@ const Sort = React.memo(({ }); Sort.propTypes = { - searchLength: PropTypes.number, + searching: PropTypes.bool, sortBy: PropTypes.string, theme: PropTypes.string, toggleSort: PropTypes.func diff --git a/app/views/RoomsListView/ListHeader/index.js b/app/views/RoomsListView/ListHeader/index.js index 106d80c7..63d20ca9 100644 --- a/app/views/RoomsListView/ListHeader/index.js +++ b/app/views/RoomsListView/ListHeader/index.js @@ -6,22 +6,37 @@ import Directory from './Directory'; import Sort from './Sort'; const ListHeader = React.memo(({ - searchLength, sortBy, onChangeSearchText, toggleSort, goDirectory, inputRef + searching, + sortBy, + onChangeSearchText, + toggleSort, + goDirectory, + inputRef, + onCancelSearchPress, + onSearchFocus }) => ( <> - - - + + + )); ListHeader.propTypes = { - searchLength: PropTypes.number, + searching: PropTypes.bool, sortBy: PropTypes.string, onChangeSearchText: PropTypes.func, toggleSort: PropTypes.func, goDirectory: PropTypes.func, - inputRef: PropTypes.func + inputRef: PropTypes.func, + onCancelSearchPress: PropTypes.func, + onSearchFocus: PropTypes.func }; export default ListHeader; diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index e8dca1d8..c2a99673 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -101,23 +101,21 @@ const keyExtractor = item => item.rid; class RoomsListView extends React.Component { static navigationOptions = ({ navigation, screenProps }) => { const searching = navigation.getParam('searching'); - const cancelSearchingAndroid = navigation.getParam( - 'cancelSearchingAndroid' - ); + const cancelSearch = navigation.getParam('cancelSearch', () => {}); const onPressItem = navigation.getParam('onPressItem', () => {}); - const initSearchingAndroid = navigation.getParam( - 'initSearchingAndroid', + const initSearching = navigation.getParam( + 'initSearching', () => {} ); return { ...themedHeader(screenProps.theme), - headerLeft: searching ? ( + headerLeft: searching && isAndroid ? ( ) : ( @@ -127,13 +125,13 @@ class RoomsListView extends React.Component { /> ), headerTitle: , - headerRight: searching ? null : ( + headerRight: searching && isAndroid ? null : ( {isAndroid ? ( ) : null} nextProps[key] !== this.props[key]); if (propsUpdated) { @@ -262,6 +260,10 @@ class RoomsListView extends React.Component { this.shouldUpdate = true; } + if (nextState.searching !== searching) { + return true; + } + // Abort if it's not focused if (!nextProps.navigation.isFocused()) { return false; @@ -269,16 +271,12 @@ class RoomsListView extends React.Component { const { loading, - searching, width, search } = this.state; if (nextState.loading !== loading) { return true; } - if (nextState.searching !== searching) { - return true; - } if (nextState.width !== width) { return true; } @@ -452,29 +450,50 @@ class RoomsListView extends React.Component { }); } - initSearchingAndroid = () => { + initSearching = () => { const { openSearchHeader, navigation } = this.props; - this.setState({ searching: true }); - navigation.setParams({ searching: true }); - openSearchHeader(); + this.internalSetState({ searching: true }); + if (isAndroid) { + navigation.setParams({ searching: true }); + openSearchHeader(); + } }; - cancelSearchingAndroid = () => { + cancelSearch = () => { + const { searching } = this.state; + const { closeSearchHeader, navigation } = this.props; + + if (!searching) { + return; + } + + if (isIOS && this.inputRef) { + this.inputRef.blur(); + this.inputRef.clear(); + } if (isAndroid) { - const { closeSearchHeader, navigation } = this.props; - this.setState({ searching: false }); navigation.setParams({ searching: false }); closeSearchHeader(); - this.internalSetState({ search: [] }); } Keyboard.dismiss(); + + this.setState({ searching: false, search: [] }, () => { + setTimeout(() => { + const offset = isAndroid ? 0 : SCROLL_OFFSET; + if (this.scroll.scrollTo) { + this.scroll.scrollTo({ x: 0, y: offset, animated: true }); + } else if (this.scroll.scrollToOffset) { + this.scroll.scrollToOffset({ offset }); + } + }, 200); + }); }; handleBackPress = () => { const { searching } = this.state; const { appStart } = this.props; if (searching) { - this.cancelSearchingAndroid(); + this.cancelSearch(); return true; } appStart('background'); @@ -483,10 +502,19 @@ class RoomsListView extends React.Component { // eslint-disable-next-line react/sort-comp search = debounce(async(text) => { + const { searching } = this.state; const result = await RocketChat.search({ text }); + // if the search was cancelled before the promise is resolved + if (!searching) { + return; + } this.internalSetState({ - search: result + search: result, + searching: true }); + if (this.scroll && this.scroll.scrollTo) { + this.scroll.scrollTo({ x: 0, y: 0, animated: true }); + } }, 300); getRoomTitle = item => RocketChat.getRoomTitle(item) @@ -494,8 +522,8 @@ class RoomsListView extends React.Component { getRoomAvatar = item => RocketChat.getRoomAvatar(item) goRoom = (item) => { - this.cancelSearchingAndroid(); const { navigation } = this.props; + this.cancelSearch(); this.item = item; navigation.navigate('RoomView', { rid: item.rid, @@ -678,21 +706,29 @@ class RoomsListView extends React.Component { }; onRefresh = () => { + const { searching } = this.state; const { roomsRequest } = this.props; + if (searching) { + return; + } roomsRequest({ allData: true }); } getScrollRef = ref => (this.scroll = ref); + getInputRef = ref => (this.inputRef = ref); + renderListHeader = () => { - const { search } = this.state; + const { searching } = this.state; const { sortBy } = this.props; return ( { this.inputRef = ref; }} - searchLength={search.length} + inputRef={this.getInputRef} + searching={searching} sortBy={sortBy} onChangeSearchText={this.search} + onCancelSearchPress={this.cancelSearch} + onSearchFocus={this.initSearching} toggleSort={this.toggleSort} goDirectory={this.goDirectory} /> @@ -768,7 +804,7 @@ class RoomsListView extends React.Component { renderScroll = () => { const { - loading, chats, search + loading, chats, search, searching } = this.state; const { theme, refreshing } = this.props; @@ -779,8 +815,8 @@ class RoomsListView extends React.Component { return (