about summary refs log tree commit diff
path: root/src/screens
diff options
context:
space:
mode:
Diffstat (limited to 'src/screens')
-rw-r--r--src/screens/Messages/ChatList.tsx36
-rw-r--r--src/screens/Profile/Header/Handle.tsx2
-rw-r--r--src/screens/Profile/Header/ProfileHeaderStandard.tsx3
-rw-r--r--src/screens/Profile/Header/Shell.tsx5
-rw-r--r--src/screens/Search/SearchResults.tsx65
-rw-r--r--src/screens/Settings/ContentAndMediaSettings.tsx2
-rw-r--r--src/screens/Settings/Settings.tsx52
7 files changed, 147 insertions, 18 deletions
diff --git a/src/screens/Messages/ChatList.tsx b/src/screens/Messages/ChatList.tsx
index e13f0617b..c37a025cc 100644
--- a/src/screens/Messages/ChatList.tsx
+++ b/src/screens/Messages/ChatList.tsx
@@ -164,12 +164,18 @@ export function MessagesScreenInner({navigation, route}: Props) {
         // filter out convos that are actively being left
         .filter(convo => !leftConvos.includes(convo.id))
 
+      const hasInboxRequests = inboxPreviewConvos?.length > 0
+
       return [
-        {
-          type: 'INBOX',
-          count: inboxPreviewConvos.length,
-          profiles: inboxPreviewConvos.slice(0, 3),
-        },
+        ...(hasInboxRequests
+          ? [
+              {
+                type: 'INBOX' as const,
+                count: inboxPreviewConvos.length,
+                profiles: inboxPreviewConvos.slice(0, 3),
+              },
+            ]
+          : []),
         ...conversations.map(
           convo => ({type: 'CONVERSATION', conversation: convo}) as const,
         ),
@@ -223,16 +229,24 @@ export function MessagesScreenInner({navigation, route}: Props) {
     return listenSoftReset(onSoftReset)
   }, [onSoftReset, isScreenFocused])
 
-  // Will always have 1 item - the inbox button
-  if (conversations.length < 2) {
+  // NOTE(APiligrim)
+  // Show empty state only if there are no conversations at all
+  const actualConversations = conversations.filter(
+    item => item.type === 'CONVERSATION',
+  )
+  const hasInboxRequests = inboxPreviewConvos?.length > 0
+
+  if (actualConversations.length === 0) {
     return (
       <Layout.Screen>
         <Header newChatControl={newChatControl} />
         <Layout.Center>
-          <InboxPreview
-            count={inboxPreviewConvos.length}
-            profiles={inboxPreviewConvos}
-          />
+          {hasInboxRequests && (
+            <InboxPreview
+              count={inboxPreviewConvos.length}
+              profiles={inboxPreviewConvos}
+            />
+          )}
           {isLoading ? (
             <ChatListLoadingPlaceholder />
           ) : (
diff --git a/src/screens/Profile/Header/Handle.tsx b/src/screens/Profile/Header/Handle.tsx
index cfbf430c4..f52b6d68e 100644
--- a/src/screens/Profile/Header/Handle.tsx
+++ b/src/screens/Profile/Header/Handle.tsx
@@ -23,7 +23,7 @@ export function ProfileHeaderHandle({
   const blockHide = profile.viewer?.blocking || profile.viewer?.blockedBy
   return (
     <View
-      style={[a.flex_row, a.gap_xs, a.align_center, {maxWidth: '100%'}]}
+      style={[a.flex_row, a.gap_sm, a.align_center, {maxWidth: '100%'}]}
       pointerEvents={disableTaps ? 'none' : isIOS ? 'auto' : 'box-none'}>
       <NewskieDialog profile={profile} disabled={disableTaps} />
       {profile.viewer?.followedBy && !blockHide ? (
diff --git a/src/screens/Profile/Header/ProfileHeaderStandard.tsx b/src/screens/Profile/Header/ProfileHeaderStandard.tsx
index 5dbf32c57..2f61ba4df 100644
--- a/src/screens/Profile/Header/ProfileHeaderStandard.tsx
+++ b/src/screens/Profile/Header/ProfileHeaderStandard.tsx
@@ -251,7 +251,7 @@ let ProfileHeaderStandard = ({
           <ProfileMenu profile={profile} />
         </View>
         <View
-          style={[a.flex_col, a.gap_2xs, a.pb_sm, live ? a.pt_sm : a.pt_2xs]}>
+          style={[a.flex_col, a.gap_xs, a.pb_sm, live ? a.pt_sm : a.pt_2xs]}>
           <View style={[a.flex_row, a.align_center, a.gap_xs, a.flex_1]}>
             <Text
               emoji
@@ -261,6 +261,7 @@ let ProfileHeaderStandard = ({
                 gtMobile ? a.text_4xl : a.text_3xl,
                 a.self_start,
                 a.font_heavy,
+                a.leading_tight,
               ]}>
               {sanitizeDisplayName(
                 profile.displayName || sanitizeHandle(profile.handle),
diff --git a/src/screens/Profile/Header/Shell.tsx b/src/screens/Profile/Header/Shell.tsx
index 53585c094..27962ba05 100644
--- a/src/screens/Profile/Header/Shell.tsx
+++ b/src/screens/Profile/Header/Shell.tsx
@@ -229,6 +229,7 @@ let ProfileHeaderShell = ({
                 size={live.isActive ? 88 : 90}
                 avatar={profile.avatar}
                 moderation={moderation.ui('avatar')}
+                noBorder
               />
               {live.isActive && <LiveIndicator size="large" />}
             </Animated.View>
@@ -260,7 +261,7 @@ export {ProfileHeaderShell}
 const styles = StyleSheet.create({
   backBtnWrapper: {
     position: 'absolute',
-    left: 10,
+    left: 12,
     width: 30,
     height: 30,
     overflow: 'hidden',
@@ -279,7 +280,7 @@ const styles = StyleSheet.create({
   },
   aviPosition: {
     position: 'absolute',
-    top: 110,
+    top: 104,
     left: 10,
   },
   avi: {
diff --git a/src/screens/Search/SearchResults.tsx b/src/screens/Search/SearchResults.tsx
index 6b7a582d5..b626c9329 100644
--- a/src/screens/Search/SearchResults.tsx
+++ b/src/screens/Search/SearchResults.tsx
@@ -4,11 +4,14 @@ import {type AppBskyFeedDefs} from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
+import {usePalette} from '#/lib/hooks/usePalette'
 import {augmentSearchQuery} from '#/lib/strings/helpers'
 import {useActorSearch} from '#/state/queries/actor-search'
 import {usePopularFeedsSearch} from '#/state/queries/feed'
 import {useSearchPostsQuery} from '#/state/queries/search-posts'
 import {useSession} from '#/state/session'
+import {useLoggedOutViewControls} from '#/state/shell/logged-out'
+import {useCloseAllActiveElements} from '#/state/util'
 import {Pager} from '#/view/com/pager/Pager'
 import {TabBar} from '#/view/com/pager/TabBar'
 import {Post} from '#/view/com/post/Post'
@@ -17,6 +20,8 @@ import {List} from '#/view/com/util/List'
 import {atoms as a, useTheme, web} from '#/alf'
 import * as FeedCard from '#/components/FeedCard'
 import * as Layout from '#/components/Layout'
+import {InlineLinkText} from '#/components/Link'
+import {SearchError} from '#/components/SearchError'
 import {Text} from '#/components/Typography'
 
 let SearchResults = ({
@@ -104,7 +109,15 @@ function Loader() {
   )
 }
 
-function EmptyState({message, error}: {message: string; error?: string}) {
+function EmptyState({
+  message,
+  error,
+  children,
+}: {
+  message: string
+  error?: string
+  children?: React.ReactNode
+}) {
   const t = useTheme()
 
   return (
@@ -132,6 +145,8 @@ function EmptyState({message, error}: {message: string; error?: string}) {
               </Text>
             </>
           )}
+
+          {children}
         </View>
       </View>
     </Layout.Content>
@@ -161,6 +176,7 @@ let SearchScreenPostResults = ({
   const {_} = useLingui()
   const {currentAccount} = useSession()
   const [isPTR, setIsPTR] = useState(false)
+  const isLoggedin = Boolean(currentAccount?.did)
 
   const augmentedQuery = useMemo(() => {
     return augmentSearchQuery(query || '', {did: currentAccount?.did})
@@ -177,6 +193,8 @@ let SearchScreenPostResults = ({
     hasNextPage,
   } = useSearchPostsQuery({query: augmentedQuery, sort, enabled: active})
 
+  const pal = usePalette('default')
+  const t = useTheme()
   const onPullToRefresh = useCallback(async () => {
     setIsPTR(true)
     await refetch()
@@ -216,6 +234,51 @@ let SearchScreenPostResults = ({
     return temp
   }, [posts, isFetchingNextPage])
 
+  const closeAllActiveElements = useCloseAllActiveElements()
+  const {requestSwitchToAccount} = useLoggedOutViewControls()
+
+  const showSignIn = () => {
+    closeAllActiveElements()
+    requestSwitchToAccount({requestedAccount: 'none'})
+  }
+
+  const showCreateAccount = () => {
+    closeAllActiveElements()
+    requestSwitchToAccount({requestedAccount: 'new'})
+  }
+
+  if (!isLoggedin) {
+    return (
+      <SearchError
+        title={_(msg`Search is currently unavailable when logged out`)}>
+        <Text style={[a.text_md, a.text_center, a.leading_snug]}>
+          <Trans>
+            <InlineLinkText
+              style={[pal.link]}
+              label={_(msg`sign in`)}
+              to={'#'}
+              onPress={showSignIn}>
+              Sign in
+            </InlineLinkText>
+            <Text style={t.atoms.text_contrast_medium}> or </Text>
+            <InlineLinkText
+              style={[pal.link]}
+              label={_(msg`create an account`)}
+              to={'#'}
+              onPress={showCreateAccount}>
+              create an account
+            </InlineLinkText>
+            <Text> </Text>
+            <Text style={t.atoms.text_contrast_medium}>
+              to search for news, sports, politics, and everything else
+              happening on Bluesky.
+            </Text>
+          </Trans>
+        </Text>
+      </SearchError>
+    )
+  }
+
   return error ? (
     <EmptyState
       message={_(
diff --git a/src/screens/Settings/ContentAndMediaSettings.tsx b/src/screens/Settings/ContentAndMediaSettings.tsx
index 10d5b140b..e1144d064 100644
--- a/src/screens/Settings/ContentAndMediaSettings.tsx
+++ b/src/screens/Settings/ContentAndMediaSettings.tsx
@@ -150,7 +150,7 @@ export function ContentAndMediaSettingsScreen({}: Props) {
               </Toggle.Item>
               <Toggle.Item
                 name="show_trending_videos"
-                label={_(msg`Enable trending videos in your Discover feed.`)}
+                label={_(msg`Enable trending videos in your Discover feed`)}
                 value={!trendingVideoDisabled}
                 onChange={value => {
                   const hide = Boolean(!value)
diff --git a/src/screens/Settings/Settings.tsx b/src/screens/Settings/Settings.tsx
index 4d10a9d0d..b712c054c 100644
--- a/src/screens/Settings/Settings.tsx
+++ b/src/screens/Settings/Settings.tsx
@@ -1,5 +1,5 @@
 import {useState} from 'react'
-import {LayoutAnimation, Pressable, View} from 'react-native'
+import {Alert, LayoutAnimation, Pressable, View} from 'react-native'
 import {Linking} from 'react-native'
 import {useReducedMotion} from 'react-native-reanimated'
 import {type AppBskyActorDefs, moderateProfile} from '@atproto/api'
@@ -12,12 +12,14 @@ import {useActorStatus} from '#/lib/actor-status'
 import {IS_INTERNAL} from '#/lib/app-info'
 import {HELP_DESK_URL} from '#/lib/constants'
 import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
+import {useApplyPullRequestOTAUpdate} from '#/lib/hooks/useOTAUpdates'
 import {
   type CommonNavigatorParams,
   type NavigationProp,
 } from '#/lib/routes/types'
 import {sanitizeDisplayName} from '#/lib/strings/display-names'
 import {sanitizeHandle} from '#/lib/strings/handles'
+import {isIOS, isNative} from '#/platform/detection'
 import {useProfileShadow} from '#/state/cache/profile-shadow'
 import * as persisted from '#/state/persisted'
 import {clearStorage} from '#/state/persisted'
@@ -364,6 +366,12 @@ function DevOptions() {
   const onboardingDispatch = useOnboardingDispatch()
   const navigation = useNavigation<NavigationProp>()
   const {mutate: deleteChatDeclarationRecord} = useDeleteActorDeclaration()
+  const {
+    tryApplyUpdate,
+    revertToEmbedded,
+    isCurrentlyRunningPullRequestDeployment,
+    currentChannel,
+  } = useApplyPullRequestOTAUpdate()
   const [actyNotifNudged, setActyNotifNudged] = useActivitySubscriptionsNudged()
 
   const resetOnboarding = async () => {
@@ -392,6 +400,30 @@ function DevOptions() {
     setActyNotifNudged(false)
   }
 
+  const onPressApplyOta = () => {
+    Alert.prompt(
+      'Apply OTA',
+      'Enter the channel for the OTA you wish to apply.',
+      [
+        {
+          style: 'cancel',
+          text: 'Cancel',
+        },
+        {
+          style: 'default',
+          text: 'Apply',
+          onPress: channel => {
+            tryApplyUpdate(channel ?? '')
+          },
+        },
+      ],
+      'plain-text',
+      isCurrentlyRunningPullRequestDeployment
+        ? currentChannel
+        : 'pull-request-',
+    )
+  }
+
   return (
     <>
       <SettingsList.PressableItem
@@ -452,6 +484,24 @@ function DevOptions() {
           <Trans>Clear all storage data (restart after this)</Trans>
         </SettingsList.ItemText>
       </SettingsList.PressableItem>
+      {isIOS ? (
+        <SettingsList.PressableItem
+          onPress={onPressApplyOta}
+          label={_(msg`Apply Pull Request`)}>
+          <SettingsList.ItemText>
+            <Trans>Apply Pull Request</Trans>
+          </SettingsList.ItemText>
+        </SettingsList.PressableItem>
+      ) : null}
+      {isNative && isCurrentlyRunningPullRequestDeployment ? (
+        <SettingsList.PressableItem
+          onPress={revertToEmbedded}
+          label={_(msg`Unapply Pull Request`)}>
+          <SettingsList.ItemText>
+            <Trans>Unapply Pull Request {currentChannel}</Trans>
+          </SettingsList.ItemText>
+        </SettingsList.PressableItem>
+      ) : null}
     </>
   )
 }