Use Reanimated layout animations for Android composer (#8546)
This commit is contained in:
@@ -1,29 +1,30 @@
|
|||||||
import {useEffect, useRef} from 'react'
|
import {useEffect} from 'react'
|
||||||
import {Modal, View} from 'react-native'
|
import {Modal, View} from 'react-native'
|
||||||
|
import {SystemBars} from 'react-native-edge-to-edge'
|
||||||
|
|
||||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
|
||||||
import {useComposerState} from '#/state/shell/composer'
|
import {useComposerState} from '#/state/shell/composer'
|
||||||
import {ComposePost, useComposerCancelRef} from '#/view/com/composer/Composer'
|
import {ComposePost, useComposerCancelRef} from '#/view/com/composer/Composer'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {SheetCompatProvider as TooltipSheetCompatProvider} from '#/components/Tooltip'
|
import {SheetCompatProvider as TooltipSheetCompatProvider} from '#/components/Tooltip'
|
||||||
|
import {IS_LIQUID_GLASS} from '#/env'
|
||||||
|
|
||||||
export function Composer({}: {winHeight: number}) {
|
export function Composer() {
|
||||||
const {setFullyExpandedCount} = useDialogStateControlContext()
|
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const state = useComposerState()
|
const state = useComposerState()
|
||||||
const ref = useComposerCancelRef()
|
const ref = useComposerCancelRef()
|
||||||
|
|
||||||
const open = !!state
|
const open = !!state
|
||||||
const prevOpen = useRef(open)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open && !prevOpen.current) {
|
if (open && !IS_LIQUID_GLASS) {
|
||||||
setFullyExpandedCount(c => c + 1)
|
const entry = SystemBars.pushStackEntry({
|
||||||
} else if (!open && prevOpen.current) {
|
style: {
|
||||||
setFullyExpandedCount(c => c - 1)
|
statusBar: 'light',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return () => SystemBars.popStackEntry(entry)
|
||||||
}
|
}
|
||||||
prevOpen.current = open
|
}, [open])
|
||||||
}, [open, setFullyExpandedCount])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
+22
-30
@@ -1,49 +1,41 @@
|
|||||||
import {useEffect} from 'react'
|
import {useEffect} from 'react'
|
||||||
import {Animated, Easing} from 'react-native'
|
import {SystemBars} from 'react-native-edge-to-edge'
|
||||||
|
import Animated, {
|
||||||
|
Easing,
|
||||||
|
SlideInDown,
|
||||||
|
SlideOutDown,
|
||||||
|
} from 'react-native-reanimated'
|
||||||
|
|
||||||
import {useAnimatedValue} from '#/lib/hooks/useAnimatedValue'
|
|
||||||
import {useComposerState} from '#/state/shell/composer'
|
import {useComposerState} from '#/state/shell/composer'
|
||||||
|
import {ComposePost} from '#/view/com/composer/Composer'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {ComposePost} from '../com/composer/Composer'
|
|
||||||
|
|
||||||
export function Composer({winHeight}: {winHeight: number}) {
|
export function Composer() {
|
||||||
const state = useComposerState()
|
const state = useComposerState()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const initInterp = useAnimatedValue(0)
|
|
||||||
|
const open = !!state
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state) {
|
if (open) {
|
||||||
Animated.timing(initInterp, {
|
const entry = SystemBars.pushStackEntry({
|
||||||
toValue: 1,
|
style: {
|
||||||
duration: 300,
|
statusBar: t.name !== 'light' ? 'light' : 'dark',
|
||||||
easing: Easing.out(Easing.exp),
|
},
|
||||||
useNativeDriver: true,
|
})
|
||||||
}).start()
|
return () => SystemBars.popStackEntry(entry)
|
||||||
} else {
|
|
||||||
initInterp.setValue(0)
|
|
||||||
}
|
}
|
||||||
}, [initInterp, state])
|
}, [open, t.name])
|
||||||
const wrapperAnimStyle = {
|
|
||||||
transform: [
|
|
||||||
{
|
|
||||||
translateY: initInterp.interpolate({
|
|
||||||
inputRange: [0, 1],
|
|
||||||
outputRange: [winHeight, 0],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
// rendering
|
if (!open) {
|
||||||
// =
|
|
||||||
|
|
||||||
if (!state) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={[a.absolute, a.inset_0, t.atoms.bg, wrapperAnimStyle]}
|
style={[a.absolute, a.inset_0, t.atoms.bg]}
|
||||||
|
entering={SlideInDown.duration(300).easing(Easing.out(Easing.exp))}
|
||||||
|
exiting={SlideOutDown.duration(200).easing(Easing.in(Easing.quad))}
|
||||||
aria-modal
|
aria-modal
|
||||||
accessibilityViewIsModal>
|
accessibilityViewIsModal>
|
||||||
<ComposePost
|
<ComposePost
|
||||||
|
|||||||
@@ -5,18 +5,15 @@ import {RemoveScrollBar} from 'react-remove-scroll-bar'
|
|||||||
import {useA11y} from '#/state/a11y'
|
import {useA11y} from '#/state/a11y'
|
||||||
import {useModals} from '#/state/modals'
|
import {useModals} from '#/state/modals'
|
||||||
import {type ComposerOpts, useComposerState} from '#/state/shell/composer'
|
import {type ComposerOpts, useComposerState} from '#/state/shell/composer'
|
||||||
|
import {ComposePost, useComposerCancelRef} from '#/view/com/composer/Composer'
|
||||||
import {atoms as a, flatten, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, flatten, useBreakpoints, useTheme} from '#/alf'
|
||||||
import {ComposePost, useComposerCancelRef} from '../com/composer/Composer'
|
|
||||||
|
|
||||||
const BOTTOM_BAR_HEIGHT = 61
|
const BOTTOM_BAR_HEIGHT = 61
|
||||||
|
|
||||||
export function Composer({}: {winHeight: number}) {
|
export function Composer() {
|
||||||
const state = useComposerState()
|
const state = useComposerState()
|
||||||
const isActive = !!state
|
const isActive = !!state
|
||||||
|
|
||||||
// rendering
|
|
||||||
// =
|
|
||||||
|
|
||||||
if (!isActive) {
|
if (!isActive) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ import {Composer} from './Composer'
|
|||||||
import {DrawerContent} from './Drawer'
|
import {DrawerContent} from './Drawer'
|
||||||
|
|
||||||
function ShellInner() {
|
function ShellInner() {
|
||||||
const winDim = useWindowDimensions()
|
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
const {state: policyUpdateState} = usePolicyUpdateContext()
|
const {state: policyUpdateState} = usePolicyUpdateContext()
|
||||||
|
|
||||||
@@ -108,8 +107,7 @@ function ShellInner() {
|
|||||||
<TabsNavigator layout={drawerLayout} />
|
<TabsNavigator layout={drawerLayout} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</View>
|
</View>
|
||||||
|
<Composer />
|
||||||
<Composer winHeight={winDim.height} />
|
|
||||||
<ModalsContainer />
|
<ModalsContainer />
|
||||||
<MutedWordsDialog />
|
<MutedWordsDialog />
|
||||||
<SigninDialog />
|
<SigninDialog />
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ function ShellInner() {
|
|||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<FlatNavigator layout={drawerLayout} />
|
<FlatNavigator layout={drawerLayout} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
<Composer winHeight={0} />
|
<Composer />
|
||||||
<ModalsContainer />
|
<ModalsContainer />
|
||||||
<MutedWordsDialog />
|
<MutedWordsDialog />
|
||||||
<SigninDialog />
|
<SigninDialog />
|
||||||
|
|||||||
Reference in New Issue
Block a user