mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-11 18:24:43 +02:00
Mobile: Dismiss dialogs on background tap (#10557)
This commit is contained in:
parent
97d15bb26a
commit
80aeff6ecd
@ -29,8 +29,8 @@ const useStyles = (themeId: number, containerStyle: ViewStyle, size: DialogSize)
|
||||
return useMemo(() => {
|
||||
const theme = themeStyle(themeId);
|
||||
|
||||
const maxWidth = size === DialogSize.Large ? Infinity : 500;
|
||||
const maxHeight = size === DialogSize.Large ? Infinity : 700;
|
||||
const maxWidth = size === DialogSize.Large ? windowSize.width : 500;
|
||||
const maxHeight = size === DialogSize.Large ? windowSize.height : 700;
|
||||
|
||||
return StyleSheet.create({
|
||||
webView: {
|
||||
@ -45,29 +45,27 @@ const useStyles = (themeId: number, containerStyle: ViewStyle, size: DialogSize)
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
dialog: {
|
||||
backgroundColor: theme.backgroundColor,
|
||||
borderRadius: 12,
|
||||
padding: 10,
|
||||
|
||||
// Use Math.min with width and height -- the maxWidth and maxHeight style
|
||||
// properties don't seem to limit the size for this.
|
||||
height: Math.min(maxHeight, windowSize.height * 0.9),
|
||||
width: Math.min(maxWidth, windowSize.width * 0.97),
|
||||
dialogContainer: {
|
||||
maxHeight,
|
||||
maxWidth,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
flexShrink: 1,
|
||||
|
||||
// Center
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
paddingLeft: 6,
|
||||
paddingRight: 6,
|
||||
|
||||
...containerStyle,
|
||||
},
|
||||
dialogContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexGrow: 1,
|
||||
dialogSurface: {
|
||||
borderRadius: 12,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
padding: 10,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
});
|
||||
}, [themeId, windowSize.width, windowSize.height, containerStyle, size]);
|
||||
@ -96,7 +94,7 @@ const DismissibleDialog: React.FC<Props> = props => {
|
||||
backgroundColor='rgba(0, 0, 0, 0.1)'
|
||||
transparent={true}
|
||||
>
|
||||
<Surface style={styles.dialog} elevation={1}>
|
||||
<Surface style={styles.dialogSurface} elevation={1}>
|
||||
{closeButton}
|
||||
{props.children}
|
||||
</Surface>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { Modal, ModalProps, StyleSheet, View, ViewStyle, useWindowDimensions } from 'react-native';
|
||||
import { RefObject, useCallback, useMemo, useRef } from 'react';
|
||||
import { GestureResponderEvent, Modal, ModalProps, StyleSheet, View, ViewStyle, useWindowDimensions } from 'react-native';
|
||||
import { hasNotch } from 'react-native-device-info';
|
||||
|
||||
interface ModalElementProps extends ModalProps {
|
||||
@ -13,21 +13,39 @@ const useStyles = (backgroundColor?: string) => {
|
||||
const { width: windowWidth, height: windowHeight } = useWindowDimensions();
|
||||
const isLandscape = windowWidth > windowHeight;
|
||||
return useMemo(() => {
|
||||
return StyleSheet.create({
|
||||
contentWrapper: isLandscape ? {
|
||||
marginRight: hasNotch() ? 60 : 0,
|
||||
marginLeft: hasNotch() ? 60 : 0,
|
||||
marginTop: 15,
|
||||
marginBottom: 15,
|
||||
const backgroundPadding: ViewStyle = isLandscape ? {
|
||||
paddingRight: hasNotch() ? 60 : 0,
|
||||
paddingLeft: hasNotch() ? 60 : 0,
|
||||
paddingTop: 15,
|
||||
paddingBottom: 15,
|
||||
} : {
|
||||
marginTop: hasNotch() ? 65 : 15,
|
||||
marginBottom: hasNotch() ? 35 : 15,
|
||||
paddingTop: hasNotch() ? 65 : 15,
|
||||
paddingBottom: hasNotch() ? 35 : 15,
|
||||
};
|
||||
return StyleSheet.create({
|
||||
modalBackground: {
|
||||
...backgroundPadding,
|
||||
backgroundColor,
|
||||
flexGrow: 1,
|
||||
},
|
||||
modalBackground: { backgroundColor, flexGrow: 1 },
|
||||
});
|
||||
}, [isLandscape, backgroundColor]);
|
||||
};
|
||||
|
||||
const useBackgroundTouchListeners = (onRequestClose: (event: GestureResponderEvent)=> void, backdropRef: RefObject<View>) => {
|
||||
const onShouldBackgroundCaptureTouch = useCallback((event: GestureResponderEvent) => {
|
||||
return event.target === backdropRef.current && event.nativeEvent.touches.length === 1;
|
||||
}, [backdropRef]);
|
||||
|
||||
const onBackgroundTouchFinished = useCallback((event: GestureResponderEvent) => {
|
||||
if (event.target === backdropRef.current) {
|
||||
onRequestClose?.(event);
|
||||
}
|
||||
}, [onRequestClose, backdropRef]);
|
||||
|
||||
return { onShouldBackgroundCaptureTouch, onBackgroundTouchFinished };
|
||||
};
|
||||
|
||||
const ModalElement: React.FC<ModalElementProps> = ({
|
||||
children,
|
||||
containerStyle,
|
||||
@ -39,18 +57,26 @@ const ModalElement: React.FC<ModalElementProps> = ({
|
||||
// contentWrapper adds padding. To allow styling the region outside of the modal
|
||||
// (e.g. to add a background), the content is wrapped twice.
|
||||
const content = (
|
||||
<View style={[styles.contentWrapper, containerStyle]}>
|
||||
<View style={containerStyle}>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
|
||||
const backgroundRef = useRef<View>();
|
||||
const { onShouldBackgroundCaptureTouch, onBackgroundTouchFinished } = useBackgroundTouchListeners(modalProps.onRequestClose, backgroundRef);
|
||||
|
||||
// supportedOrientations: On iOS, this allows the dialog to be shown in non-portrait orientations.
|
||||
return (
|
||||
<Modal
|
||||
supportedOrientations={['portrait', 'portrait-upside-down', 'landscape', 'landscape-left', 'landscape-right']}
|
||||
{...modalProps}
|
||||
>
|
||||
<View style={styles.modalBackground}>{content}</View>
|
||||
<View
|
||||
ref={backgroundRef}
|
||||
style={styles.modalBackground}
|
||||
onStartShouldSetResponder={onShouldBackgroundCaptureTouch}
|
||||
onResponderRelease={onBackgroundTouchFinished}
|
||||
>{content}</View>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user