Improve aesthetic of main menu swipeout (use screen mask)

zio/stable
Paul Frazee 2022-12-09 11:46:49 -06:00
parent fbf8e5fa14
commit 9e5940f0ab
2 changed files with 35 additions and 5 deletions

View File

@ -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 = (

View File

@ -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',