about summary refs log tree commit diff
path: root/src/view/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com')
-rw-r--r--src/view/com/composer/Composer.tsx21
-rw-r--r--src/view/com/composer/videos/SelectVideoBtn.tsx112
-rw-r--r--src/view/com/feeds/FeedPage.tsx16
-rw-r--r--src/view/com/post-thread/PostThread.tsx18
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx4
-rw-r--r--src/view/com/post/Post.tsx16
-rw-r--r--src/view/com/posts/PostFeedItem.tsx4
-rw-r--r--src/view/com/util/post-ctrls/PostCtrls.tsx4
8 files changed, 63 insertions, 132 deletions
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index b6d269d28..e690e7256 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -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,8 +119,6 @@ import * as Toast from '#/view/com/util/Toast'
 import {UserAvatar} from '#/view/com/util/UserAvatar'
 import {atoms as a, native, useTheme, web} from '#/alf'
 import {Button, ButtonIcon, ButtonText} from '#/components/Button'
-import {useDialogControl} from '#/components/Dialog'
-import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
 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'
@@ -331,15 +328,6 @@ export const ComposePost = ({
     }
   }, [onPressCancel, closeAllDialogs, closeAllModals])
 
-  const {needsEmailVerification} = useEmail()
-  const emailVerificationControl = useDialogControl()
-
-  useEffect(() => {
-    if (needsEmailVerification) {
-      emailVerificationControl.open()
-    }
-  }, [needsEmailVerification, emailVerificationControl])
-
   const missingAltError = useMemo(() => {
     if (!requireAltTextEnabled) {
       return
@@ -620,15 +608,6 @@ export const ComposePost = ({
   const isWebFooterSticky = !isNative && thread.posts.length > 1
   return (
     <BottomSheetPortalProvider>
-      <VerifyEmailDialog
-        control={emailVerificationControl}
-        onCloseWithoutVerifying={() => {
-          onClose()
-        }}
-        reasonText={_(
-          msg`Before creating a post, you must first verify your email.`,
-        )}
-      />
       <KeyboardAvoidingView
         testID="composePostView"
         behavior={isIOS ? 'padding' : 'height'}
diff --git a/src/view/com/composer/videos/SelectVideoBtn.tsx b/src/view/com/composer/videos/SelectVideoBtn.tsx
index 8d9371f0d..96715955f 100644
--- a/src/view/com/composer/videos/SelectVideoBtn.tsx
+++ b/src/view/com/composer/videos/SelectVideoBtn.tsx
@@ -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} />
     </>
   )
 }
diff --git a/src/view/com/feeds/FeedPage.tsx b/src/view/com/feeds/FeedPage.tsx
index f643adaf9..604533b0f 100644
--- a/src/view/com/feeds/FeedPage.tsx
+++ b/src/view/com/feeds/FeedPage.tsx
@@ -1,32 +1,32 @@
 import React from 'react'
 import {View} from 'react-native'
-import {AppBskyActorDefs, AppBskyFeedDefs} from '@atproto/api'
+import {type AppBskyActorDefs, AppBskyFeedDefs} from '@atproto/api'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
-import {NavigationProp, useNavigation} from '@react-navigation/native'
+import {type NavigationProp, useNavigation} from '@react-navigation/native'
 import {useQueryClient} from '@tanstack/react-query'
 
 import {VIDEO_FEED_URIS} from '#/lib/constants'
+import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
 import {ComposeIcon2} from '#/lib/icons'
 import {getRootNavigation, getTabState, TabState} from '#/lib/routes/helpers'
-import {AllNavigatorParams} from '#/lib/routes/types'
+import {type AllNavigatorParams} from '#/lib/routes/types'
 import {logEvent} from '#/lib/statsig/statsig'
 import {s} from '#/lib/styles'
 import {isNative} from '#/platform/detection'
 import {listenSoftReset} from '#/state/events'
 import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback'
 import {useSetHomeBadge} from '#/state/home-badge'
-import {SavedFeedSourceInfo} from '#/state/queries/feed'
+import {type SavedFeedSourceInfo} from '#/state/queries/feed'
 import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
-import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
+import {type FeedDescriptor, type FeedParams} from '#/state/queries/post-feed'
 import {truncateAndInvalidate} from '#/state/queries/util'
 import {useSession} from '#/state/session'
 import {useSetMinimalShellMode} from '#/state/shell'
-import {useComposerControls} from '#/state/shell/composer'
 import {useHeaderOffset} from '#/components/hooks/useHeaderOffset'
 import {PostFeed} from '../posts/PostFeed'
 import {FAB} from '../util/fab/FAB'
-import {ListMethods} from '../util/List'
+import {type ListMethods} from '../util/List'
 import {LoadLatestBtn} from '../util/load-latest/LoadLatestBtn'
 import {MainScrollProvider} from '../util/MainScrollProvider'
 
@@ -57,7 +57,7 @@ export function FeedPage({
   const {_} = useLingui()
   const navigation = useNavigation<NavigationProp<AllNavigatorParams>>()
   const queryClient = useQueryClient()
-  const {openComposer} = useComposerControls()
+  const {openComposer} = useOpenComposer()
   const [isScrolledDown, setIsScrolledDown] = React.useState(false)
   const setMinimalShellMode = useSetMinimalShellMode()
   const headerOffset = useHeaderOffset()
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index 83dbdb553..d974ce6b5 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -5,7 +5,7 @@ import Animated from 'react-native-reanimated'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
 import {
   AppBskyFeedDefs,
-  AppBskyFeedThreadgate,
+  type AppBskyFeedThreadgate,
   moderatePost,
 } from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
@@ -14,6 +14,7 @@ import {useLingui} from '@lingui/react'
 import {HITSLOP_10} from '#/lib/constants'
 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
 import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
+import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
 import {useSetTitle} from '#/lib/hooks/useSetTitle'
 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
 import {clamp} from '#/lib/numbers'
@@ -25,19 +26,18 @@ import {useModerationOpts} from '#/state/preferences/moderation-opts'
 import {
   fillThreadModerationCache,
   sortThread,
-  ThreadBlocked,
-  ThreadModerationCache,
-  ThreadNode,
-  ThreadNotFound,
-  ThreadPost,
+  type ThreadBlocked,
+  type ThreadModerationCache,
+  type ThreadNode,
+  type ThreadNotFound,
+  type ThreadPost,
   usePostThreadQuery,
 } from '#/state/queries/post-thread'
 import {useSetThreadViewPreferencesMutation} from '#/state/queries/preferences'
 import {usePreferencesQuery} from '#/state/queries/preferences'
 import {useSession} from '#/state/session'
-import {useComposerControls} from '#/state/shell'
 import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
-import {List, ListMethods} from '#/view/com/util/List'
+import {List, type ListMethods} from '#/view/com/util/List'
 import {atoms as a, useTheme} from '#/alf'
 import {Button, ButtonIcon} from '#/components/Button'
 import {SettingsSliderVertical_Stroke2_Corner0_Rounded as SettingsSlider} from '#/components/icons/SettingsSlider'
@@ -394,7 +394,7 @@ export function PostThread({uri}: {uri: string | undefined}) {
     [refetch],
   )
 
-  const {openComposer} = useComposerControls()
+  const {openComposer} = useOpenComposer()
   const onPressReply = React.useCallback(() => {
     if (thread?.type !== 'post') {
       return
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index dfd641f66..10c3e6b4d 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -17,6 +17,7 @@ import {msg, Plural, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
 import {MAX_POST_LINES} from '#/lib/constants'
+import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
 import {useOpenLink} from '#/lib/hooks/useOpenLink'
 import {usePalette} from '#/lib/hooks/usePalette'
 import {makeProfileLink} from '#/lib/routes/links'
@@ -36,7 +37,6 @@ import {useProfileShadow} from '#/state/cache/profile-shadow'
 import {useLanguagePrefs} from '#/state/preferences'
 import {type ThreadPost} from '#/state/queries/post-thread'
 import {useSession} from '#/state/session'
-import {useComposerControls} from '#/state/shell/composer'
 import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
 import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn'
 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
@@ -204,7 +204,7 @@ let PostThreadItemLoaded = ({
   const pal = usePalette('default')
   const {_, i18n} = useLingui()
   const langPrefs = useLanguagePrefs()
-  const {openComposer} = useComposerControls()
+  const {openComposer} = useOpenComposer()
   const [limitLines, setLimitLines] = React.useState(
     () => countLines(richText?.text) >= MAX_POST_LINES,
   )
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index 600cee428..c6cf254f3 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -1,11 +1,11 @@
 import React, {useMemo, useState} from 'react'
-import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
+import {type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native'
 import {
-  AppBskyFeedDefs,
+  type AppBskyFeedDefs,
   AppBskyFeedPost,
   AtUri,
   moderatePost,
-  ModerationDecision,
+  type ModerationDecision,
   RichText as RichTextAPI,
 } from '@atproto/api'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
@@ -14,15 +14,19 @@ import {useLingui} from '@lingui/react'
 import {useQueryClient} from '@tanstack/react-query'
 
 import {MAX_POST_LINES} from '#/lib/constants'
+import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
 import {usePalette} from '#/lib/hooks/usePalette'
 import {makeProfileLink} from '#/lib/routes/links'
 import {countLines} from '#/lib/strings/helpers'
 import {colors, s} from '#/lib/styles'
-import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
+import {
+  POST_TOMBSTONE,
+  type Shadow,
+  usePostShadow,
+} from '#/state/cache/post-shadow'
 import {useModerationOpts} from '#/state/preferences/moderation-opts'
 import {precacheProfile} from '#/state/queries/profile'
 import {useSession} from '#/state/session'
-import {useComposerControls} from '#/state/shell/composer'
 import {AviFollowButton} from '#/view/com/posts/AviFollowButton'
 import {atoms as a} from '#/alf'
 import {ProfileHoverCard} from '#/components/ProfileHoverCard'
@@ -113,7 +117,7 @@ function PostInner({
   const queryClient = useQueryClient()
   const pal = usePalette('default')
   const {_} = useLingui()
-  const {openComposer} = useComposerControls()
+  const {openComposer} = useOpenComposer()
   const [limitLines, setLimitLines] = useState(
     () => countLines(richText?.text) >= MAX_POST_LINES,
   )
diff --git a/src/view/com/posts/PostFeedItem.tsx b/src/view/com/posts/PostFeedItem.tsx
index facd31e5f..123a8b0c2 100644
--- a/src/view/com/posts/PostFeedItem.tsx
+++ b/src/view/com/posts/PostFeedItem.tsx
@@ -19,6 +19,7 @@ import {useQueryClient} from '@tanstack/react-query'
 
 import {isReasonFeedSource, type ReasonFeedSource} from '#/lib/api/feed/types'
 import {MAX_POST_LINES} from '#/lib/constants'
+import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
 import {usePalette} from '#/lib/hooks/usePalette'
 import {makeProfileLink} from '#/lib/routes/links'
 import {sanitizeDisplayName} from '#/lib/strings/display-names'
@@ -33,7 +34,6 @@ import {
 import {useFeedFeedbackContext} from '#/state/feed-feedback'
 import {precacheProfile} from '#/state/queries/profile'
 import {useSession} from '#/state/session'
-import {useComposerControls} from '#/state/shell/composer'
 import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
 import {FeedNameText} from '#/view/com/util/FeedInfoText'
 import {PostCtrls} from '#/view/com/util/post-ctrls/PostCtrls'
@@ -159,7 +159,7 @@ let FeedItemInner = ({
   onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
 }): React.ReactNode => {
   const queryClient = useQueryClient()
-  const {openComposer} = useComposerControls()
+  const {openComposer} = useOpenComposer()
   const pal = usePalette('default')
   const {_} = useLingui()
 
diff --git a/src/view/com/util/post-ctrls/PostCtrls.tsx b/src/view/com/util/post-ctrls/PostCtrls.tsx
index d97654a63..a9cae8886 100644
--- a/src/view/com/util/post-ctrls/PostCtrls.tsx
+++ b/src/view/com/util/post-ctrls/PostCtrls.tsx
@@ -22,6 +22,7 @@ import {DISCOVER_DEBUG_DIDS, POST_CTRL_HITSLOP} from '#/lib/constants'
 import {CountWheel} from '#/lib/custom-animations/CountWheel'
 import {AnimatedLikeIcon} from '#/lib/custom-animations/LikeIcon'
 import {useHaptics} from '#/lib/haptics'
+import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
 import {makeProfileLink} from '#/lib/routes/links'
 import {shareUrl} from '#/lib/sharing'
 import {useGate} from '#/lib/statsig/statsig'
@@ -33,7 +34,6 @@ import {
   usePostRepostMutationQueue,
 } from '#/state/queries/post'
 import {useRequireAuth, useSession} from '#/state/session'
-import {useComposerControls} from '#/state/shell/composer'
 import {
   ProgressGuideAction,
   useProgressGuideControls,
@@ -76,7 +76,7 @@ let PostCtrls = ({
 }): React.ReactNode => {
   const t = useTheme()
   const {_, i18n} = useLingui()
-  const {openComposer} = useComposerControls()
+  const {openComposer} = useOpenComposer()
   const {currentAccount} = useSession()
   const [queueLike, queueUnlike] = usePostLikeMutationQueue(post, logContext)
   const [queueRepost, queueUnrepost] = usePostRepostMutationQueue(