allow swipe dismissal on iOS
This commit is contained in:
@@ -173,8 +173,10 @@ export const ComposePost = ({
|
|||||||
imageUris: initImageUris,
|
imageUris: initImageUris,
|
||||||
videoUri: initVideoUri,
|
videoUri: initVideoUri,
|
||||||
cancelRef,
|
cancelRef,
|
||||||
|
setIsDirty,
|
||||||
}: Props & {
|
}: Props & {
|
||||||
cancelRef?: React.RefObject<CancelRef | null>
|
cancelRef?: React.RefObject<CancelRef | null>
|
||||||
|
setIsDirty?: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
}) => {
|
}) => {
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
@@ -304,24 +306,37 @@ export const ComposePost = ({
|
|||||||
[insets, isKeyboardVisible],
|
[insets, isKeyboardVisible],
|
||||||
)
|
)
|
||||||
|
|
||||||
const onPressCancel = useCallback(() => {
|
const isDirty = thread.posts.some(
|
||||||
if (textInput.current?.maybeClosePopup()) {
|
post =>
|
||||||
|
post.shortenedGraphemeLength > 0 || post.embed.media || post.embed.link,
|
||||||
|
)
|
||||||
|
|
||||||
|
// very unfortunate, but we need to pass state back up to the parent on iOS
|
||||||
|
//
|
||||||
|
// WARNING - if the Modal on iOS thinks it's not dirty,
|
||||||
|
// `allowSwipeDismissal` will be true, and if we don't then close the composer
|
||||||
|
// when `onPressCancel` is called it will be bad (might even softlock)
|
||||||
|
// so we need to keep the parent state and the behaviour of onPressCancel in
|
||||||
|
// tight sync. do NOT force the modal to stay open without marking it as dirty! -sfn
|
||||||
|
useEffect(() => {
|
||||||
|
if (isIOS) {
|
||||||
|
setIsDirty?.(isDirty)
|
||||||
|
}
|
||||||
|
}, [isDirty, setIsDirty])
|
||||||
|
|
||||||
|
const onPressCancel = useNonReactiveCallback(() => {
|
||||||
|
// web only, so it's fine w.r.t. the Modal
|
||||||
|
const didCloseAutocomplete = textInput.current?.maybeClosePopup()
|
||||||
|
if (isWeb && didCloseAutocomplete) {
|
||||||
return
|
return
|
||||||
} else if (
|
} else if (isDirty) {
|
||||||
thread.posts.some(
|
|
||||||
post =>
|
|
||||||
post.shortenedGraphemeLength > 0 ||
|
|
||||||
post.embed.media ||
|
|
||||||
post.embed.link,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
closeAllDialogs()
|
closeAllDialogs()
|
||||||
Keyboard.dismiss()
|
Keyboard.dismiss()
|
||||||
discardPromptControl.open()
|
discardPromptControl.open()
|
||||||
} else {
|
} else {
|
||||||
onClose()
|
onClose()
|
||||||
}
|
}
|
||||||
}, [thread, closeAllDialogs, discardPromptControl, onClose])
|
})
|
||||||
|
|
||||||
useImperativeHandle(cancelRef, () => ({onPressCancel}))
|
useImperativeHandle(cancelRef, () => ({onPressCancel}))
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import {useEffect, useRef, useState} from 'react'
|
||||||
import {Modal, View} from 'react-native'
|
import {Modal, View} from 'react-native'
|
||||||
|
|
||||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
import {useDialogStateControlContext} from '#/state/dialogs'
|
||||||
@@ -11,11 +11,17 @@ export function Composer({}: {winHeight: number}) {
|
|||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const state = useComposerState()
|
const state = useComposerState()
|
||||||
const ref = useComposerCancelRef()
|
const ref = useComposerCancelRef()
|
||||||
|
const [isDirty, setIsDirty] = useState(
|
||||||
|
!!state?.text ||
|
||||||
|
!!state?.imageUris ||
|
||||||
|
!!state?.videoUri ||
|
||||||
|
!!state?.mention,
|
||||||
|
)
|
||||||
|
|
||||||
const open = !!state
|
const open = !!state
|
||||||
const prevOpen = React.useRef(open)
|
const prevOpen = useRef(open)
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (open && !prevOpen.current) {
|
if (open && !prevOpen.current) {
|
||||||
setFullyExpandedCount(c => c + 1)
|
setFullyExpandedCount(c => c + 1)
|
||||||
} else if (!open && prevOpen.current) {
|
} else if (!open && prevOpen.current) {
|
||||||
@@ -31,7 +37,8 @@ export function Composer({}: {winHeight: number}) {
|
|||||||
visible={open}
|
visible={open}
|
||||||
presentationStyle="pageSheet"
|
presentationStyle="pageSheet"
|
||||||
animationType="slide"
|
animationType="slide"
|
||||||
onRequestClose={() => ref.current?.onPressCancel()}>
|
onRequestClose={() => ref.current?.onPressCancel()}
|
||||||
|
allowSwipeDismissal={!isDirty}>
|
||||||
<View style={[t.atoms.bg, a.flex_1]}>
|
<View style={[t.atoms.bg, a.flex_1]}>
|
||||||
<ComposePost
|
<ComposePost
|
||||||
cancelRef={ref}
|
cancelRef={ref}
|
||||||
@@ -43,6 +50,7 @@ export function Composer({}: {winHeight: number}) {
|
|||||||
text={state?.text}
|
text={state?.text}
|
||||||
imageUris={state?.imageUris}
|
imageUris={state?.imageUris}
|
||||||
videoUri={state?.videoUri}
|
videoUri={state?.videoUri}
|
||||||
|
setIsDirty={setIsDirty}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
Reference in New Issue
Block a user