about summary refs log tree commit diff
path: root/src/view/com/posts
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/posts')
-rw-r--r--src/view/com/posts/CustomFeedEmptyState.tsx9
-rw-r--r--src/view/com/posts/DiscoverFallbackHeader.tsx43
-rw-r--r--src/view/com/posts/Feed.tsx31
-rw-r--r--src/view/com/posts/FeedErrorMessage.tsx15
-rw-r--r--src/view/com/posts/FeedItem.tsx76
-rw-r--r--src/view/com/posts/FeedSlice.tsx3
-rw-r--r--src/view/com/posts/FollowingEmptyState.tsx13
-rw-r--r--src/view/com/posts/FollowingEndOfFeed.tsx13
8 files changed, 145 insertions, 58 deletions
diff --git a/src/view/com/posts/CustomFeedEmptyState.tsx b/src/view/com/posts/CustomFeedEmptyState.tsx
index e83a94f03..62a10fd19 100644
--- a/src/view/com/posts/CustomFeedEmptyState.tsx
+++ b/src/view/com/posts/CustomFeedEmptyState.tsx
@@ -12,6 +12,7 @@ import {NavigationProp} from 'lib/routes/types'
 import {usePalette} from 'lib/hooks/usePalette'
 import {s} from 'lib/styles'
 import {isWeb} from 'platform/detection'
