diff --git a/app/components/autocomplete/at_mention/at_mention.js b/app/components/autocomplete/at_mention/at_mention.js
index fc4284aca..1aa29e392 100644
--- a/app/components/autocomplete/at_mention/at_mention.js
+++ b/app/components/autocomplete/at_mention/at_mention.js
@@ -9,6 +9,7 @@ import {RequestStatus} from 'mattermost-redux/constants';
import {AT_MENTION_REGEX, AT_MENTION_SEARCH_REGEX} from 'app/constants/autocomplete';
import AtMentionItem from 'app/components/autocomplete/at_mention_item';
+import AutocompleteDivider from 'app/components/autocomplete/autocomplete_divider';
import AutocompleteSectionHeader from 'app/components/autocomplete/autocomplete_section_header';
import SpecialMentionItem from 'app/components/autocomplete/special_mention_item';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
@@ -26,6 +27,7 @@ export default class AtMention extends PureComponent {
isSearch: PropTypes.bool,
matchTerm: PropTypes.string,
onChangeText: PropTypes.func.isRequired,
+ onResultCountChange: PropTypes.func.isRequired,
outChannel: PropTypes.array,
requestStatus: PropTypes.string.isRequired,
teamMembers: PropTypes.array,
@@ -55,6 +57,9 @@ export default class AtMention extends PureComponent {
mentionComplete: false,
sections: []
});
+
+ this.props.onResultCountChange(0);
+
return;
} else if (matchTerm === null) {
// if the terms did not change but is null then we don't need to do anything
@@ -113,6 +118,8 @@ export default class AtMention extends PureComponent {
this.setState({
sections
});
+
+ this.props.onResultCountChange(sections.reduce((total, section) => total + section.data.length, 0));
}
}
@@ -214,6 +221,7 @@ export default class AtMention extends PureComponent {
sections={sections}
renderItem={this.renderItem}
renderSectionHeader={this.renderSectionHeader}
+ ItemSeparatorComponent={AutocompleteDivider}
initialNumToRender={10}
/>
);
diff --git a/app/components/autocomplete/at_mention_item/at_mention_item.js b/app/components/autocomplete/at_mention_item/at_mention_item.js
index 5aa6b2659..e68956549 100644
--- a/app/components/autocomplete/at_mention_item/at_mention_item.js
+++ b/app/components/autocomplete/at_mention_item/at_mention_item.js
@@ -10,7 +10,7 @@ import {
} from 'react-native';
import ProfilePicture from 'app/components/profile_picture';
-import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme';
+import {makeStyleSheetFromTheme} from 'app/utils/theme';
export default class AtMentionItem extends PureComponent {
static propTypes = {
@@ -60,19 +60,14 @@ export default class AtMentionItem extends PureComponent {
);
}
}
+
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
return {
row: {
paddingVertical: 8,
flexDirection: 'row',
alignItems: 'center',
- backgroundColor: theme.centerChannelBg,
- borderTopWidth: 1,
- borderTopColor: changeOpacity(theme.centerChannelColor, 0.2),
- borderLeftWidth: 1,
- borderLeftColor: changeOpacity(theme.centerChannelColor, 0.2),
- borderRightWidth: 1,
- borderRightColor: changeOpacity(theme.centerChannelColor, 0.2)
+ backgroundColor: theme.centerChannelBg
},
rowPicture: {
marginHorizontal: 8,
diff --git a/app/components/autocomplete/autocomplete.js b/app/components/autocomplete/autocomplete.js
new file mode 100644
index 000000000..f551266e2
--- /dev/null
+++ b/app/components/autocomplete/autocomplete.js
@@ -0,0 +1,123 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React, {PureComponent} from 'react';
+import PropTypes from 'prop-types';
+import {
+ Platform,
+ View
+} from 'react-native';
+
+import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
+
+import AtMention from './at_mention';
+import ChannelMention from './channel_mention';
+import EmojiSuggestion from './emoji_suggestion';
+
+export default class Autocomplete extends PureComponent {
+ static propTypes = {
+ onChangeText: PropTypes.func.isRequired,
+ rootId: PropTypes.string,
+ isSearch: PropTypes.bool,
+ theme: PropTypes.object.isRequired,
+ value: PropTypes.string
+ };
+
+ static defaultProps = {
+ isSearch: false
+ };
+
+ state = {
+ cursorPosition: 0,
+ atMentionCount: 0,
+ channelMentionCount: 0,
+ emojiCount: 0
+ };
+
+ handleSelectionChange = (event) => {
+ this.setState({
+ cursorPosition: event.nativeEvent.selection.end
+ });
+ };
+
+ handleAtMentionCountChange = (atMentionCount) => {
+ this.setState({atMentionCount});
+ };
+
+ handleChannelMentionCountChange = (channelMentionCount) => {
+ this.setState({channelMentionCount});
+ };
+
+ handleEmojiCountChange = (emojiCount) => {
+ this.setState({emojiCount});
+ };
+
+ render() {
+ const style = getStyleFromTheme(this.props.theme);
+
+ const containerStyle = [style.base];
+ if (this.props.isSearch) {
+ containerStyle.push(style.searchContainer);
+ } else {
+ containerStyle.push(style.container);
+ }
+
+ // We always need to render something, but we only draw the borders when we have results to show
+ if (this.state.atMentionCount + this.state.channelMentionCount + this.state.emojiCount > 0) {
+ containerStyle.push(style.borders);
+ }
+
+ return (
+
+
+
+
+
+ );
+ }
+}
+
+const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
+ return {
+ base: {
+ left: 0,
+ overflow: 'hidden',
+ position: 'absolute',
+ right: 0
+ },
+ borders: {
+ borderWidth: 1,
+ borderColor: changeOpacity(theme.centerChannelColor, 0.2)
+ },
+ container: {
+ bottom: 0,
+ maxHeight: 200
+ },
+ searchContainer: {
+ elevation: 5,
+ flex: 1,
+ maxHeight: 250,
+ zIndex: 5,
+ ...Platform.select({
+ android: {
+ top: 47
+ },
+ ios: {
+ top: 64
+ }
+ })
+ }
+ };
+});
diff --git a/app/components/autocomplete/autocomplete_divider/autocomplete_divider.js b/app/components/autocomplete/autocomplete_divider/autocomplete_divider.js
new file mode 100644
index 000000000..e094d80e1
--- /dev/null
+++ b/app/components/autocomplete/autocomplete_divider/autocomplete_divider.js
@@ -0,0 +1,32 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React, {PureComponent} from 'react';
+import PropTypes from 'prop-types';
+import {View} from 'react-native';
+
+import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme';
+
+export default class AutocompleteDivider extends PureComponent {
+ static propTypes = {
+ theme: PropTypes.object.isRequired
+ };
+
+ render() {
+ const {theme} = this.props;
+ const style = getStyleFromTheme(theme);
+
+ return (
+
+ );
+ }
+}
+
+const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
+ return {
+ divider: {
+ height: 1,
+ backgroundColor: changeOpacity(theme.centerChannelColor, 0.2)
+ }
+ };
+});
diff --git a/app/components/autocomplete/autocomplete_divider/index.js b/app/components/autocomplete/autocomplete_divider/index.js
new file mode 100644
index 000000000..af4ab5d1b
--- /dev/null
+++ b/app/components/autocomplete/autocomplete_divider/index.js
@@ -0,0 +1,16 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {connect} from 'react-redux';
+
+import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
+
+import AutocompleteDivider from './autocomplete_divider';
+
+function mapStateToProps(state) {
+ return {
+ theme: getTheme(state)
+ };
+}
+
+export default connect(mapStateToProps)(AutocompleteDivider);
diff --git a/app/components/autocomplete/autocomplete_section_header.js b/app/components/autocomplete/autocomplete_section_header.js
index 041b87be0..a5c950d93 100644
--- a/app/components/autocomplete/autocomplete_section_header.js
+++ b/app/components/autocomplete/autocomplete_section_header.js
@@ -40,11 +40,7 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
paddingLeft: 8,
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
borderTopWidth: 1,
- borderTopColor: changeOpacity(theme.centerChannelColor, 0.2),
- borderLeftWidth: 1,
- borderLeftColor: changeOpacity(theme.centerChannelColor, 0.2),
- borderRightWidth: 1,
- borderRightColor: changeOpacity(theme.centerChannelColor, 0.2)
+ borderTopColor: changeOpacity(theme.centerChannelColor, 0.2)
},
sectionText: {
fontSize: 12,
diff --git a/app/components/autocomplete/channel_mention/channel_mention.js b/app/components/autocomplete/channel_mention/channel_mention.js
index ad6eb0605..0aa901397 100644
--- a/app/components/autocomplete/channel_mention/channel_mention.js
+++ b/app/components/autocomplete/channel_mention/channel_mention.js
@@ -8,6 +8,7 @@ import {SectionList} from 'react-native';
import {RequestStatus} from 'mattermost-redux/constants';
import {CHANNEL_MENTION_REGEX, CHANNEL_MENTION_SEARCH_REGEX} from 'app/constants/autocomplete';
+import AutocompleteDivider from 'app/components/autocomplete/autocomplete_divider';
import AutocompleteSectionHeader from 'app/components/autocomplete/autocomplete_section_header';
import ChannelMentionItem from 'app/components/autocomplete/channel_mention_item';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
@@ -24,6 +25,7 @@ export default class ChannelMention extends PureComponent {
myChannels: PropTypes.array,
otherChannels: PropTypes.array,
onChangeText: PropTypes.func.isRequired,
+ onResultCountChange: PropTypes.func.isRequired,
privateChannels: PropTypes.array,
publicChannels: PropTypes.array,
requestStatus: PropTypes.string.isRequired,
@@ -53,6 +55,9 @@ export default class ChannelMention extends PureComponent {
mentionComplete: false,
sections: []
});
+
+ this.props.onResultCountChange(0);
+
return;
} else if (matchTerm === null) {
// if the terms did not change but is null then we don't need to do anything
@@ -112,6 +117,8 @@ export default class ChannelMention extends PureComponent {
this.setState({
sections
});
+
+ this.props.onResultCountChange(sections.reduce((total, section) => total + section.data.length, 0));
}
}
@@ -178,6 +185,7 @@ export default class ChannelMention extends PureComponent {
sections={sections}
renderItem={this.renderItem}
renderSectionHeader={this.renderSectionHeader}
+ ItemSeparatorComponent={AutocompleteDivider}
initialNumToRender={10}
/>
);
diff --git a/app/components/autocomplete/channel_mention_item/channel_mention_item.js b/app/components/autocomplete/channel_mention_item/channel_mention_item.js
index 119ff5ecd..75389c9dc 100644
--- a/app/components/autocomplete/channel_mention_item/channel_mention_item.js
+++ b/app/components/autocomplete/channel_mention_item/channel_mention_item.js
@@ -8,7 +8,7 @@ import {
TouchableOpacity
} from 'react-native';
-import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme';
+import {makeStyleSheetFromTheme} from 'app/utils/theme';
export default class ChannelMentionItem extends PureComponent {
static propTypes = {
@@ -46,19 +46,14 @@ export default class ChannelMentionItem extends PureComponent {
);
}
}
+
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
return {
row: {
padding: 8,
flexDirection: 'row',
alignItems: 'center',
- backgroundColor: theme.centerChannelBg,
- borderTopWidth: 1,
- borderTopColor: changeOpacity(theme.centerChannelColor, 0.2),
- borderLeftWidth: 1,
- borderLeftColor: changeOpacity(theme.centerChannelColor, 0.2),
- borderRightWidth: 1,
- borderRightColor: changeOpacity(theme.centerChannelColor, 0.2)
+ backgroundColor: theme.centerChannelBg
},
rowDisplayName: {
fontSize: 13,
diff --git a/app/components/autocomplete/emoji_suggestion/emoji_suggestion.js b/app/components/autocomplete/emoji_suggestion/emoji_suggestion.js
index a380724e3..5c8b701b9 100644
--- a/app/components/autocomplete/emoji_suggestion/emoji_suggestion.js
+++ b/app/components/autocomplete/emoji_suggestion/emoji_suggestion.js
@@ -10,8 +10,9 @@ import {
View
} from 'react-native';
+import AutocompleteDivider from 'app/components/autocomplete/autocomplete_divider';
import Emoji from 'app/components/emoji';
-import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme';
+import {makeStyleSheetFromTheme} from 'app/utils/theme';
const EMOJI_REGEX = /(^|\s|^\+|^-)(:([^:\s]*))$/i;
const EMOJI_REGEX_WITHOUT_PREFIX = /\B(:([^:\s]*))$/i;
@@ -25,6 +26,7 @@ export default class EmojiSuggestion extends Component {
emojis: PropTypes.array.isRequired,
theme: PropTypes.object.isRequired,
onChangeText: PropTypes.func.isRequired,
+ onResultCountChange: PropTypes.func.isRequired,
rootId: PropTypes.string,
value: PropTypes.string
};
@@ -49,6 +51,9 @@ export default class EmojiSuggestion extends Component {
matchTerm: null,
emojiComplete: false
});
+
+ this.props.onResultCountChange(0);
+
return;
}
@@ -69,9 +74,11 @@ export default class EmojiSuggestion extends Component {
}
this.setState({
- active: data.length,
+ active: data.length > 0,
dataSource: data
});
+
+ this.props.onResultCountChange(data.length);
}
completeSuggestion = (emoji) => {
@@ -137,6 +144,7 @@ export default class EmojiSuggestion extends Component {
data={this.state.dataSource}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
+ ItemSeparatorComponent={AutocompleteDivider}
pageSize={10}
initialListSize={10}
/>
@@ -162,13 +170,7 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 8,
- backgroundColor: theme.centerChannelBg,
- borderTopWidth: 1,
- borderTopColor: changeOpacity(theme.centerChannelColor, 0.2),
- borderLeftWidth: 1,
- borderLeftColor: changeOpacity(theme.centerChannelColor, 0.2),
- borderRightWidth: 1,
- borderRightColor: changeOpacity(theme.centerChannelColor, 0.2)
+ backgroundColor: theme.centerChannelBg
}
};
});
diff --git a/app/components/autocomplete/index.js b/app/components/autocomplete/index.js
index 1b2877272..a0ebdca7c 100644
--- a/app/components/autocomplete/index.js
+++ b/app/components/autocomplete/index.js
@@ -1,89 +1,16 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import React, {PureComponent} from 'react';
-import PropTypes from 'prop-types';
-import {
- Platform,
- StyleSheet,
- View
-} from 'react-native';
+import {connect} from 'react-redux';
-import AtMention from './at_mention';
-import ChannelMention from './channel_mention';
-import EmojiSuggestion from './emoji_suggestion';
+import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
-export default class Autocomplete extends PureComponent {
- static propTypes = {
- onChangeText: PropTypes.func.isRequired,
- rootId: PropTypes.string,
- isSearch: PropTypes.bool,
- value: PropTypes.string
+import Autocomplete from './autocomplete';
+
+function mapStateToProps(state) {
+ return {
+ theme: getTheme(state)
};
-
- static defaultProps = {
- isSearch: false
- };
-
- state = {
- cursorPosition: 0
- };
-
- handleSelectionChange = (event) => {
- this.setState({
- cursorPosition: event.nativeEvent.selection.end
- });
- };
-
- render() {
- const searchContainer = this.props.isSearch ? style.searchContainer : null;
- const container = this.props.isSearch ? null : style.container;
- return (
-
-
-
-
-
-
-
- );
- }
}
-const style = StyleSheet.create({
- container: {
- position: 'absolute',
- bottom: 0,
- left: 0,
- right: 0,
- maxHeight: 200,
- overflow: 'hidden'
- },
- searchContainer: {
- elevation: 5,
- flex: 1,
- left: 0,
- maxHeight: 250,
- overflow: 'hidden',
- position: 'absolute',
- right: 0,
- zIndex: 5,
- ...Platform.select({
- android: {
- top: 47
- },
- ios: {
- top: 64
- }
- })
- }
-});
+export default connect(mapStateToProps, null, null, {withRef: true})(Autocomplete);
diff --git a/app/components/autocomplete/special_mention_item.js b/app/components/autocomplete/special_mention_item.js
index ebba3ab91..c74be2afa 100644
--- a/app/components/autocomplete/special_mention_item.js
+++ b/app/components/autocomplete/special_mention_item.js
@@ -70,13 +70,7 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
paddingVertical: 8,
flexDirection: 'row',
alignItems: 'center',
- backgroundColor: theme.centerChannelBg,
- borderTopWidth: 1,
- borderTopColor: changeOpacity(theme.centerChannelColor, 0.2),
- borderLeftWidth: 1,
- borderLeftColor: changeOpacity(theme.centerChannelColor, 0.2),
- borderRightWidth: 1,
- borderRightColor: changeOpacity(theme.centerChannelColor, 0.2)
+ backgroundColor: theme.centerChannelBg
},
rowPicture: {
marginHorizontal: 8,
diff --git a/app/components/post_textbox/post_textbox.js b/app/components/post_textbox/post_textbox.js
index b46479d88..58881b004 100644
--- a/app/components/post_textbox/post_textbox.js
+++ b/app/components/post_textbox/post_textbox.js
@@ -199,7 +199,7 @@ class PostTextbox extends PureComponent {
this.props.actions.handlePostDraftSelectionChanged(this.props.channelId, cursorPosition);
}
- this.autocomplete.handleSelectionChange(event);
+ this.autocomplete.getWrappedInstance().handleSelectionChange(event);
};
handleSendMessage = () => {
diff --git a/app/screens/search/search.js b/app/screens/search/search.js
index 271f6cd60..75b7a716f 100644
--- a/app/screens/search/search.js
+++ b/app/screens/search/search.js
@@ -150,7 +150,7 @@ class Search extends PureComponent {
handleSelectionChange = (event) => {
if (this.autocomplete) {
- this.autocomplete.handleSelectionChange(event);
+ this.autocomplete.getWrappedInstance().handleSelectionChange(event);
}
};