fix(rn,bottom-sheet) fix scroll
In the past we used a PanResponder to detect user gestures in the sheet to show a reduced version or a full-height version of it, and also to close it. There is an obvious conflic between the gestures and scrolling, which didn't work all that great, but we could live with it. After reactions were introduced we no longer rendered the 2 different heights, so that functionaligy stopped being used but the PanResponder still remained there. This commit removes it completely and sets a max height of 75% on any BottomSheet, so any tap outside will close it.
This commit is contained in:
parent
98ef0e74d6
commit
ad8cdcd81b
|
@ -1,40 +1,15 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { PureComponent, type Node } from 'react';
|
import React, { PureComponent, type Node } from 'react';
|
||||||
import { PanResponder, SafeAreaView, ScrollView, View } from 'react-native';
|
import { SafeAreaView, ScrollView, View } from 'react-native';
|
||||||
|
|
||||||
import { ColorSchemeRegistry } from '../../../color-scheme';
|
|
||||||
import { SlidingView } from '../../../react';
|
import { SlidingView } from '../../../react';
|
||||||
import { connect } from '../../../redux';
|
|
||||||
import { StyleType } from '../../../styles';
|
|
||||||
|
|
||||||
import { bottomSheetStyles as styles } from './styles';
|
import { bottomSheetStyles as styles } from './styles';
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimal distance that needs to be moved by the finger to consider it a swipe.
|
|
||||||
*/
|
|
||||||
const GESTURE_DISTANCE_THRESHOLD = 5;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The minimal speed needed to be achieved by the finger to consider it as a swipe.
|
|
||||||
*/
|
|
||||||
const GESTURE_SPEED_THRESHOLD = 0.2;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of {@code BottomSheet}'s React {@code Component} prop types.
|
* The type of {@code BottomSheet}'s React {@code Component} prop types.
|
||||||
*/
|
*/
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
/**
|
|
||||||
* The height of the screen.
|
|
||||||
*/
|
|
||||||
_height: number,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The color-schemed stylesheet of the feature.
|
|
||||||
*/
|
|
||||||
_styles: StyleType,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to add padding to scroll view.
|
* Whether to add padding to scroll view.
|
||||||
*/
|
*/
|
||||||
|
@ -51,11 +26,6 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
onCancel: ?Function,
|
onCancel: ?Function,
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback to be attached to the custom swipe event of the BottomSheet.
|
|
||||||
*/
|
|
||||||
onSwipe?: Function,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to render a bottom sheet header element, if necessary.
|
* Function to render a bottom sheet header element, if necessary.
|
||||||
*/
|
*/
|
||||||
|
@ -81,8 +51,6 @@ type Props = {
|
||||||
* A component emulating Android's BottomSheet.
|
* A component emulating Android's BottomSheet.
|
||||||
*/
|
*/
|
||||||
class BottomSheet extends PureComponent<Props> {
|
class BottomSheet extends PureComponent<Props> {
|
||||||
panResponder: Object;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default values for {@code BottomSheet} component's properties.
|
* Default values for {@code BottomSheet} component's properties.
|
||||||
*
|
*
|
||||||
|
@ -93,21 +61,6 @@ class BottomSheet extends PureComponent<Props> {
|
||||||
showSlidingView: true
|
showSlidingView: true
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates a new component.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.panResponder = PanResponder.create({
|
|
||||||
onStartShouldSetPanResponder: this._onShouldSetResponder.bind(this),
|
|
||||||
onMoveShouldSetPanResponder: this._onShouldSetResponder.bind(this),
|
|
||||||
onPanResponderRelease: this._onGestureEnd.bind(this)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements React's {@link Component#render()}.
|
* Implements React's {@link Component#render()}.
|
||||||
*
|
*
|
||||||
|
@ -116,8 +69,6 @@ class BottomSheet extends PureComponent<Props> {
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
_height,
|
|
||||||
_styles,
|
|
||||||
addScrollViewPadding,
|
addScrollViewPadding,
|
||||||
renderHeader,
|
renderHeader,
|
||||||
renderFooter,
|
renderFooter,
|
||||||
|
@ -143,20 +94,16 @@ class BottomSheet extends PureComponent<Props> {
|
||||||
style = { [
|
style = { [
|
||||||
styles.sheetItemContainer,
|
styles.sheetItemContainer,
|
||||||
renderHeader
|
renderHeader
|
||||||
? _styles.sheetHeader
|
? styles.sheetHeader
|
||||||
: _styles.sheet,
|
: styles.sheet,
|
||||||
renderFooter && _styles.sheetFooter,
|
renderFooter && styles.sheetFooter,
|
||||||
style,
|
style
|
||||||
{
|
] }>
|
||||||
maxHeight: _height - 100
|
|
||||||
}
|
|
||||||
] }
|
|
||||||
{ ...this.panResponder.panHandlers }>
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
bounces = { false }
|
bounces = { false }
|
||||||
showsVerticalScrollIndicator = { false }
|
showsVerticalScrollIndicator = { false }
|
||||||
style = { [
|
style = { [
|
||||||
renderFooter && _styles.sheet,
|
renderFooter && styles.sheet,
|
||||||
addScrollViewPadding && styles.scrollView
|
addScrollViewPadding && styles.scrollView
|
||||||
] } >
|
] } >
|
||||||
{ this.props.children }
|
{ this.props.children }
|
||||||
|
@ -167,63 +114,6 @@ class BottomSheet extends PureComponent<Props> {
|
||||||
</SlidingView>
|
</SlidingView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback to handle a gesture end event.
|
|
||||||
*
|
|
||||||
* @param {Object} evt - The native gesture event.
|
|
||||||
* @param {Object} gestureState - The gesture state.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_onGestureEnd(evt, gestureState) {
|
|
||||||
const verticalSwipe = Math.abs(gestureState.vy) > Math.abs(gestureState.vx)
|
|
||||||
&& Math.abs(gestureState.vy) > GESTURE_SPEED_THRESHOLD;
|
|
||||||
|
|
||||||
if (verticalSwipe) {
|
|
||||||
const direction = gestureState.vy > 0 ? 'down' : 'up';
|
|
||||||
const { onCancel, onSwipe } = this.props;
|
|
||||||
let isSwipeHandled = false;
|
|
||||||
|
|
||||||
if (onSwipe) {
|
|
||||||
isSwipeHandled = onSwipe(direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (direction === 'down' && !isSwipeHandled) {
|
|
||||||
// Swipe down is a special gesture that can be used to close the
|
|
||||||
// BottomSheet, so if the swipe is not handled by the parent
|
|
||||||
// component, we consider it as a request to close.
|
|
||||||
onCancel && onCancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the pan responder should activate, false otherwise.
|
|
||||||
*
|
|
||||||
* @param {Object} evt - The native gesture event.
|
|
||||||
* @param {Object} gestureState - The gesture state.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
_onShouldSetResponder({ nativeEvent }, gestureState) {
|
|
||||||
return nativeEvent.touches.length === 1
|
|
||||||
&& Math.abs(gestureState.dx) > GESTURE_DISTANCE_THRESHOLD
|
|
||||||
&& Math.abs(gestureState.dy) > GESTURE_DISTANCE_THRESHOLD;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export default BottomSheet;
|
||||||
* Maps part of the Redux state to the props of this component.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The Redux state.
|
|
||||||
* @returns {{
|
|
||||||
* _styles: StyleType
|
|
||||||
* }}
|
|
||||||
*/
|
|
||||||
function _mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
_styles: ColorSchemeRegistry.get(state, 'BottomSheet'),
|
|
||||||
_height: state['features/base/responsive-ui'].clientHeight
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(_mapStateToProps)(BottomSheet);
|
|
||||||
|
|
|
@ -20,85 +20,6 @@ export const MD_FONT_SIZE = 16;
|
||||||
export const MD_ITEM_HEIGHT = 48;
|
export const MD_ITEM_HEIGHT = 48;
|
||||||
export const MD_ITEM_MARGIN_PADDING = 16;
|
export const MD_ITEM_MARGIN_PADDING = 16;
|
||||||
|
|
||||||
/**
|
|
||||||
* The React {@code Component} styles of {@code BottomSheet}. These have
|
|
||||||
* been implemented as per the Material Design guidelines:
|
|
||||||
* {@link https://material.io/guidelines/components/bottom-sheets.html}.
|
|
||||||
*/
|
|
||||||
export const bottomSheetStyles = {
|
|
||||||
sheetAreaCover: {
|
|
||||||
backgroundColor: ColorPalette.transparent,
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
|
|
||||||
scrollView: {
|
|
||||||
paddingHorizontal: 0
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Style for the container of the sheet.
|
|
||||||
*/
|
|
||||||
sheetContainer: {
|
|
||||||
alignItems: 'stretch',
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'flex-end',
|
|
||||||
maxWidth: 500,
|
|
||||||
marginLeft: 'auto',
|
|
||||||
marginRight: 'auto',
|
|
||||||
width: '100%'
|
|
||||||
},
|
|
||||||
|
|
||||||
sheetItemContainer: {
|
|
||||||
flex: -1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
dialogButton: {
|
|
||||||
...BaseTheme.typography.labelButton
|
|
||||||
},
|
|
||||||
|
|
||||||
destructiveDialogButton: {
|
|
||||||
...BaseTheme.typography.labelButton,
|
|
||||||
color: BaseTheme.palette.actionDanger
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const brandedDialog = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The style of bold {@code Text} rendered by the {@code Dialog}s of the
|
|
||||||
* feature authentication.
|
|
||||||
*/
|
|
||||||
boldDialogText: {
|
|
||||||
fontWeight: 'bold'
|
|
||||||
},
|
|
||||||
|
|
||||||
buttonFarRight: {
|
|
||||||
borderBottomRightRadius: BORDER_RADIUS
|
|
||||||
},
|
|
||||||
|
|
||||||
buttonWrapper: {
|
|
||||||
alignItems: 'stretch',
|
|
||||||
borderRadius: BORDER_RADIUS,
|
|
||||||
flexDirection: 'row'
|
|
||||||
},
|
|
||||||
|
|
||||||
mainWrapper: {
|
|
||||||
alignSelf: 'stretch',
|
|
||||||
padding: BoxModel.padding * 2,
|
|
||||||
|
|
||||||
// The added bottom padding is to compensate the empty space around the
|
|
||||||
// close icon.
|
|
||||||
paddingBottom: BoxModel.padding * 3
|
|
||||||
},
|
|
||||||
|
|
||||||
overlayTouchable: {
|
|
||||||
...StyleSheet.absoluteFillObject
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reusable (colored) style for text in any branded dialogs.
|
* Reusable (colored) style for text in any branded dialogs.
|
||||||
*/
|
*/
|
||||||
|
@ -136,12 +57,40 @@ export const inputDialog = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default styles for the items of a {@code BottomSheet}-based menu.
|
* The React {@code Component} styles of {@code BottomSheet}. These have
|
||||||
*
|
* been implemented as per the Material Design guidelines:
|
||||||
* These have been implemented as per the Material Design guidelines:
|
|
||||||
* {@link https://material.io/guidelines/components/bottom-sheets.html}.
|
* {@link https://material.io/guidelines/components/bottom-sheets.html}.
|
||||||
*/
|
*/
|
||||||
ColorSchemeRegistry.register('BottomSheet', {
|
export const bottomSheetStyles = {
|
||||||
|
sheetAreaCover: {
|
||||||
|
backgroundColor: ColorPalette.transparent,
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
|
||||||
|
scrollView: {
|
||||||
|
paddingHorizontal: 0
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style for the container of the sheet.
|
||||||
|
*/
|
||||||
|
sheetContainer: {
|
||||||
|
borderColor: 'red',
|
||||||
|
alignItems: 'stretch',
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
maxWidth: 500,
|
||||||
|
marginLeft: 'auto',
|
||||||
|
marginRight: 'auto',
|
||||||
|
width: '100%'
|
||||||
|
},
|
||||||
|
|
||||||
|
sheetItemContainer: {
|
||||||
|
flex: -1,
|
||||||
|
maxHeight: '75%'
|
||||||
|
},
|
||||||
|
|
||||||
buttons: {
|
buttons: {
|
||||||
/**
|
/**
|
||||||
* Style for the {@code Icon} element in a generic item of the menu.
|
* Style for the {@code Icon} element in a generic item of the menu.
|
||||||
|
@ -194,7 +143,53 @@ ColorSchemeRegistry.register('BottomSheet', {
|
||||||
sheetFooter: {
|
sheetFooter: {
|
||||||
backgroundColor: BaseTheme.palette.bottomSheet
|
backgroundColor: BaseTheme.palette.bottomSheet
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
dialogButton: {
|
||||||
|
...BaseTheme.typography.labelButton
|
||||||
|
},
|
||||||
|
|
||||||
|
destructiveDialogButton: {
|
||||||
|
...BaseTheme.typography.labelButton,
|
||||||
|
color: BaseTheme.palette.actionDanger
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const brandedDialog = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The style of bold {@code Text} rendered by the {@code Dialog}s of the
|
||||||
|
* feature authentication.
|
||||||
|
*/
|
||||||
|
boldDialogText: {
|
||||||
|
fontWeight: 'bold'
|
||||||
|
},
|
||||||
|
|
||||||
|
buttonFarRight: {
|
||||||
|
borderBottomRightRadius: BORDER_RADIUS
|
||||||
|
},
|
||||||
|
|
||||||
|
buttonWrapper: {
|
||||||
|
alignItems: 'stretch',
|
||||||
|
borderRadius: BORDER_RADIUS,
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
|
||||||
|
mainWrapper: {
|
||||||
|
alignSelf: 'stretch',
|
||||||
|
padding: BoxModel.padding * 2,
|
||||||
|
|
||||||
|
// The added bottom padding is to compensate the empty space around the
|
||||||
|
// close icon.
|
||||||
|
paddingBottom: BoxModel.padding * 3
|
||||||
|
},
|
||||||
|
|
||||||
|
overlayTouchable: {
|
||||||
|
...StyleSheet.absoluteFillObject
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Color schemed styles for all the component based on the abstract dialog.
|
* Color schemed styles for all the component based on the abstract dialog.
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { Divider } from 'react-native-paper';
|
import { Divider } from 'react-native-paper';
|
||||||
|
|
||||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
|
||||||
import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
|
import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
|
||||||
|
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
import { StyleType } from '../../../base/styles';
|
|
||||||
import { SharedDocumentButton } from '../../../etherpad';
|
import { SharedDocumentButton } from '../../../etherpad';
|
||||||
import { ParticipantsPaneButton } from '../../../participants-pane/components/native';
|
import { ParticipantsPaneButton } from '../../../participants-pane/components/native';
|
||||||
import { ReactionMenu } from '../../../reactions/components';
|
import { ReactionMenu } from '../../../reactions/components';
|
||||||
|
@ -35,11 +34,6 @@ import ToggleSelfViewButton from './ToggleSelfViewButton';
|
||||||
*/
|
*/
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
/**
|
|
||||||
* The color-schemed stylesheet of the dialog feature.
|
|
||||||
*/
|
|
||||||
_bottomSheetStyles: StyleType,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the overflow menu is currently visible, false otherwise.
|
* True if the overflow menu is currently visible, false otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -118,7 +112,6 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
_bottomSheetStyles,
|
|
||||||
_reactionsEnabled,
|
_reactionsEnabled,
|
||||||
_selfViewHidden,
|
_selfViewHidden,
|
||||||
_width
|
_width
|
||||||
|
@ -128,16 +121,16 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||||
const buttonProps = {
|
const buttonProps = {
|
||||||
afterClick: this._onCancel,
|
afterClick: this._onCancel,
|
||||||
showLabel: true,
|
showLabel: true,
|
||||||
styles: _bottomSheetStyles.buttons
|
styles: bottomSheetStyles.buttons
|
||||||
};
|
};
|
||||||
|
|
||||||
const topButtonProps = {
|
const topButtonProps = {
|
||||||
afterClick: this._onCancel,
|
afterClick: this._onCancel,
|
||||||
showLabel: true,
|
showLabel: true,
|
||||||
styles: {
|
styles: {
|
||||||
..._bottomSheetStyles.buttons,
|
...bottomSheetStyles.buttons,
|
||||||
style: {
|
style: {
|
||||||
..._bottomSheetStyles.buttons.style,
|
...bottomSheetStyles.buttons.style,
|
||||||
borderTopLeftRadius: 16,
|
borderTopLeftRadius: 16,
|
||||||
borderTopRightRadius: 16
|
borderTopRightRadius: 16
|
||||||
}
|
}
|
||||||
|
@ -217,7 +210,6 @@ function _mapStateToProps(state) {
|
||||||
const { disableSelfView } = state['features/base/settings'];
|
const { disableSelfView } = state['features/base/settings'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_bottomSheetStyles: ColorSchemeRegistry.get(state, 'BottomSheet'),
|
|
||||||
_isOpen: isDialogOpen(state, OverflowMenu_),
|
_isOpen: isDialogOpen(state, OverflowMenu_),
|
||||||
_reactionsEnabled: isReactionsEnabled(state),
|
_reactionsEnabled: isReactionsEnabled(state),
|
||||||
_selfViewHidden: Boolean(disableSelfView),
|
_selfViewHidden: Boolean(disableSelfView),
|
||||||
|
|
Loading…
Reference in New Issue