+import {Trans} from '@lingui/macro'
 
 export function CustomFeedEmptyState() {
   const pal = usePalette('default')
@@ -33,15 +34,17 @@ export function CustomFeedEmptyState() {
         <MagnifyingGlassIcon style={[styles.emptyIcon, pal.text]} size={62} />
       </View>
       <Text type="xl-medium" style={[s.textCenter, pal.text]}>
-        This feed is empty! You may need to follow more users or tune your
-        language settings.
+        <Trans>
+          This feed is empty! You may need to follow more users or tune your
+          language settings.
+        </Trans>
       </Text>
       <Button
         type="inverted"
         style={styles.emptyBtn}
         onPress={onPressFindAccounts}>
         <Text type="lg-medium" style={palInverted.text}>
-          Find accounts to follow
+          <Trans>Find accounts to follow</Trans>
         </Text>
         <FontAwesomeIcon
           icon="angle-right"
diff --git a/src/view/com/posts/DiscoverFallbackHeader.tsx b/src/view/com/posts/DiscoverFallbackHeader.tsx
new file mode 100644
index 000000000..ffde89997
--- /dev/null
+++ b/src/view/com/posts/DiscoverFallbackHeader.tsx
@@ -0,0 +1,43 @@
+import React from 'react'
+import {View} from 'react-native'
+import {Trans} from '@lingui/macro'
+import {Text} from '../util/text/Text'
+import {usePalette} from '#/lib/hooks/usePalette'
+import {TextLink} from '../util/Link'
+import {InfoCircleIcon} from '#/lib/icons'
+
+export function DiscoverFallbackHeader() {
+  const pal = usePalette('default')
+  return (
+    <View
+      style={[
+        {
+          flexDirection: 'row',
+          alignItems: 'center',
+          paddingVertical: 12,
+          paddingHorizontal: 12,
+          borderTopWidth: 1,
+        },
+        pal.border,
+        pal.viewLight,
+      ]}>
+      <View style={{width: 68, paddingLeft: 12}}>
+        <InfoCircleIcon size={36} style={pal.textLight} strokeWidth={1.5} />
+      </View>
+      <View style={{flex: 1}}>
+        <Text type="md" style={pal.text}>
+          <Trans>
+            We ran out of posts from your follows. Here's the latest from{' '}
+            <TextLink
+              type="md-medium"
+              href="/profile/bsky.app/feed/whats-hot"
+              text="Discover"
+              style={pal.link}
+            />
+            .
+          </Trans>
+        </Text>
+      </View>
+    </View>
+  )
+}
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index 02a3537eb..04753fe6c 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -28,13 +28,18 @@ import {isWeb} from '#/platform/detection'
 import {listenPostCreated} from '#/state/events'
 import {useSession} from '#/state/session'
 import {STALE} from '#/state/queries'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {DiscoverFallbackHeader} from './DiscoverFallbackHeader'
+import {FALLBACK_MARKER_POST} from '#/lib/api/feed/home'
 
 const LOADING_ITEM = {_reactKey: '__loading__'}
 const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
 const ERROR_ITEM = {_reactKey: '__error__'}
 const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
 
-const REFRESH_AFTER = STALE.HOURS.ONE
+// DISABLED need to check if this is causing random feed refreshes -prf
+// const REFRESH_AFTER = STALE.HOURS.ONE
 const CHECK_LATEST_AFTER = STALE.SECONDS.THIRTY
 
 let Feed = ({
@@ -44,6 +49,7 @@ let Feed = ({
   style,
   enabled,
   pollInterval,
+  disablePoll,
   scrollElRef,
   onScrolledDownChange,
   onHasNew,
@@ -61,6 +67,7 @@ let Feed = ({
   style?: StyleProp<ViewStyle>
   enabled?: boolean
   pollInterval?: number
+  disablePoll?: boolean
   scrollElRef?: ListRef
   onHasNew?: (v: boolean) => void
   onScrolledDownChange?: (isScrolledDown: boolean) => void
@@ -74,6 +81,7 @@ let Feed = ({
 }): React.ReactNode => {
   const theme = useTheme()
   const {track} = useAnalytics()
+  const {_} = useLingui()
   const queryClient = useQueryClient()
   const {currentAccount} = useSession()
   const [isPTRing, setIsPTRing] = React.useState(false)
@@ -104,7 +112,7 @@ let Feed = ({
   )
 
   const checkForNew = React.useCallback(async () => {
-    if (!data?.pages[0] || isFetching || !onHasNew || !enabled) {
+    if (!data?.pages[0] || isFetching || !onHasNew || !enabled || disablePoll) {
       return
     }
     try {
@@ -114,7 +122,7 @@ let Feed = ({
     } catch (e) {
       logger.error('Poll latest failed', {feed, error: String(e)})
     }
-  }, [feed, data, isFetching, onHasNew, enabled])
+  }, [feed, data, isFetching, onHasNew, enabled, disablePoll])
 
   const myDid = currentAccount?.did || ''
   const onPostCreated = React.useCallback(() => {
@@ -143,11 +151,12 @@ let Feed = ({
   React.useEffect(() => {
     if (enabled) {
       const timeSinceFirstLoad = Date.now() - lastFetchRef.current
-      if (timeSinceFirstLoad > REFRESH_AFTER) {
+      // DISABLED need to check if this is causing random feed refreshes -prf
+      /*if (timeSinceFirstLoad > REFRESH_AFTER) {
         // do a full refresh
         scrollElRef?.current?.scrollToOffset({offset: 0, animated: false})
         queryClient.resetQueries({queryKey: RQKEY(feed)})
-      } else if (
+      } else*/ if (
         timeSinceFirstLoad > CHECK_LATEST_AFTER &&
         checkForNewRef.current
       ) {
@@ -250,16 +259,24 @@ let Feed = ({
       } else if (item === LOAD_MORE_ERROR_ITEM) {
         return (
           <LoadMoreRetryBtn
-            label="There was an issue fetching posts. Tap here to try again."
+            label={_(
+              msg`There was an issue fetching posts. Tap here to try again.`,
+            )}
             onPress={onPressRetryLoadMore}
           />
         )
       } else if (item === LOADING_ITEM) {
         return <PostFeedLoadingPlaceholder />
+      } else if (item.rootUri === FALLBACK_MARKER_POST.post.uri) {
+        // HACK
+        // tell the user we fell back to discover
+        // see home.ts (feed api) for more info
+        // -prf
+        return <DiscoverFallbackHeader />
       }
       return <FeedSlice slice={item} />
     },
-    [feed, error, onPressTryAgain, onPressRetryLoadMore, renderEmptyState],
+    [feed, error, onPressTryAgain, onPressRetryLoadMore, renderEmptyState, _],
   )
 
   const shouldRenderEndOfFeed =
diff --git a/src/view/com/posts/FeedErrorMessage.tsx b/src/view/com/posts/FeedErrorMessage.tsx
index aeac45980..48ed49bb1 100644
--- a/src/view/com/posts/FeedErrorMessage.tsx
+++ b/src/view/com/posts/FeedErrorMessage.tsx
@@ -38,6 +38,7 @@ export function FeedErrorMessage({
   error?: Error
   onPressTryAgain: () => void
 }) {
+  const {_: _l} = useLingui()
   const knownError = React.useMemo(
     () => detectKnownError(feedDesc, error),
     [feedDesc, error],
@@ -60,7 +61,7 @@ export function FeedErrorMessage({
     return (
       <EmptyState
         icon="ban"
-        message="Posts hidden"
+        message={_l(msgLingui`Posts hidden`)}
         style={{paddingVertical: 40}}
       />
     )
@@ -134,7 +135,9 @@ function FeedgenErrorMessage({
           await removeFeed({uri})
         } catch (err) {
           Toast.show(
-            'There was an an issue removing this feed. Please check your internet connection and try again.',
+            _l(
+              msgLingui`There was an an issue removing this feed. Please check your internet connection and try again.`,
+            ),
           )
           logger.error('Failed to remove feed', {error: err})
         }
@@ -160,20 +163,20 @@ function FeedgenErrorMessage({
             {knownError === KnownError.FeedgenDoesNotExist && (
               <Button
                 type="inverted"
-                label="Remove feed"
+                label={_l(msgLingui`Remove feed`)}
                 onPress={onRemoveFeed}
               />
             )}
             <Button
               type="default-light"
-              label="View profile"
+              label={_l(msgLingui`View profile`)}
               onPress={onViewProfile}
             />
           </View>
         )
       }
     }
-  }, [knownError, onViewProfile, onRemoveFeed])
+  }, [knownError, onViewProfile, onRemoveFeed, _l])
 
   return (
     <View
@@ -191,7 +194,7 @@ function FeedgenErrorMessage({
 
       {rawError?.message && (
         <Text style={pal.textLight}>
-          <Trans>Message from server</Trans>: {rawError.message}
+          <Trans>Message from server: {rawError.message}</Trans>
         </Text>
       )}
 
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index 942d7bf71..225607ca9 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -35,6 +35,8 @@ import {useComposerControls} from '#/state/shell/composer'
 import {Shadow, usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
 import {FeedNameText} from '../util/FeedInfoText'
 import {useSession} from '#/state/session'
+import {Trans, msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 export function FeedItem({
   post,
@@ -103,6 +105,7 @@ let FeedItemInner = ({
 }): React.ReactNode => {
   const {openComposer} = useComposerControls()
   const pal = usePalette('default')
+  const {_} = useLingui()
   const {currentAccount} = useSession()
   const href = useMemo(() => {
     const urip = new AtUri(post.uri)
@@ -131,6 +134,7 @@ let FeedItemInner = ({
           displayName: post.author.displayName,
           avatar: post.author.avatar,
         },
+        embed: post.embed,
       },
     })
   }, [post, record, openComposer])
@@ -181,24 +185,28 @@ let FeedItemInner = ({
                 style={pal.textLight}
                 lineHeight={1.2}
                 numberOfLines={1}>
-                From{' '}
-                <FeedNameText
-                  type="sm-bold"
-                  uri={reason.uri}
-                  href={reason.href}
-                  lineHeight={1.2}
-                  numberOfLines={1}
-                  style={pal.textLight}
-                />
+                <Trans context="from-feed">
+                  From{' '}
+                  <FeedNameText
+                    type="sm-bold"
+                    uri={reason.uri}
+                    href={reason.href}
+                    lineHeight={1.2}
+                    numberOfLines={1}
+                    style={pal.textLight}
+                  />
+                </Trans>
               </Text>
             </Link>
           ) : AppBskyFeedDefs.isReasonRepost(reason) ? (
             <Link
               style={styles.includeReason}
               href={makeProfileLink(reason.by)}
-              title={`Reposted by ${sanitizeDisplayName(
-                reason.by.displayName || reason.by.handle,
-              )}`}>
+              title={_(
+                msg`Reposted by ${sanitizeDisplayName(
+                  reason.by.displayName || reason.by.handle,
+                )}`,
+              )}>
               <FontAwesomeIcon
                 icon="retweet"
                 style={{
@@ -212,17 +220,19 @@ let FeedItemInner = ({
                 style={pal.textLight}
                 lineHeight={1.2}
                 numberOfLines={1}>
-                Reposted by{' '}
-                <TextLinkOnWebOnly
-                  type="sm-bold"
-                  style={pal.textLight}
-                  lineHeight={1.2}
-                  numberOfLines={1}
-                  text={sanitizeDisplayName(
-                    reason.by.displayName || sanitizeHandle(reason.by.handle),
-                  )}
-                  href={makeProfileLink(reason.by)}
-                />
+                <Trans>
+                  Reposted by{' '}
+                  <TextLinkOnWebOnly
+                    type="sm-bold"
+                    style={pal.textLight}
+                    lineHeight={1.2}
+                    numberOfLines={1}
+                    text={sanitizeDisplayName(
+                      reason.by.displayName || sanitizeHandle(reason.by.handle),
+                    )}
+                    href={makeProfileLink(reason.by)}
+                  />
+                </Trans>
               </Text>
             </Link>
           ) : null}
@@ -273,13 +283,15 @@ let FeedItemInner = ({
                 style={[pal.textLight, s.mr2]}
                 lineHeight={1.2}
                 numberOfLines={1}>
-                Reply to{' '}
-                <UserInfoText
-                  type="md"
-                  did={replyAuthorDid}
-                  attr="displayName"
-                  style={[pal.textLight, s.ml2]}
-                />
+                <Trans context="description">
+                  Reply to{' '}
+                  <UserInfoText
+                    type="md"
+                    did={replyAuthorDid}
+                    attr="displayName"
+                    style={[pal.textLight]}
+                  />
+                </Trans>
               </Text>
             </View>
           )}
@@ -292,6 +304,7 @@ let FeedItemInner = ({
           <PostCtrls
             post={post}
             record={record}
+            richText={richText}
             onPressReply={onPressReply}
             showAppealLabelItem={
               post.author.did === currentAccount?.did && isModeratedPost
@@ -316,6 +329,7 @@ let PostContent = ({
   postAuthor: AppBskyFeedDefs.PostView['author']
 }): React.ReactNode => {
   const pal = usePalette('default')
+  const {_} = useLingui()
   const [limitLines, setLimitLines] = useState(
     () => countLines(richText.text) >= MAX_POST_LINES,
   )
@@ -345,7 +359,7 @@ let PostContent = ({
       ) : undefined}
       {limitLines ? (
         <TextLink
-          text="Show More"
+          text={_(msg`Show More`)}
           style={pal.link}
           onPress={onPressShowMore}
           href="#"
diff --git a/src/view/com/posts/FeedSlice.tsx b/src/view/com/posts/FeedSlice.tsx
index c1a8c0e18..84edee4a1 100644
--- a/src/view/com/posts/FeedSlice.tsx
+++ b/src/view/com/posts/FeedSlice.tsx
@@ -8,6 +8,7 @@ import Svg, {Circle, Line} from 'react-native-svg'
 import {FeedItem} from './FeedItem'
 import {usePalette} from 'lib/hooks/usePalette'
 import {makeProfileLink} from 'lib/routes/links'
+import {Trans} from '@lingui/macro'
 
 let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
   if (slice.isThread && slice.items.length > 3) {
@@ -99,7 +100,7 @@ function ViewFullThread({slice}: {slice: FeedPostSlice}) {
       </View>
 
       <Text type="md" style={[pal.link, {paddingTop: 18, paddingBottom: 4}]}>
-        View full thread
+        <Trans>View full thread</Trans>
       </Text>
     </Link>
   )
diff --git a/src/view/com/posts/FollowingEmptyState.tsx b/src/view/com/posts/FollowingEmptyState.tsx
index aac29603d..ef02039af 100644
--- a/src/view/com/posts/FollowingEmptyState.tsx
+++ b/src/view/com/posts/FollowingEmptyState.tsx
@@ -12,6 +12,7 @@ import {NavigationProp} from 'lib/routes/types'
 import {usePalette} from 'lib/hooks/usePalette'
 import {s} from 'lib/styles'
 import {isWeb} from 'platform/detection'
+import {Trans} from '@lingui/macro'
 
 export function FollowingEmptyState() {
   const pal = usePalette('default')
@@ -43,15 +44,17 @@ export function FollowingEmptyState() {
           <MagnifyingGlassIcon style={[styles.icon, pal.text]} size={62} />
         </View>
         <Text type="xl-medium" style={[s.textCenter, pal.text]}>
-          Your following feed is empty! Follow more users to see what's
-          happening.
+          <Trans>
+            Your following feed is empty! Follow more users to see what's
+            happening.
+          </Trans>
         </Text>
         <Button
           type="inverted"
           style={styles.emptyBtn}
           onPress={onPressFindAccounts}>
           <Text type="lg-medium" style={palInverted.text}>
-            Find accounts to follow
+            <Trans>Find accounts to follow</Trans>
           </Text>
           <FontAwesomeIcon
             icon="angle-right"
@@ -61,14 +64,14 @@ export function FollowingEmptyState() {
         </Button>
 
         <Text type="xl-medium" style={[s.textCenter, pal.text, s.mt20]}>
-          You can also discover new Custom Feeds to follow.
+          <Trans>You can also discover new Custom Feeds to follow.</Trans>
         </Text>
         <Button
           type="inverted"
           style={[styles.emptyBtn, s.mt10]}
           onPress={onPressDiscoverFeeds}>
           <Text type="lg-medium" style={palInverted.text}>
-            Discover new custom feeds
+            <Trans>Discover new custom feeds</Trans>
           </Text>
           <FontAwesomeIcon
             icon="angle-right"
diff --git a/src/view/com/posts/FollowingEndOfFeed.tsx b/src/view/com/posts/FollowingEndOfFeed.tsx
index 3f1297547..bea5bedea 100644
--- a/src/view/com/posts/FollowingEndOfFeed.tsx
+++ b/src/view/com/posts/FollowingEndOfFeed.tsx
@@ -11,6 +11,7 @@ import {NavigationProp} from 'lib/routes/types'
 import {usePalette} from 'lib/hooks/usePalette'
 import {s} from 'lib/styles'
 import {isWeb} from 'platform/detection'
+import {Trans} from '@lingui/macro'
 
 export function FollowingEndOfFeed() {
   const pal = usePalette('default')
@@ -44,15 +45,17 @@ export function FollowingEndOfFeed() {
       ]}>
       <View style={styles.inner}>
         <Text type="xl-medium" style={[s.textCenter, pal.text]}>
-          You've reached the end of your feed! Find some more accounts to
-          follow.
+          <Trans>
+            You've reached the end of your feed! Find some more accounts to
+            follow.
+          </Trans>
         </Text>
         <Button
           type="inverted"
           style={styles.emptyBtn}
           onPress={onPressFindAccounts}>
           <Text type="lg-medium" style={palInverted.text}>
-            Find accounts to follow
+            <Trans>Find accounts to follow</Trans>
           </Text>
           <FontAwesomeIcon
             icon="angle-right"
@@ -62,14 +65,14 @@ export function FollowingEndOfFeed() {
         </Button>
 
         <Text type="xl-medium" style={[s.textCenter, pal.text, s.mt20]}>
-          You can also discover new Custom Feeds to follow.
+          <Trans>You can also discover new Custom Feeds to follow.</Trans>
         </Text>
         <Button
           type="inverted"
           style={[styles.emptyBtn, s.mt10]}
           onPress={onPressDiscoverFeeds}>
           <Text type="lg-medium" style={palInverted.text}>
-            Discover new custom feeds
+            <Trans>Discover new custom feeds</Trans>
           </Text>
           <FontAwesomeIcon
             icon="angle-right"