[FIX] Spotlight (#1719)
This commit is contained in:
parent
3a87872415
commit
58e5781ed2
|
@ -37,7 +37,7 @@ const styles = StyleSheet.create({
|
||||||
...sharedStyles.textRegular
|
...sharedStyles.textRegular
|
||||||
},
|
},
|
||||||
cancel: {
|
cancel: {
|
||||||
marginRight: 10
|
marginRight: 15
|
||||||
},
|
},
|
||||||
cancelText: {
|
cancelText: {
|
||||||
...sharedStyles.textRegular,
|
...sharedStyles.textRegular,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 }]}
|
||||||
|
|
Loading…
Reference in New Issue