[FIX] Spotlight (#1719)

This commit is contained in:
Diego Mello 2020-02-13 16:24:39 -03:00 committed by GitHub
parent 3a87872415
commit 58e5781ed2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 133 additions and 59 deletions

View File

@ -37,7 +37,7 @@ const styles = StyleSheet.create({
...sharedStyles.textRegular ...sharedStyles.textRegular
}, },
cancel: { cancel: {
marginRight: 10 marginRight: 15
}, },
cancelText: { cancelText: {
...sharedStyles.textRegular, ...sharedStyles.textRegular,

View File

@ -565,18 +565,28 @@ const RocketChat = {
RocketChat.spotlight(searchText, usernames, { users: filterUsers, rooms: filterRooms }), RocketChat.spotlight(searchText, usernames, { users: filterUsers, rooms: filterRooms }),
new Promise((resolve, reject) => this.oldPromise = reject) new Promise((resolve, reject) => this.oldPromise = reject)
]); ]);
if (filterUsers) {
data = data.concat(users.map(user => ({ data = data.concat(users.map(user => ({
...user, ...user,
rid: user.username, rid: user.username,
name: user.username, name: user.username,
t: 'd', t: 'd',
search: true search: true
})), rooms.map(room => ({ })));
rid: room._id, }
...room, if (filterRooms) {
search: true 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; delete this.oldPromise;
return data; return data;

View File

@ -38,6 +38,7 @@ class RoomsListHeaderView extends PureComponent {
} }
} }
// eslint-disable-next-line react/sort-comp
handleCommands = ({ event }) => { handleCommands = ({ event }) => {
if (handleCommandOpenServerDropdown(event)) { if (handleCommandOpenServerDropdown(event)) {
this.onPress(); this.onPress();
@ -79,7 +80,7 @@ class RoomsListHeaderView extends PureComponent {
connecting={connecting} connecting={connecting}
isFetching={isFetching} isFetching={isFetching}
onPress={this.onPress} onPress={this.onPress}
onSearchChangeText={text => this.onSearchChangeText(text)} onSearchChangeText={this.onSearchChangeText}
/> />
); );
} }

View File

@ -10,7 +10,10 @@ import DisclosureIndicator from '../../../containers/DisclosureIndicator';
import { themes } from '../../../constants/colors'; import { themes } from '../../../constants/colors';
import { withTheme } from '../../../theme'; 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 }; const color = { color: themes[theme].headerSecondaryText };
return ( return (
<Touch <Touch
@ -33,6 +36,7 @@ const Directory = React.memo(({ goDirectory, theme }) => {
}); });
Directory.propTypes = { Directory.propTypes = {
searching: PropTypes.bool,
goDirectory: PropTypes.func, goDirectory: PropTypes.func,
theme: PropTypes.string theme: PropTypes.string
}; };

View File

@ -5,7 +5,9 @@ import SearchBox from '../../../containers/SearchBox';
import { isIOS } from '../../../utils/deviceInfo'; import { isIOS } from '../../../utils/deviceInfo';
import { withTheme } from '../../../theme'; import { withTheme } from '../../../theme';
const SearchBar = React.memo(({ theme, onChangeSearchText, inputRef }) => { const SearchBar = React.memo(({
theme, onChangeSearchText, inputRef, searching, onCancelSearchPress, onSearchFocus
}) => {
if (isIOS) { if (isIOS) {
return ( return (
<SearchBox <SearchBox
@ -13,6 +15,9 @@ const SearchBar = React.memo(({ theme, onChangeSearchText, inputRef }) => {
testID='rooms-list-view-search' testID='rooms-list-view-search'
inputRef={inputRef} inputRef={inputRef}
theme={theme} theme={theme}
hasCancel={searching}
onCancelPress={onCancelSearchPress}
onFocus={onSearchFocus}
/> />
); );
} }
@ -21,8 +26,11 @@ const SearchBar = React.memo(({ theme, onChangeSearchText, inputRef }) => {
SearchBar.propTypes = { SearchBar.propTypes = {
theme: PropTypes.string, theme: PropTypes.string,
searching: PropTypes.bool,
inputRef: PropTypes.func, inputRef: PropTypes.func,
onChangeSearchText: PropTypes.func onChangeSearchText: PropTypes.func,
onCancelSearchPress: PropTypes.func,
onSearchFocus: PropTypes.func
}; };
export default withTheme(SearchBar); export default withTheme(SearchBar);

View File

@ -11,9 +11,9 @@ import { withTheme } from '../../../theme';
const Sort = React.memo(({ const Sort = React.memo(({
searchLength, sortBy, toggleSort, theme searching, sortBy, toggleSort, theme
}) => { }) => {
if (searchLength > 0) { if (searching > 0) {
return null; return null;
} }
return ( return (
@ -36,7 +36,7 @@ const Sort = React.memo(({
}); });
Sort.propTypes = { Sort.propTypes = {
searchLength: PropTypes.number, searching: PropTypes.bool,
sortBy: PropTypes.string, sortBy: PropTypes.string,
theme: PropTypes.string, theme: PropTypes.string,
toggleSort: PropTypes.func toggleSort: PropTypes.func

View File

@ -6,22 +6,37 @@ import Directory from './Directory';
import Sort from './Sort'; import Sort from './Sort';
const ListHeader = React.memo(({ const ListHeader = React.memo(({
searchLength, sortBy, onChangeSearchText, toggleSort, goDirectory, inputRef searching,
sortBy,
onChangeSearchText,
toggleSort,
goDirectory,
inputRef,
onCancelSearchPress,
onSearchFocus
}) => ( }) => (
<> <>
<SearchBar onChangeSearchText={onChangeSearchText} inputRef={inputRef} /> <SearchBar
<Directory goDirectory={goDirectory} /> inputRef={inputRef}
<Sort searchLength={searchLength} sortBy={sortBy} toggleSort={toggleSort} /> searching={searching}
onChangeSearchText={onChangeSearchText}
onCancelSearchPress={onCancelSearchPress}
onSearchFocus={onSearchFocus}
/>
<Directory searching={searching} goDirectory={goDirectory} />
<Sort searching={searching} sortBy={sortBy} toggleSort={toggleSort} />
</> </>
)); ));
ListHeader.propTypes = { ListHeader.propTypes = {
searchLength: PropTypes.number, searching: PropTypes.bool,
sortBy: PropTypes.string, sortBy: PropTypes.string,
onChangeSearchText: PropTypes.func, onChangeSearchText: PropTypes.func,
toggleSort: PropTypes.func, toggleSort: PropTypes.func,
goDirectory: PropTypes.func, goDirectory: PropTypes.func,
inputRef: PropTypes.func inputRef: PropTypes.func,
onCancelSearchPress: PropTypes.func,
onSearchFocus: PropTypes.func
}; };
export default ListHeader; export default ListHeader;

View File

@ -101,23 +101,21 @@ const keyExtractor = item => item.rid;
class RoomsListView extends React.Component { class RoomsListView extends React.Component {
static navigationOptions = ({ navigation, screenProps }) => { static navigationOptions = ({ navigation, screenProps }) => {
const searching = navigation.getParam('searching'); const searching = navigation.getParam('searching');
const cancelSearchingAndroid = navigation.getParam( const cancelSearch = navigation.getParam('cancelSearch', () => {});
'cancelSearchingAndroid'
);
const onPressItem = navigation.getParam('onPressItem', () => {}); const onPressItem = navigation.getParam('onPressItem', () => {});
const initSearchingAndroid = navigation.getParam( const initSearching = navigation.getParam(
'initSearchingAndroid', 'initSearching',
() => {} () => {}
); );
return { return {
...themedHeader(screenProps.theme), ...themedHeader(screenProps.theme),
headerLeft: searching ? ( headerLeft: searching && isAndroid ? (
<CustomHeaderButtons left> <CustomHeaderButtons left>
<Item <Item
title='cancel' title='cancel'
iconName='cross' iconName='cross'
onPress={cancelSearchingAndroid} onPress={cancelSearch}
/> />
</CustomHeaderButtons> </CustomHeaderButtons>
) : ( ) : (
@ -127,13 +125,13 @@ class RoomsListView extends React.Component {
/> />
), ),
headerTitle: <RoomsListHeaderView />, headerTitle: <RoomsListHeaderView />,
headerRight: searching ? null : ( headerRight: searching && isAndroid ? null : (
<CustomHeaderButtons> <CustomHeaderButtons>
{isAndroid ? ( {isAndroid ? (
<Item <Item
title='search' title='search'
iconName='magnifier' iconName='magnifier'
onPress={initSearchingAndroid} onPress={initSearching}
/> />
) : null} ) : null}
<Item <Item
@ -200,8 +198,8 @@ class RoomsListView extends React.Component {
const { navigation, closeServerDropdown } = this.props; const { navigation, closeServerDropdown } = this.props;
navigation.setParams({ navigation.setParams({
onPressItem: this._onPressItem, onPressItem: this._onPressItem,
initSearchingAndroid: this.initSearchingAndroid, initSearching: this.initSearching,
cancelSearchingAndroid: this.cancelSearchingAndroid cancelSearch: this.cancelSearch
}); });
if (isTablet) { if (isTablet) {
EventEmitter.addEventListener(KEY_COMMAND, this.handleCommands); EventEmitter.addEventListener(KEY_COMMAND, this.handleCommands);
@ -247,7 +245,7 @@ class RoomsListView extends React.Component {
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
const { allChats } = this.state; const { allChats, searching } = 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) {
@ -262,6 +260,10 @@ class RoomsListView extends React.Component {
this.shouldUpdate = true; this.shouldUpdate = true;
} }
if (nextState.searching !== searching) {
return true;
}
// Abort if it's not focused // Abort if it's not focused
if (!nextProps.navigation.isFocused()) { if (!nextProps.navigation.isFocused()) {
return false; return false;
@ -269,16 +271,12 @@ class RoomsListView extends React.Component {
const { const {
loading, loading,
searching,
width, width,
search search
} = this.state; } = this.state;
if (nextState.loading !== loading) { if (nextState.loading !== loading) {
return true; return true;
} }
if (nextState.searching !== searching) {
return true;
}
if (nextState.width !== width) { if (nextState.width !== width) {
return true; return true;
} }
@ -452,29 +450,50 @@ class RoomsListView extends React.Component {
}); });
} }
initSearchingAndroid = () => { initSearching = () => {
const { openSearchHeader, navigation } = this.props; const { openSearchHeader, navigation } = this.props;
this.setState({ searching: true }); this.internalSetState({ searching: true });
navigation.setParams({ searching: true }); if (isAndroid) {
openSearchHeader(); 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) { if (isAndroid) {
const { closeSearchHeader, navigation } = this.props;
this.setState({ searching: false });
navigation.setParams({ searching: false }); navigation.setParams({ searching: false });
closeSearchHeader(); closeSearchHeader();
this.internalSetState({ search: [] });
} }
Keyboard.dismiss(); 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 = () => { handleBackPress = () => {
const { searching } = this.state; const { searching } = this.state;
const { appStart } = this.props; const { appStart } = this.props;
if (searching) { if (searching) {
this.cancelSearchingAndroid(); this.cancelSearch();
return true; return true;
} }
appStart('background'); appStart('background');
@ -483,10 +502,19 @@ class RoomsListView extends React.Component {
// eslint-disable-next-line react/sort-comp // eslint-disable-next-line react/sort-comp
search = debounce(async(text) => { search = debounce(async(text) => {
const { searching } = this.state;
const result = await RocketChat.search({ text }); const result = await RocketChat.search({ text });
// if the search was cancelled before the promise is resolved
if (!searching) {
return;
}
this.internalSetState({ this.internalSetState({
search: result search: result,
searching: true
}); });
if (this.scroll && this.scroll.scrollTo) {
this.scroll.scrollTo({ x: 0, y: 0, animated: true });
}
}, 300); }, 300);
getRoomTitle = item => RocketChat.getRoomTitle(item) getRoomTitle = item => RocketChat.getRoomTitle(item)
@ -494,8 +522,8 @@ class RoomsListView extends React.Component {
getRoomAvatar = item => RocketChat.getRoomAvatar(item) getRoomAvatar = item => RocketChat.getRoomAvatar(item)
goRoom = (item) => { goRoom = (item) => {
this.cancelSearchingAndroid();
const { navigation } = this.props; const { navigation } = this.props;
this.cancelSearch();
this.item = item; this.item = item;
navigation.navigate('RoomView', { navigation.navigate('RoomView', {
rid: item.rid, rid: item.rid,
@ -678,21 +706,29 @@ class RoomsListView extends React.Component {
}; };
onRefresh = () => { onRefresh = () => {
const { searching } = this.state;
const { roomsRequest } = this.props; const { roomsRequest } = this.props;
if (searching) {
return;
}
roomsRequest({ allData: true }); roomsRequest({ allData: true });
} }
getScrollRef = ref => (this.scroll = ref); getScrollRef = ref => (this.scroll = ref);
getInputRef = ref => (this.inputRef = ref);
renderListHeader = () => { renderListHeader = () => {
const { search } = this.state; const { searching } = this.state;
const { sortBy } = this.props; const { sortBy } = this.props;
return ( return (
<ListHeader <ListHeader
inputRef={(ref) => { this.inputRef = ref; }} inputRef={this.getInputRef}
searchLength={search.length} searching={searching}
sortBy={sortBy} sortBy={sortBy}
onChangeSearchText={this.search} onChangeSearchText={this.search}
onCancelSearchPress={this.cancelSearch}
onSearchFocus={this.initSearching}
toggleSort={this.toggleSort} toggleSort={this.toggleSort}
goDirectory={this.goDirectory} goDirectory={this.goDirectory}
/> />
@ -768,7 +804,7 @@ class RoomsListView extends React.Component {
renderScroll = () => { renderScroll = () => {
const { const {
loading, chats, search loading, chats, search, searching
} = this.state; } = this.state;
const { theme, refreshing } = this.props; const { theme, refreshing } = this.props;
@ -779,8 +815,8 @@ class RoomsListView extends React.Component {
return ( return (
<FlatList <FlatList
ref={this.getScrollRef} ref={this.getScrollRef}
data={search.length ? search : chats} data={searching ? search : chats}
extraData={search.length ? search : chats} extraData={searching ? search : chats}
contentOffset={isIOS ? { x: 0, y: SCROLL_OFFSET } : {}} contentOffset={isIOS ? { x: 0, y: SCROLL_OFFSET } : {}}
keyExtractor={keyExtractor} keyExtractor={keyExtractor}
style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]} style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]}