diff --git a/app/components/channel_drawer/channels_list/filtered_list/filtered_list.js b/app/components/channel_drawer/channels_list/filtered_list/filtered_list.js index 627a9fa7b..5b2910e75 100644 --- a/app/components/channel_drawer/channels_list/filtered_list/filtered_list.js +++ b/app/components/channel_drawer/channels_list/filtered_list/filtered_list.js @@ -120,30 +120,6 @@ class ChannelDrawerList extends Component { }); }; - completeDirectGroupInfo = (channel) => { - const {currentUserId, myPreferences, profiles, profilesInChannel} = this.props; - const profilesIds = profilesInChannel[channel.id]; - if (profilesIds) { - function sortUsernames(a, b) { - const locale = profiles[currentUserId].locale; - return a.localeCompare(b, locale, {numeric: true}); - } - - const displayName = []; - profilesIds.forEach((teammateId) => { - if (teammateId !== currentUserId) { - displayName.push(displayUsername(profiles[teammateId], myPreferences)); - } - }); - - const gm = {...channel}; - return Object.assign(gm, { - display_name: displayName.sort(sortUsernames).join(', ') - }); - } - return channel; - }; - buildChannelsForSearch = (props, term) => { const data = []; const {groupChannels, otherChannels, styles} = props; @@ -166,9 +142,11 @@ class ChannelDrawerList extends Component { }); const unreads = this.filterChannels(unreadChannels, term); - const channels = this.filterChannels([...favorites, ...publicChannels, ...privateChannels], term); + const channels = this.filterChannels([...favorites, ...publicChannels, ...privateChannels], term). + sort(sortChannelsByDisplayName.bind(null, props.intl.locale)); + const others = this.filterChannels(notMemberOf, term); - const groups = this.filterChannels(groupChannels.map((g) => this.completeDirectGroupInfo(g)), term); + const groups = this.filterChannels(groupChannels, term); const fakeDms = this.filterChannels(this.buildFakeDms(props), term); const directMessages = [...groups, ...fakeDms].sort(sortChannelsByDisplayName.bind(null, props.intl.locale)); @@ -204,8 +182,8 @@ class ChannelDrawerList extends Component { }; buildFakeDms = (props) => { - const {myPreferences, profiles, statuses} = props; - const users = Object.values(profiles); + const {currentUserId, myPreferences, profiles, statuses} = props; + const users = Object.values(profiles).filter((p) => p.id !== currentUserId); return users.map((u) => { const displayName = displayUsername(u, myPreferences); diff --git a/app/components/channel_drawer/channels_list/index.js b/app/components/channel_drawer/channels_list/index.js index 82e597dbb..0b9c75491 100644 --- a/app/components/channel_drawer/channels_list/index.js +++ b/app/components/channel_drawer/channels_list/index.js @@ -49,7 +49,7 @@ class ChannelsList extends Component { this.firstUnreadChannel = null; this.state = { searching: false, - term: null + term: '' }; MaterialIcon.getImageSource('close', 20, this.props.theme.sidebarHeaderTextColor). @@ -104,7 +104,7 @@ class ChannelsList extends Component { cancelSearch = () => { this.props.onSearchEnds(); this.setState({searching: false}); - this.onSearch(null); + this.onSearch(''); }; render() { @@ -169,6 +169,7 @@ class ChannelsList extends Component { onCancelButtonPress={this.cancelSearch} onChangeText={this.onSearch} onFocus={this.onSearchFocused} + value={term} /> ); diff --git a/app/components/search_bar/search_bar.android.js b/app/components/search_bar/search_bar.android.js index 5abc4950f..565dfb486 100644 --- a/app/components/search_bar/search_bar.android.js +++ b/app/components/search_bar/search_bar.android.js @@ -17,10 +17,15 @@ import {changeOpacity} from 'app/utils/theme'; export default class SearchBarAndroid extends PureComponent { static propTypes = { autoFocus: PropTypes.bool, + backArrowSize: PropTypes.number, + deleteIconSize: PropTypes.number, + searchIconSize: PropTypes.number, onCancelButtonPress: PropTypes.func, onChangeText: PropTypes.func, onFocus: PropTypes.func, + onBlur: PropTypes.func, onSearchButtonPress: PropTypes.func, + onSelectionChange: PropTypes.func, backgroundColor: PropTypes.string, placeholderTextColor: PropTypes.string, titleCancelColor: PropTypes.string, @@ -37,25 +42,32 @@ export default class SearchBarAndroid extends PureComponent { inputHeight: PropTypes.number, inputBorderRadius: PropTypes.number, blurOnSubmit: PropTypes.bool, - value: PropTypes.string + value: PropTypes.string, + containerStyle: PropTypes.object }; static defaultProps = { + backArrowSize: 24, + deleteIconSize: 16, + searchIconSize: 16, blurOnSubmit: false, placeholder: 'Search', showCancelButton: true, placeholderTextColor: changeOpacity('#000', 0.5), + containerStyle: {}, onSearchButtonPress: () => true, onCancelButtonPress: () => true, onChangeText: () => true, - onFocus: () => true + onFocus: () => true, + onBlur: () => true, + onSelectionChange: () => true, + value: '' }; constructor(props) { super(props); this.state = { - isFocused: false, - value: props.value || '' + isFocused: false }; } @@ -63,8 +75,12 @@ export default class SearchBarAndroid extends PureComponent { this.onCancelButtonPress(); }; + onBlur = () => { + this.props.onBlur(); + }; + onSearchButtonPress = () => { - const {value} = this.state; + const {value} = this.props; if (value) { this.props.onSearchButtonPress(value); @@ -75,8 +91,7 @@ export default class SearchBarAndroid extends PureComponent { Keyboard.dismiss(); InteractionManager.runAfterInteractions(() => { this.setState({ - isFocused: false, - value: '' + isFocused: false }, () => { this.props.onCancelButtonPress(); }); @@ -84,15 +99,22 @@ export default class SearchBarAndroid extends PureComponent { }; onChangeText = (value) => { - this.setState({value}); this.props.onChangeText(value); }; + onSelectionChange = (event) => { + this.props.onSelectionChange(event); + }; + onFocus = () => { this.setState({isFocused: true}); this.props.onFocus(); }; + blur = () => { + this.refs.input.blur(); + }; + focus = () => { this.refs.input.focus(); }; @@ -100,6 +122,9 @@ export default class SearchBarAndroid extends PureComponent { render() { const { autoCapitalize, + backArrowSize, + deleteIconSize, + searchIconSize, backgroundColor, blurOnSubmit, inputHeight, @@ -110,9 +135,11 @@ export default class SearchBarAndroid extends PureComponent { returnKeyType, titleCancelColor, tintColorDelete, - tintColorSearch + tintColorSearch, + containerStyle, + value } = this.props; - const {isFocused, value} = this.state; + const {isFocused} = this.state; const inputNoBackground = { ...inputStyle @@ -130,6 +157,7 @@ export default class SearchBarAndroid extends PureComponent { {isFocused ? : } @@ -170,8 +198,10 @@ export default class SearchBarAndroid extends PureComponent { returnKeyType={returnKeyType || 'search'} keyboardType={keyboardType || 'default'} onFocus={this.onFocus} + onBlur={this.onBlur} onChangeText={this.onChangeText} onSubmitEditing={this.onSearchButtonPress} + onSelectionChange={this.onSelectionChange} placeholder={placeholder} placeholderTextColor={placeholderTextColor} underlineColorAndroid='transparent' @@ -186,7 +216,7 @@ export default class SearchBarAndroid extends PureComponent { : null @@ -208,7 +238,6 @@ const styles = StyleSheet.create({ searchBar: { flex: 1, flexDirection: 'row', - backgroundColor: 'red', alignItems: 'center' }, searchBarInput: { diff --git a/app/components/search_bar/search_bar.ios.js b/app/components/search_bar/search_bar.ios.js index 71b9036a3..5459a36ff 100644 --- a/app/components/search_bar/search_bar.ios.js +++ b/app/components/search_bar/search_bar.ios.js @@ -11,7 +11,9 @@ export default class SearchBarIos extends Component { onCancelButtonPress: PropTypes.func, onChangeText: PropTypes.func, onFocus: PropTypes.func, + onBlur: PropTypes.func, onSearchButtonPress: PropTypes.func, + onSelectionChange: PropTypes.func, backgroundColor: PropTypes.string, placeholderTextColor: PropTypes.string, titleCancelColor: PropTypes.string, @@ -43,13 +45,19 @@ export default class SearchBarIos extends Component { onSearchButtonPress: () => true, onCancelButtonPress: () => true, onChangeText: () => true, - onFocus: () => true + onFocus: () => true, + onBlur: () => true, + onSelectionChange: () => true }; cancel = () => { this.refs.search.onCancel(); }; + onBlur = () => { + this.props.onBlur(); + }; + onCancel = () => { Keyboard.dismiss(); InteractionManager.runAfterInteractions(() => { @@ -75,6 +83,14 @@ export default class SearchBarIos extends Component { } }; + onSelectionChange = (event) => { + this.props.onSelectionChange(event); + }; + + blur = () => { + this.refs.search.blur(); + }; + focus = () => { this.refs.search.focus(); }; @@ -92,8 +108,9 @@ export default class SearchBarIos extends Component { onCancel={this.onCancel} onChangeText={this.onChangeText} onFocus={this.onFocus} + onBlur={this.onBlur} onSearch={this.onSearch} - afterDelete={this.afterDelete} + onSelectionChange={this.onSelectionChange} onDelete={this.onDelete} /> ); diff --git a/app/components/search_bar/search_box.js b/app/components/search_bar/search_box.js index 9b676ede8..b3f0be595 100644 --- a/app/components/search_bar/search_box.js +++ b/app/components/search_bar/search_box.js @@ -24,11 +24,13 @@ const middleHeight = 20; export default class Search extends Component { static propTypes = { + onBlur: PropTypes.func, onFocus: PropTypes.func, onSearch: PropTypes.func, onChangeText: PropTypes.func, onCancel: PropTypes.func, onDelete: PropTypes.func, + onSelectionChange: PropTypes.func, backgroundColor: PropTypes.string, placeholderTextColor: PropTypes.string, titleCancelColor: PropTypes.string, @@ -76,6 +78,8 @@ export default class Search extends Component { }; static defaultProps = { + onSelectionChange: () => true, + onBlur: () => true, editable: true, blurOnSubmit: false, keyboardShouldPersist: false, @@ -91,7 +95,8 @@ export default class Search extends Component { shadowOpacityCollapsed: 0.12, shadowOpacityExpanded: 0.24, shadowRadius: 4, - shadowVisible: false + shadowVisible: false, + value: '' }; constructor(props) { @@ -117,6 +122,26 @@ export default class Search extends Component { this.shadowHeight = this.props.shadowOffsetHeightCollapsed; } + componentWillReceiveProps(nextProps) { + if (this.props.value !== nextProps.value) { + if (nextProps.value) { + this.iconDeleteAnimated = new Animated.Value(1); + } + } + } + + blur = () => { + this.refs.input_keyword.getNode().blur(); + }; + + focus = () => { + this.refs.input_keyword.getNode().focus(); + }; + + onBlur = () => { + this.props.onBlur(); + }; + onLayout = (event) => { const contentWidth = event.nativeEvent.layout.width; this.contentWidth = contentWidth; @@ -134,12 +159,11 @@ export default class Search extends Component { } if (this.props.onSearch) { - this.props.onSearch(this.state.keyword); + this.props.onSearch(this.props.value); } }; onChangeText = (text) => { - this.setState({keyword: text}); Animated.timing( this.iconDeleteAnimated, { @@ -149,7 +173,7 @@ export default class Search extends Component { ).start(); if (this.props.onChangeText) { - this.props.onChangeText(this.state.keyword); + this.props.onChangeText(text); } }; @@ -164,16 +188,12 @@ export default class Search extends Component { await this.expandAnimation(); if (this.props.onFocus) { - this.props.onFocus(this.state.keyword); + this.props.onFocus(this.props.value); } }); }; - focus = async () => { - this.refs.input_keyword.getNode().focus(); - }; - - onDelete = async () => { + onDelete = () => { Animated.timing( this.iconDeleteAnimated, { @@ -197,6 +217,10 @@ export default class Search extends Component { } }; + onSelectionChange = (event) => { + this.props.onSelectionChange(event); + }; + expandAnimation = () => { return new Promise((resolve) => { Animated.parallel([ @@ -231,7 +255,7 @@ export default class Search extends Component { Animated.timing( this.iconDeleteAnimated, { - toValue: (this.state.keyword.length > 0) ? 1 : 0, + toValue: (this.props.value.length > 0) ? 1 : 0, duration: 200 } ).start(), @@ -339,18 +363,21 @@ export default class Search extends Component { ]} autoFocus={this.props.autoFocus} editable={this.props.editable} - value={this.state.keyword} + value={this.props.value} onChangeText={this.onChangeText} placeholder={this.placeholder} placeholderTextColor={this.props.placeholderTextColor} onSubmitEditing={this.onSearch} + onSelectionChange={this.onSelectionChange} autoCorrect={false} blurOnSubmit={this.props.blurOnSubmit} returnKeyType={this.props.returnKeyType || 'search'} keyboardType={this.props.keyboardType || 'default'} autoCapitalize={this.props.autoCapitalize} + onBlur={this.onBlur} onFocus={this.onFocus} underlineColorAndroid='transparent' + enablesReturnKeyAutomatically={true} /> {((this.props.iconSearch) ? diff --git a/app/screens/channel_add_members/channel_add_members.js b/app/screens/channel_add_members/channel_add_members.js index 1a607e161..114c88d3b 100644 --- a/app/screens/channel_add_members/channel_add_members.js +++ b/app/screens/channel_add_members/channel_add_members.js @@ -59,7 +59,8 @@ class ChannelAddMembers extends PureComponent { profiles: [], searching: false, selectedMembers: {}, - showNoResults: false + showNoResults: false, + term: '' }; this.addButton.title = props.intl.formatMessage({id: 'integrations.add', defaultMessage: 'Add'}); @@ -121,7 +122,7 @@ class ChannelAddMembers extends PureComponent { cancelSearch = () => { this.setState({ searching: false, - term: null, + term: '', page: 0, profiles: markSelectedProfiles(this.props.membersNotInChannel, this.state.selectedMembers) }); @@ -215,7 +216,7 @@ class ChannelAddMembers extends PureComponent { render() { const {intl, loadMoreRequestStatus, searchRequestStatus, preferences, theme} = this.props; - const {adding, profiles, searching} = this.state; + const {adding, profiles, searching, term} = this.state; const {formatMessage} = intl; const isLoading = (loadMoreRequestStatus === RequestStatus.STARTED) || (searchRequestStatus === RequestStatus.STARTED); @@ -255,6 +256,7 @@ class ChannelAddMembers extends PureComponent { onChangeText={this.searchProfiles} onSearchButtonPress={this.searchProfiles} onCancelButtonPress={this.cancelSearch} + value={term} /> { this.setState({ searching: false, - term: null, + term: '', page: 0, profiles: markSelectedProfiles(this.props.currentChannelMembers, this.state.selectedMembers) }); @@ -272,7 +273,7 @@ class ChannelMembers extends PureComponent { render() { const {canManageUsers, intl, preferences, requestStatus, searchRequestStatus, theme} = this.props; const {formatMessage} = intl; - const {profiles, removing, searching, showNoResults} = this.state; + const {profiles, removing, searching, showNoResults, term} = this.state; const isLoading = (requestStatus === RequestStatus.STARTED) || (requestStatus.status === RequestStatus.NOT_STARTED) || (searchRequestStatus === RequestStatus.STARTED); const more = searching ? () => true : this.loadMoreMembers; @@ -311,6 +312,7 @@ class ChannelMembers extends PureComponent { onChangeText={this.searchProfiles} onSearchButtonPress={this.searchProfiles} onCancelButtonPress={this.cancelSearch} + value={term} /> { this.props.actions.getChannels(this.props.currentTeamId, 0); this.setState({ - term: null, + term: '', searching: false, page: 0 }); @@ -264,7 +265,7 @@ class MoreChannels extends PureComponent { render() { const {intl, requestStatus, theme} = this.props; - const {adding, channels, searching} = this.state; + const {adding, channels, searching, term} = this.state; const {formatMessage} = intl; const isLoading = requestStatus.status === RequestStatus.STARTED || requestStatus.status === RequestStatus.NOT_STARTED; const style = getStyleFromTheme(theme); @@ -297,6 +298,7 @@ class MoreChannels extends PureComponent { onChangeText={this.searchProfiles} onSearchButtonPress={this.searchProfiles} onCancelButtonPress={this.cancelSearch} + value={term} /> { this.setState({ searching: false, - term: null, - error: null, + term: '', page: 0, profiles: this.props.profiles }); @@ -178,7 +178,7 @@ class MoreDirectMessages extends PureComponent { render() { const {intl, preferences, requestStatus, searchRequest, theme} = this.props; - const {adding, profiles, searching, showNoResults} = this.state; + const {adding, profiles, searching, showNoResults, term} = this.state; const {formatMessage} = intl; const isLoading = (requestStatus.status === RequestStatus.STARTED) || (requestStatus.status === RequestStatus.NOT_STARTED) || (searchRequest.status === RequestStatus.STARTED); @@ -218,6 +218,7 @@ class MoreDirectMessages extends PureComponent { onChangeText={this.searchProfiles} onSearchButtonPress={this.searchProfiles} onCancelButtonPress={this.cancelSearch} + value={term} />