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 { PanResponder, SafeAreaView, ScrollView, View } from 'react-native';
|
||||
import { SafeAreaView, ScrollView, View } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../color-scheme';
|
||||
import { SlidingView } from '../../../react';
|
||||
import { connect } from '../../../redux';
|
||||
import { StyleType } 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
@ -51,11 +26,6 @@ type Props = {
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
@ -81,8 +51,6 @@ type Props = {
|
|||
* A component emulating Android's BottomSheet.
|
||||
*/
|
||||
class BottomSheet extends PureComponent<Props> {
|
||||
panResponder: Object;
|
||||
|
||||
/**
|
||||
* Default values for {@code BottomSheet} component's properties.
|
||||
*
|
||||
|
@ -93,21 +61,6 @@ class BottomSheet extends PureComponent<Props> {
|
|||
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()}.
|
||||
*
|
||||
|
@ -116,8 +69,6 @@ class BottomSheet extends PureComponent<Props> {
|
|||
*/
|
||||
render() {
|
||||
const {
|
||||
_height,
|
||||
_styles,
|
||||
addScrollViewPadding,
|
||||
renderHeader,
|
||||
renderFooter,
|
||||
|
@ -143,20 +94,16 @@ class BottomSheet extends PureComponent<Props> {
|
|||
style = { [
|
||||
styles.sheetItemContainer,
|
||||
renderHeader
|
||||
? _styles.sheetHeader
|
||||
: _styles.sheet,
|
||||
renderFooter && _styles.sheetFooter,
|
||||
style,
|
||||
{
|
||||
maxHeight: _height - 100
|
||||
}
|
||||
] }
|
||||
{ ...this.panResponder.panHandlers }>
|
||||
? styles.sheetHeader
|
||||
: styles.sheet,
|
||||
renderFooter && styles.sheetFooter,
|
||||
style
|
||||
] }>
|
||||
<ScrollView
|
||||
bounces = { false }
|
||||
showsVerticalScrollIndicator = { false }
|
||||
style = { [
|
||||
renderFooter && _styles.sheet,
|
||||
renderFooter && styles.sheet,
|
||||
addScrollViewPadding && styles.scrollView
|
||||
] } >
|
||||
{ this.props.children }
|
||||
|
@ -167,63 +114,6 @@ class BottomSheet extends PureComponent<Props> {
|
|||
</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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
export default BottomSheet;
|
||||
|
|
|
@ -20,85 +20,6 @@ export const MD_FONT_SIZE = 16;
|
|||
export const MD_ITEM_HEIGHT = 48;
|
||||
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.
|
||||
*/
|
||||
|
@ -136,12 +57,40 @@ export const inputDialog = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Default styles for the items of a {@code BottomSheet}-based menu.
|
||||
*
|
||||
* These have been implemented as per the Material Design guidelines:
|
||||
* 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}.
|
||||
*/
|
||||
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: {
|
||||
/**
|
||||
* Style for the {@code Icon} element in a generic item of the menu.
|
||||
|
@ -194,7 +143,53 @@ ColorSchemeRegistry.register('BottomSheet', {
|
|||
sheetFooter: {
|
||||
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.
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
import React, { PureComponent } from 'react';
|
||||
import { Divider } from 'react-native-paper';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
|
||||
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { StyleType } from '../../../base/styles';
|
||||
import { SharedDocumentButton } from '../../../etherpad';
|
||||
import { ParticipantsPaneButton } from '../../../participants-pane/components/native';
|
||||
import { ReactionMenu } from '../../../reactions/components';
|
||||
|
@ -35,11 +34,6 @@ import ToggleSelfViewButton from './ToggleSelfViewButton';
|
|||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the dialog feature.
|
||||
*/
|
||||
_bottomSheetStyles: StyleType,
|
||||
|
||||
/**
|
||||
* True if the overflow menu is currently visible, false otherwise.
|
||||
*/
|
||||
|
@ -118,7 +112,6 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
*/
|
||||
render() {
|
||||
const {
|
||||
_bottomSheetStyles,
|
||||
_reactionsEnabled,
|
||||
_selfViewHidden,
|
||||
_width
|
||||
|
@ -128,16 +121,16 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
const buttonProps = {
|
||||
afterClick: this._onCancel,
|
||||
showLabel: true,
|
||||
styles: _bottomSheetStyles.buttons
|
||||
styles: bottomSheetStyles.buttons
|
||||
};
|
||||
|
||||
const topButtonProps = {
|
||||
afterClick: this._onCancel,
|
||||
showLabel: true,
|
||||
styles: {
|
||||
..._bottomSheetStyles.buttons,
|
||||
...bottomSheetStyles.buttons,
|
||||
style: {
|
||||
..._bottomSheetStyles.buttons.style,
|
||||
...bottomSheetStyles.buttons.style,
|
||||
borderTopLeftRadius: 16,
|
||||
borderTopRightRadius: 16
|
||||
}
|
||||
|
@ -217,7 +210,6 @@ function _mapStateToProps(state) {
|
|||
const { disableSelfView } = state['features/base/settings'];
|
||||
|
||||
return {
|
||||
_bottomSheetStyles: ColorSchemeRegistry.get(state, 'BottomSheet'),
|
||||
_isOpen: isDialogOpen(state, OverflowMenu_),
|
||||
_reactionsEnabled: isReactionsEnabled(state),
|
||||
_selfViewHidden: Boolean(disableSelfView),
|
||||
|
|
Loading…
Reference in New Issue