Filter channels to not return my own DM (#675)

This commit is contained in:
enahum 2017-06-28 09:45:30 -04:00 committed by Harrison Healey
parent e89b63441b
commit 7026ea4bec
9 changed files with 134 additions and 75 deletions

View file

@ -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);

View file

@ -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}
/>
</View>
);

View file

@ -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 {
<View
style={[
styles.container,
containerStyle,
{height: inputHeight},
backgroundColor && {backgroundColor}
]}
@ -140,24 +168,24 @@ export default class SearchBarAndroid extends PureComponent {
{
backgroundColor: inputColor,
height: inputHeight,
paddingLeft: inputHeight * 0.25
paddingLeft: isFocused ? 0 : inputHeight * 0.25
}
]}
>
{isFocused ?
<TouchableWithoutFeedback
onPress={this.onCancelButtonPress}
style={{paddingRight: 5}}
style={{paddingRight: 15}}
>
<Icon
name='arrow-back'
size={24}
size={backArrowSize}
color={titleCancelColor || placeholderTextColor}
/>
</TouchableWithoutFeedback> :
<Icon
name={'search'}
size={16}
size={searchIconSize}
color={tintColorSearch || placeholderTextColor}
/>
}
@ -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 {
<Icon
style={[{paddingRight: (inputHeight * 0.2)}]}
name='close'
size={16}
size={deleteIconSize}
color={tintColorDelete || placeholderTextColor}
/>
</TouchableWithoutFeedback> : null
@ -208,7 +238,6 @@ const styles = StyleSheet.create({
searchBar: {
flex: 1,
flexDirection: 'row',
backgroundColor: 'red',
alignItems: 'center'
},
searchBarInput: {

View file

@ -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}
/>
);

View file

@ -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}
/>
<TouchableWithoutFeedback onPress={this.onFocus}>
{((this.props.iconSearch) ?

View file

@ -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}
/>
</View>
<MemberList

View file

@ -60,7 +60,8 @@ class ChannelMembers extends PureComponent {
profiles: [],
searching: false,
selectedMembers: {},
showNoResults: false
showNoResults: false,
term: ''
};
this.removeButton.title = props.intl.formatMessage({id: 'channel_members_modal.remove', defaultMessage: 'Remove'});
@ -123,7 +124,7 @@ class ChannelMembers extends PureComponent {
cancelSearch = () => {
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}
/>
</View>
<MemberList

View file

@ -62,7 +62,8 @@ class MoreChannels extends PureComponent {
adding: false,
next: true,
searching: false,
showNoResults: false
showNoResults: false,
term: ''
};
this.rightButton.title = props.intl.formatMessage({id: 'mobile.create_channel', defaultMessage: 'Create'});
this.leftButton = {...this.leftButton, icon: props.closeButton};
@ -142,7 +143,7 @@ class MoreChannels extends PureComponent {
cancelSearch = () => {
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}
/>
</View>
<ChannelList

View file

@ -52,7 +52,8 @@ class MoreDirectMessages extends PureComponent {
adding: false,
next: true,
searching: false,
showNoResults: false
showNoResults: false,
term: ''
};
this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent);
}
@ -63,11 +64,11 @@ class MoreDirectMessages extends PureComponent {
nextProps.requestStatus.status === RequestStatus.SUCCESS) {
const {page} = this.state;
const profiles = nextProps.profiles.splice(0, (page + 1) * General.PROFILE_CHUNK_SIZE);
this.setState({profiles, showNoResults: true, error: null});
this.setState({profiles, showNoResults: true});
} else if (this.state.searching &&
nextProps.searchRequest.status === RequestStatus.SUCCESS) {
const results = filterProfilesMatchingTerm(nextProps.profiles, this.state.term);
this.setState({profiles: results, showNoResults: true, error: null});
this.setState({profiles: results, showNoResults: true});
}
}
@ -111,8 +112,7 @@ class MoreDirectMessages extends PureComponent {
cancelSearch = () => {
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}
/>
</View>
<MemberList