[APP-1158] Gate features by email verification state (#8305)
* Use new hook in all locations * Format * Seems to work, not great duplication * Wrap all open composer calls * Remove unneeded spans * Missed one * Fix handler on Conversation * Gate new chat in header * Add comment * Remove whoopsie * Format * add hackfix for dialog not showing * add prompt to accept chat btn * navigation not necessary * send back one screen, rather than home * Update comment --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
@@ -62,7 +62,6 @@ import {
|
||||
type SupportedMimeTypes,
|
||||
} from '#/lib/constants'
|
||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
||||
import {useEmail} from '#/lib/hooks/useEmail'
|
||||
import {useIsKeyboardVisible} from '#/lib/hooks/useIsKeyboardVisible'
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
@@ -120,10 +119,6 @@ import * as Toast from '#/view/com/util/Toast'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {atoms as a, native, useTheme} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import {
|
||||
EmailDialogScreenID,
|
||||
useEmailDialogControl,
|
||||
} from '#/components/dialogs/EmailDialog'
|
||||
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
||||
import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji'
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||
@@ -333,25 +328,6 @@ export const ComposePost = ({
|
||||
}
|
||||
}, [onPressCancel, closeAllDialogs, closeAllModals])
|
||||
|
||||
const {needsEmailVerification} = useEmail()
|
||||
const emailDialogControl = useEmailDialogControl()
|
||||
|
||||
useEffect(() => {
|
||||
if (needsEmailVerification) {
|
||||
emailDialogControl.open({
|
||||
id: EmailDialogScreenID.Verify,
|
||||
instructions: [
|
||||
<Trans key="pre-compose">
|
||||
Before creating a post, you must first verify your email.
|
||||
</Trans>,
|
||||
],
|
||||
onCloseWithoutVerifying: () => {
|
||||
onClose()
|
||||
},
|
||||
})
|
||||
}
|
||||
}, [needsEmailVerification, emailDialogControl, onClose])
|
||||
|
||||
const missingAltError = useMemo(() => {
|
||||
if (!requireAltTextEnabled) {
|
||||
return
|
||||
|
||||
@@ -1,26 +1,19 @@
|
||||
import {useCallback} from 'react'
|
||||
import {Keyboard} from 'react-native'
|
||||
import {ImagePickerAsset} from 'expo-image-picker'
|
||||
import {type ImagePickerAsset} from 'expo-image-picker'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {
|
||||
SUPPORTED_MIME_TYPES,
|
||||
SupportedMimeTypes,
|
||||
type SupportedMimeTypes,
|
||||
VIDEO_MAX_DURATION_MS,
|
||||
} from '#/lib/constants'
|
||||
import {BSKY_SERVICE} from '#/lib/constants'
|
||||
import {useVideoLibraryPermission} from '#/lib/hooks/usePermissions'
|
||||
import {getHostnameFromUrl} from '#/lib/strings/url-helpers'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {useSession} from '#/state/session'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button} from '#/components/Button'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
|
||||
import {VideoClip_Stroke2_Corner0_Rounded as VideoClipIcon} from '#/components/icons/VideoClip'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import {pickVideo} from './pickVideo'
|
||||
|
||||
type Props = {
|
||||
@@ -33,66 +26,45 @@ export function SelectVideoBtn({onSelectVideo, disabled, setError}: Props) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const {requestVideoAccessIfNeeded} = useVideoLibraryPermission()
|
||||
const control = Prompt.usePromptControl()
|
||||
const {currentAccount} = useSession()
|
||||
|
||||
const onPressSelectVideo = useCallback(async () => {
|
||||
if (isNative && !(await requestVideoAccessIfNeeded())) {
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
currentAccount &&
|
||||
!currentAccount.emailConfirmed &&
|
||||
getHostnameFromUrl(currentAccount.service) ===
|
||||
getHostnameFromUrl(BSKY_SERVICE)
|
||||
) {
|
||||
Keyboard.dismiss()
|
||||
control.open()
|
||||
} else {
|
||||
const response = await pickVideo()
|
||||
if (response.assets && response.assets.length > 0) {
|
||||
const asset = response.assets[0]
|
||||
try {
|
||||
if (isWeb) {
|
||||
// asset.duration is null for gifs (see the TODO in pickVideo.web.ts)
|
||||
if (asset.duration && asset.duration > VIDEO_MAX_DURATION_MS) {
|
||||
throw Error(_(msg`Videos must be less than 3 minutes long`))
|
||||
}
|
||||
// compression step on native converts to mp4, so no need to check there
|
||||
if (
|
||||
!SUPPORTED_MIME_TYPES.includes(
|
||||
asset.mimeType as SupportedMimeTypes,
|
||||
)
|
||||
) {
|
||||
throw Error(_(msg`Unsupported video type: ${asset.mimeType}`))
|
||||
}
|
||||
} else {
|
||||
if (typeof asset.duration !== 'number') {
|
||||
throw Error('Asset is not a video')
|
||||
}
|
||||
if (asset.duration > VIDEO_MAX_DURATION_MS) {
|
||||
throw Error(_(msg`Videos must be less than 3 minutes long`))
|
||||
}
|
||||
const response = await pickVideo()
|
||||
if (response.assets && response.assets.length > 0) {
|
||||
const asset = response.assets[0]
|
||||
try {
|
||||
if (isWeb) {
|
||||
// asset.duration is null for gifs (see the TODO in pickVideo.web.ts)
|
||||
if (asset.duration && asset.duration > VIDEO_MAX_DURATION_MS) {
|
||||
throw Error(_(msg`Videos must be less than 3 minutes long`))
|
||||
}
|
||||
onSelectVideo(asset)
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
setError(err.message)
|
||||
} else {
|
||||
setError(_(msg`An error occurred while selecting the video`))
|
||||
// compression step on native converts to mp4, so no need to check there
|
||||
if (
|
||||
!SUPPORTED_MIME_TYPES.includes(asset.mimeType as SupportedMimeTypes)
|
||||
) {
|
||||
throw Error(_(msg`Unsupported video type: ${asset.mimeType}`))
|
||||
}
|
||||
} else {
|
||||
if (typeof asset.duration !== 'number') {
|
||||
throw Error('Asset is not a video')
|
||||
}
|
||||
if (asset.duration > VIDEO_MAX_DURATION_MS) {
|
||||
throw Error(_(msg`Videos must be less than 3 minutes long`))
|
||||
}
|
||||
}
|
||||
onSelectVideo(asset)
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
setError(err.message)
|
||||
} else {
|
||||
setError(_(msg`An error occurred while selecting the video`))
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [
|
||||
requestVideoAccessIfNeeded,
|
||||
currentAccount,
|
||||
control,
|
||||
setError,
|
||||
_,
|
||||
onSelectVideo,
|
||||
])
|
||||
}, [requestVideoAccessIfNeeded, setError, _, onSelectVideo])
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -111,30 +83,6 @@ export function SelectVideoBtn({onSelectVideo, disabled, setError}: Props) {
|
||||
style={disabled && t.atoms.text_contrast_low}
|
||||
/>
|
||||
</Button>
|
||||
<VerifyEmailPrompt control={control} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function VerifyEmailPrompt({control}: {control: Prompt.PromptControlProps}) {
|
||||
const {_} = useLingui()
|
||||
const verifyEmailDialogControl = useDialogControl()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Prompt.Basic
|
||||
control={control}
|
||||
title={_(msg`Verified email required`)}
|
||||
description={_(
|
||||
msg`To upload videos to Bluesky, you must first verify your email.`,
|
||||
)}
|
||||
confirmButtonCta={_(msg`Verify now`)}
|
||||
confirmButtonColor="primary"
|
||||
onConfirm={() => {
|
||||
verifyEmailDialogControl.open()
|
||||
}}
|
||||
/>
|
||||
<VerifyEmailDialog control={verifyEmailDialogControl} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user