From e50fa1d85bec0ca5898f0d6b044dae2dcb090b7c Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Wed, 13 May 2020 10:12:53 -0400 Subject: [PATCH] MM-24973 Prevent search input to take full screen on Android landscape (#4283) --- app/components/search_bar/index.js | 454 +++++++++++++++++++++++- app/components/search_bar/search_bar.js | 453 ----------------------- 2 files changed, 452 insertions(+), 455 deletions(-) delete mode 100644 app/components/search_bar/search_bar.js diff --git a/app/components/search_bar/index.js b/app/components/search_bar/index.js index 5e646b1ca..f9876a153 100644 --- a/app/components/search_bar/index.js +++ b/app/components/search_bar/index.js @@ -1,4 +1,454 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import SearchBar from './search_bar'; -export default SearchBar; + +import React, {PureComponent} from 'react'; +import PropTypes from 'prop-types'; +import { + Animated, + InteractionManager, + Keyboard, + TouchableWithoutFeedback, + StyleSheet, + View, + Platform, +} from 'react-native'; +import {intlShape} from 'react-intl'; + +import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; +import EvilIcon from 'react-native-vector-icons/EvilIcons'; + +import {SearchBar} from 'react-native-elements'; + +import {memoizeResult} from '@mm-redux/utils/helpers'; + +import CustomPropTypes from 'app/constants/custom_prop_types'; + +export default class Search extends PureComponent { + static propTypes = { + onBlur: PropTypes.func, + onFocus: PropTypes.func, + onSearchButtonPress: PropTypes.func, + onChangeText: PropTypes.func, + onCancelButtonPress: PropTypes.func, + onSelectionChange: PropTypes.func, + backgroundColor: PropTypes.string, + placeholderTextColor: PropTypes.string, + titleCancelColor: PropTypes.string, + tintColorSearch: PropTypes.string, + tintColorDelete: PropTypes.string, + selectionColor: PropTypes.string, + inputStyle: CustomPropTypes.Style, + cancelButtonStyle: CustomPropTypes.Style, + autoFocus: PropTypes.bool, + placeholder: PropTypes.string, + cancelTitle: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.object, + ]), + returnKeyType: PropTypes.string, + keyboardType: PropTypes.string, + autoCapitalize: PropTypes.string, + inputHeight: PropTypes.number, + editable: PropTypes.bool, + blurOnSubmit: PropTypes.bool, + keyboardShouldPersist: PropTypes.bool, + value: PropTypes.string, + keyboardAppearance: PropTypes.string, + showArrow: PropTypes.bool, + searchBarRightMargin: PropTypes.number, + leftComponent: PropTypes.element, + searchIconSize: PropTypes.number, + backArrowSize: PropTypes.number, + deleteIconSize: PropTypes.number, + showCancel: PropTypes.bool, + containerHeight: PropTypes.number, + }; + + static contextTypes = { + intl: intlShape, + }; + + static defaultProps = { + onSelectionChange: () => true, + onBlur: () => true, + editable: true, + blurOnSubmit: false, + keyboardShouldPersist: false, + placeholderTextColor: 'grey', + value: '', + showArrow: false, + showCancel: true, + searchIconSize: 24, + backArrowSize: 24, + deleteIconSize: 20, + searchBarRightMargin: 0, + returnKeyType: 'search', + keyboardType: 'default', + containerHeight: 40, + }; + + constructor(props) { + super(props); + this.state = { + leftComponentWidth: 0, + }; + + this.leftComponentAnimated = new Animated.Value(0); + this.searchContainerAnimated = new Animated.Value(0); + } + + setSearchContainerRef = (ref) => { + this.searchContainerRef = ref; + } + + setInputKeywordRef = (ref) => { + this.inputKeywordRef = ref; + } + + blur = () => { + this.inputKeywordRef.blur(); + }; + + focus = () => { + this.inputKeywordRef.focus(); + }; + + onBlur = async () => { + if (this.props.leftComponent) { + await this.collapseAnimation(); + } + this.props.onBlur(); + }; + + onLeftComponentLayout = (event) => { + const leftComponentWidth = event.nativeEvent.layout.width; + this.setState({leftComponentWidth}); + }; + + onSearch = async () => { + if (this.props.keyboardShouldPersist === false) { + await Keyboard.dismiss(); + } + + this.props.onSearchButtonPress(this.props.value); + }; + + onChangeText = (text) => { + if (this.props.onChangeText) { + this.props.onChangeText(text); + } + }; + + onFocus = () => { + InteractionManager.runAfterInteractions(async () => { + if (this.props.leftComponent) { + await this.expandAnimation(); + } + + if (this.props.onFocus) { + this.props.onFocus(); + } + }); + }; + + onClear = () => { + this.focus(); + this.props.onChangeText('', true); + }; + + onCancel = () => { + Keyboard.dismiss(); + InteractionManager.runAfterInteractions(() => { + if (this.props.onCancelButtonPress) { + this.props.onCancelButtonPress(); + } + }); + }; + + onSelectionChange = (event) => { + this.props.onSelectionChange(event); + }; + + expandAnimation = () => { + return new Promise((resolve) => { + Animated.parallel([ + Animated.timing( + this.leftComponentAnimated, + { + toValue: 100, + duration: 200, + }, + ), + Animated.timing( + this.searchContainerAnimated, + { + toValue: this.state.leftComponentWidth * -1, + duration: 200, + }, + ), + ]).start(resolve); + }); + } + + collapseAnimation = () => { + return new Promise((resolve) => { + Animated.parallel([ + Animated.timing( + this.leftComponentAnimated, + { + toValue: 0, + duration: 200, + }, + ), + Animated.timing( + this.searchContainerAnimated, + { + toValue: 0, + duration: 200, + }, + ), + ]).start(resolve); + }); + } + + render() { + const {backgroundColor, inputHeight, inputStyle, placeholderTextColor, tintColorSearch, cancelButtonStyle, tintColorDelete, titleCancelColor, searchBarRightMargin, containerHeight} = this.props; + const searchBarStyle = getSearchBarStyle( + backgroundColor, + cancelButtonStyle, + inputHeight, + inputStyle, + placeholderTextColor, + tintColorDelete, + tintColorSearch, + titleCancelColor, + searchBarRightMargin, + containerHeight, + ); + const {intl} = this.context; + + let clearIcon = null; + let searchIcon = null; + let cancelIcon = null; + + if (Platform.OS === 'ios') { + clearIcon = { + type: 'ionicon', + name: 'ios-close-circle', + size: 17, + color: searchBarStyle.clearIconColorIos, + }; + + searchIcon = ( + + ); + } else { + searchIcon = this.props.showArrow ? + ( + + + + ) : + { + type: 'material', + size: this.props.searchIconSize, + color: searchBarStyle.searchIconColor, + name: 'search', + }; + + // Making sure the icon won't change depending on whether the input is in focus on Android devices + cancelIcon = { + type: 'material', + size: 25, + color: searchBarStyle.clearIconColorAndroid, + name: 'arrow-back', + }; + + clearIcon = { + type: 'material', + size: this.props.deleteIconSize, + color: searchBarStyle.clearIconColorAndroid, + name: 'close', + }; + } + + return ( + + {((this.props.leftComponent) ? + + {this.props.leftComponent} + : + null + )} + + + + + ); + } +} + +const getSearchBarStyle = memoizeResult(( + backgroundColor, + cancelButtonStyle, + inputHeight, + inputStyle, + placeholderTextColor, + tintColorDelete, + tintColorSearch, + titleCancelColor, + searchBarRightMargin, + containerHeight, +) => ({ + cancelButtonText: { + ...cancelButtonStyle, + color: titleCancelColor, + }, + container: { + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + height: containerHeight, + flex: 1, + }, + clearIconColorIos: tintColorDelete || styles.defaultColor.color, + clearIconColorAndroid: titleCancelColor || placeholderTextColor, + inputStyle: { + ...inputStyle, + backgroundColor: 'transparent', + height: inputHeight, + }, + inputContainer: { + backgroundColor: inputStyle.backgroundColor, + height: inputHeight, + }, + searchBarWrapper: { + marginRight: searchBarRightMargin, + height: Platform.select({ + ios: inputHeight || containerHeight - 10, + android: inputHeight, + }), + }, + searchBarContainer: { + backgroundColor, + }, + searchIcon: { + color: tintColorSearch || placeholderTextColor, + top: 10, + }, + searchIconColor: tintColorSearch || placeholderTextColor, +})); + +const styles = StyleSheet.create({ + defaultColor: { + color: 'grey', + }, + fullWidth: { + flex: 1, + }, + inputContainer: { + marginLeft: 0, + borderRadius: Platform.select({ + ios: 2, + android: 0, + }), + }, + inputMargin: { + marginLeft: 4, + paddingTop: 0, + marginTop: Platform.select({ + ios: 0, + android: 8, + }), + }, + leftIcon: { + marginLeft: 4, + }, + searchContainer: { + paddingTop: 0, + paddingBottom: 0, + marginLeft: 0, + }, + text: { + fontSize: Platform.select({ + ios: 14, + android: 15, + }), + color: '#fff', + }, +}); diff --git a/app/components/search_bar/search_bar.js b/app/components/search_bar/search_bar.js deleted file mode 100644 index 68294a69f..000000000 --- a/app/components/search_bar/search_bar.js +++ /dev/null @@ -1,453 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {PureComponent} from 'react'; -import PropTypes from 'prop-types'; -import { - Animated, - InteractionManager, - Keyboard, - TouchableWithoutFeedback, - StyleSheet, - View, - Platform, -} from 'react-native'; -import {intlShape} from 'react-intl'; - -import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; -import EvilIcon from 'react-native-vector-icons/EvilIcons'; - -import {SearchBar} from 'react-native-elements'; - -import {memoizeResult} from '@mm-redux/utils/helpers'; - -import CustomPropTypes from 'app/constants/custom_prop_types'; - -export default class Search extends PureComponent { - static propTypes = { - onBlur: PropTypes.func, - onFocus: PropTypes.func, - onSearchButtonPress: PropTypes.func, - onChangeText: PropTypes.func, - onCancelButtonPress: PropTypes.func, - onSelectionChange: PropTypes.func, - backgroundColor: PropTypes.string, - placeholderTextColor: PropTypes.string, - titleCancelColor: PropTypes.string, - tintColorSearch: PropTypes.string, - tintColorDelete: PropTypes.string, - selectionColor: PropTypes.string, - inputStyle: CustomPropTypes.Style, - cancelButtonStyle: CustomPropTypes.Style, - autoFocus: PropTypes.bool, - placeholder: PropTypes.string, - cancelTitle: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.object, - ]), - returnKeyType: PropTypes.string, - keyboardType: PropTypes.string, - autoCapitalize: PropTypes.string, - inputHeight: PropTypes.number, - editable: PropTypes.bool, - blurOnSubmit: PropTypes.bool, - keyboardShouldPersist: PropTypes.bool, - value: PropTypes.string, - keyboardAppearance: PropTypes.string, - showArrow: PropTypes.bool, - searchBarRightMargin: PropTypes.number, - leftComponent: PropTypes.element, - searchIconSize: PropTypes.number, - backArrowSize: PropTypes.number, - deleteIconSize: PropTypes.number, - showCancel: PropTypes.bool, - containerHeight: PropTypes.number, - }; - - static contextTypes = { - intl: intlShape, - }; - - static defaultProps = { - onSelectionChange: () => true, - onBlur: () => true, - editable: true, - blurOnSubmit: false, - keyboardShouldPersist: false, - placeholderTextColor: 'grey', - value: '', - showArrow: false, - showCancel: true, - searchIconSize: 24, - backArrowSize: 24, - deleteIconSize: 20, - searchBarRightMargin: 0, - returnKeyType: 'search', - keyboardType: 'default', - containerHeight: 40, - }; - - constructor(props) { - super(props); - this.state = { - leftComponentWidth: 0, - }; - - this.leftComponentAnimated = new Animated.Value(0); - this.searchContainerAnimated = new Animated.Value(0); - } - - setSearchContainerRef = (ref) => { - this.searchContainerRef = ref; - } - - setInputKeywordRef = (ref) => { - this.inputKeywordRef = ref; - } - - blur = () => { - this.inputKeywordRef.blur(); - }; - - focus = () => { - this.inputKeywordRef.focus(); - }; - - onBlur = async () => { - if (this.props.leftComponent) { - await this.collapseAnimation(); - } - this.props.onBlur(); - }; - - onLeftComponentLayout = (event) => { - const leftComponentWidth = event.nativeEvent.layout.width; - this.setState({leftComponentWidth}); - }; - - onSearch = async () => { - if (this.props.keyboardShouldPersist === false) { - await Keyboard.dismiss(); - } - - this.props.onSearchButtonPress(this.props.value); - }; - - onChangeText = (text) => { - if (this.props.onChangeText) { - this.props.onChangeText(text); - } - }; - - onFocus = () => { - InteractionManager.runAfterInteractions(async () => { - if (this.props.leftComponent) { - await this.expandAnimation(); - } - - if (this.props.onFocus) { - this.props.onFocus(); - } - }); - }; - - onClear = () => { - this.focus(); - this.props.onChangeText('', true); - }; - - onCancel = () => { - Keyboard.dismiss(); - InteractionManager.runAfterInteractions(() => { - if (this.props.onCancelButtonPress) { - this.props.onCancelButtonPress(); - } - }); - }; - - onSelectionChange = (event) => { - this.props.onSelectionChange(event); - }; - - expandAnimation = () => { - return new Promise((resolve) => { - Animated.parallel([ - Animated.timing( - this.leftComponentAnimated, - { - toValue: 100, - duration: 200, - }, - ), - Animated.timing( - this.searchContainerAnimated, - { - toValue: this.state.leftComponentWidth * -1, - duration: 200, - }, - ), - ]).start(resolve); - }); - } - - collapseAnimation = () => { - return new Promise((resolve) => { - Animated.parallel([ - Animated.timing( - this.leftComponentAnimated, - { - toValue: 0, - duration: 200, - }, - ), - Animated.timing( - this.searchContainerAnimated, - { - toValue: 0, - duration: 200, - }, - ), - ]).start(resolve); - }); - } - - render() { - const {backgroundColor, inputHeight, inputStyle, placeholderTextColor, tintColorSearch, cancelButtonStyle, tintColorDelete, titleCancelColor, searchBarRightMargin, containerHeight} = this.props; - const searchBarStyle = getSearchBarStyle( - backgroundColor, - cancelButtonStyle, - inputHeight, - inputStyle, - placeholderTextColor, - tintColorDelete, - tintColorSearch, - titleCancelColor, - searchBarRightMargin, - containerHeight, - ); - const {intl} = this.context; - - let clearIcon = null; - let searchIcon = null; - let cancelIcon = null; - - if (Platform.OS === 'ios') { - clearIcon = { - type: 'ionicon', - name: 'ios-close-circle', - size: 17, - color: searchBarStyle.clearIconColorIos, - }; - - searchIcon = ( - - ); - } else { - searchIcon = this.props.showArrow ? - ( - - - - ) : - { - type: 'material', - size: this.props.searchIconSize, - color: searchBarStyle.searchIconColor, - name: 'search', - }; - - // Making sure the icon won't change depending on whether the input is in focus on Android devices - cancelIcon = { - type: 'material', - size: 25, - color: searchBarStyle.clearIconColorAndroid, - name: 'arrow-back', - }; - - clearIcon = { - type: 'material', - size: this.props.deleteIconSize, - color: searchBarStyle.clearIconColorAndroid, - name: 'close', - }; - } - - return ( - - {((this.props.leftComponent) ? - - {this.props.leftComponent} - : - null - )} - - - - - ); - } -} - -const getSearchBarStyle = memoizeResult(( - backgroundColor, - cancelButtonStyle, - inputHeight, - inputStyle, - placeholderTextColor, - tintColorDelete, - tintColorSearch, - titleCancelColor, - searchBarRightMargin, - containerHeight, -) => ({ - cancelButtonText: { - ...cancelButtonStyle, - color: titleCancelColor, - }, - container: { - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center', - height: containerHeight, - flex: 1, - }, - clearIconColorIos: tintColorDelete || styles.defaultColor.color, - clearIconColorAndroid: titleCancelColor || placeholderTextColor, - inputStyle: { - ...inputStyle, - backgroundColor: 'transparent', - height: inputHeight, - }, - inputContainer: { - backgroundColor: inputStyle.backgroundColor, - height: inputHeight, - }, - searchBarWrapper: { - marginRight: searchBarRightMargin, - height: Platform.select({ - ios: inputHeight || containerHeight - 10, - android: inputHeight, - }), - }, - searchBarContainer: { - backgroundColor, - }, - searchIcon: { - color: tintColorSearch || placeholderTextColor, - top: 10, - }, - searchIconColor: tintColorSearch || placeholderTextColor, -})); - -const styles = StyleSheet.create({ - defaultColor: { - color: 'grey', - }, - fullWidth: { - flex: 1, - }, - inputContainer: { - marginLeft: 0, - borderRadius: Platform.select({ - ios: 2, - android: 0, - }), - }, - inputMargin: { - marginLeft: 4, - paddingTop: 0, - marginTop: Platform.select({ - ios: 0, - android: 8, - }), - }, - leftIcon: { - marginLeft: 4, - }, - searchContainer: { - paddingTop: 0, - paddingBottom: 0, - marginLeft: 0, - }, - text: { - fontSize: Platform.select({ - ios: 14, - android: 15, - }), - color: '#fff', - }, -});