Improve aesthetic of main menu swipeout (use screen mask)
parent
fbf8e5fa14
commit
9e5940f0ab
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react'
|
import React, {useState} from 'react'
|
||||||
import {
|
import {
|
||||||
Animated,
|
Animated,
|
||||||
GestureResponderEvent,
|
GestureResponderEvent,
|
||||||
|
@ -19,6 +19,7 @@ interface Props {
|
||||||
distThresholdDivisor?: number
|
distThresholdDivisor?: number
|
||||||
useNativeDriver?: boolean
|
useNativeDriver?: boolean
|
||||||
onSwipeStart?: () => void
|
onSwipeStart?: () => void
|
||||||
|
onSwipeStartDirection?: (dx: number) => void
|
||||||
onSwipeEnd?: (dx: number) => void
|
onSwipeEnd?: (dx: number) => void
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}
|
}
|
||||||
|
@ -32,10 +33,12 @@ export function HorzSwipe({
|
||||||
distThresholdDivisor = 1.75,
|
distThresholdDivisor = 1.75,
|
||||||
useNativeDriver = false,
|
useNativeDriver = false,
|
||||||
onSwipeStart,
|
onSwipeStart,
|
||||||
|
onSwipeStartDirection,
|
||||||
onSwipeEnd,
|
onSwipeEnd,
|
||||||
children,
|
children,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const winDim = useWindowDimensions()
|
const winDim = useWindowDimensions()
|
||||||
|
const [dir, setDir] = useState<number>(0)
|
||||||
|
|
||||||
const swipeVelocityThreshold = 35
|
const swipeVelocityThreshold = 35
|
||||||
const swipeDistanceThreshold = winDim.width / distThresholdDivisor
|
const swipeDistanceThreshold = winDim.width / distThresholdDivisor
|
||||||
|
@ -66,6 +69,7 @@ export function HorzSwipe({
|
||||||
}
|
}
|
||||||
|
|
||||||
const startGesture = () => {
|
const startGesture = () => {
|
||||||
|
setDir(0)
|
||||||
onSwipeStart?.()
|
onSwipeStart?.()
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -94,6 +98,12 @@ export function HorzSwipe({
|
||||||
}
|
}
|
||||||
|
|
||||||
panX.setValue(clamp(diffX / swipeDistanceThreshold, -1, 1) * -1)
|
panX.setValue(clamp(diffX / swipeDistanceThreshold, -1, 1) * -1)
|
||||||
|
|
||||||
|
const newDir = diffX > 0 ? -1 : diffX < 0 ? 1 : 0
|
||||||
|
if (newDir !== dir) {
|
||||||
|
setDir(newDir)
|
||||||
|
onSwipeStartDirection?.(newDir)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const finishGesture = (
|
const finishGesture = (
|
||||||
|
|
|
@ -113,6 +113,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
const [isTabsSelectorActive, setTabsSelectorActive] = useState(false)
|
const [isTabsSelectorActive, setTabsSelectorActive] = useState(false)
|
||||||
const scrollElRef = useRef<FlatList | undefined>()
|
const scrollElRef = useRef<FlatList | undefined>()
|
||||||
const winDim = useWindowDimensions()
|
const winDim = useWindowDimensions()
|
||||||
|
const [menuSwipingDirection, setMenuSwipingDirection] = useState(0)
|
||||||
const swipeGestureInterp = useAnimatedValue(0)
|
const swipeGestureInterp = useAnimatedValue(0)
|
||||||
const tabMenuInterp = useAnimatedValue(0)
|
const tabMenuInterp = useAnimatedValue(0)
|
||||||
const newTabInterp = useAnimatedValue(0)
|
const newTabInterp = useAnimatedValue(0)
|
||||||
|
@ -213,6 +214,15 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
const isMenuActive = store.shell.isMainMenuOpen
|
const isMenuActive = store.shell.isMainMenuOpen
|
||||||
const canSwipeLeft = store.nav.tab.canGoBack || !isMenuActive
|
const canSwipeLeft = store.nav.tab.canGoBack || !isMenuActive
|
||||||
const canSwipeRight = isMenuActive
|
const canSwipeRight = isMenuActive
|
||||||
|
const onNavSwipeStartDirection = (dx: number) => {
|
||||||
|
if (dx < 0 && !store.nav.tab.canGoBack) {
|
||||||
|
setMenuSwipingDirection(dx)
|
||||||
|
} else if (dx > 0 && isMenuActive) {
|
||||||
|
setMenuSwipingDirection(dx)
|
||||||
|
} else {
|
||||||
|
setMenuSwipingDirection(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
const onNavSwipeEnd = (dx: number) => {
|
const onNavSwipeEnd = (dx: number) => {
|
||||||
if (dx < 0) {
|
if (dx < 0) {
|
||||||
if (store.nav.tab.canGoBack) {
|
if (store.nav.tab.canGoBack) {
|
||||||
|
@ -225,6 +235,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
store.shell.setMainMenuOpen(false)
|
store.shell.setMainMenuOpen(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setMenuSwipingDirection(0)
|
||||||
}
|
}
|
||||||
const swipeTranslateX = Animated.multiply(
|
const swipeTranslateX = Animated.multiply(
|
||||||
swipeGestureInterp,
|
swipeGestureInterp,
|
||||||
|
@ -256,6 +267,15 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
outputRange: [0, 0.6, 0],
|
outputRange: [0, 0.6, 0],
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
const menuSwipeOpacity =
|
||||||
|
menuSwipingDirection !== 0
|
||||||
|
? {
|
||||||
|
opacity: swipeGestureInterp.interpolate({
|
||||||
|
inputRange: menuSwipingDirection > 0 ? [0, 1] : [-1, 0],
|
||||||
|
outputRange: [0.6, 0],
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
// TODO
|
// TODO
|
||||||
// const tabMenuTransform = {
|
// const tabMenuTransform = {
|
||||||
// transform: [{translateY: Animated.multiply(tabMenuInterp, -320)}],
|
// transform: [{translateY: Animated.multiply(tabMenuInterp, -320)}],
|
||||||
|
@ -301,6 +321,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
swipeEnabled
|
swipeEnabled
|
||||||
canSwipeLeft={canSwipeLeft}
|
canSwipeLeft={canSwipeLeft}
|
||||||
canSwipeRight={canSwipeRight}
|
canSwipeRight={canSwipeRight}
|
||||||
|
onSwipeStartDirection={onNavSwipeStartDirection}
|
||||||
onSwipeEnd={onNavSwipeEnd}>
|
onSwipeEnd={onNavSwipeEnd}>
|
||||||
<ScreenContainer style={styles.screenContainer}>
|
<ScreenContainer style={styles.screenContainer}>
|
||||||
{screenRenderDesc.screens.map(
|
{screenRenderDesc.screens.map(
|
||||||
|
@ -348,6 +369,9 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
</ScreenContainer>
|
</ScreenContainer>
|
||||||
|
{menuSwipingDirection !== 0 ? (
|
||||||
|
<Animated.View style={[styles.screenMask, menuSwipeOpacity]} />
|
||||||
|
) : undefined}
|
||||||
<Animated.View style={[styles.menuDrawer, menuSwipeTransform]}>
|
<Animated.View style={[styles.menuDrawer, menuSwipeTransform]}>
|
||||||
<Menu
|
<Menu
|
||||||
visible={isMenuActive}
|
visible={isMenuActive}
|
||||||
|
@ -484,10 +508,6 @@ const styles = StyleSheet.create({
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
borderTopWidth: 1,
|
|
||||||
borderTopColor: colors.gray2,
|
|
||||||
borderRightWidth: 1,
|
|
||||||
borderRightColor: colors.gray2,
|
|
||||||
},
|
},
|
||||||
topBarProtector: {
|
topBarProtector: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
|
Loading…
Reference in New Issue