about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2024-01-15 15:03:54 -0800
committerGitHub <noreply@github.com>2024-01-15 15:03:54 -0800
commita7d617c7a616b6f6a8e0db41f02e052d6bd077e8 (patch)
treeb20cc4ad13db4ba3813e791b534731af1dfc652e /src
parent7df0b7ade14cc8015996cb23f052066b7ae3131b (diff)
downloadvoidsky-a7d617c7a616b6f6a8e0db41f02e052d6bd077e8.tar.zst
Add a new home feed-api wrapper and give a header indicating the fallback behavior (#2534)
* Add a new home feed-api wrapper and give a header indicating the fallback behavior

* Sneak in a quick fix: use the correct text color in the delete modal

* Use imported constant
Diffstat (limited to 'src')
-rw-r--r--src/lib/api/feed/home.ts88
-rw-r--r--src/lib/api/feed/merge.ts2
-rw-r--r--src/state/queries/post-feed.ts7
-rw-r--r--src/view/com/modals/DeleteAccount.tsx7
-rw-r--r--src/view/com/posts/DiscoverFallbackHeader.tsx43
-rw-r--r--src/view/com/posts/Feed.tsx8
-rw-r--r--src/view/screens/Home.tsx3
7 files changed, 152 insertions, 6 deletions
diff --git a/src/lib/api/feed/home.ts b/src/lib/api/feed/home.ts
new file mode 100644
index 000000000..91634927a
--- /dev/null
+++ b/src/lib/api/feed/home.ts
@@ -0,0 +1,88 @@
+import {AppBskyFeedDefs} from '@atproto/api'
+import {FeedAPI, FeedAPIResponse} from './types'
+import {FollowingFeedAPI} from './following'
+import {CustomFeedAPI} from './custom'
+import {PROD_DEFAULT_FEED} from '#/lib/constants'
+
+// HACK
+// the feed API does not include any facilities for passing down
+// non-post elements. adding that is a bit of a heavy lift, and we
+// have just one temporary usecase for it: flagging when the home feed
+// falls back to discover.
+// we use this fallback marker post to drive this instead. see Feed.tsx
+// for the usage.
+// -prf
+export const FALLBACK_MARKER_POST: AppBskyFeedDefs.FeedViewPost = {
+  post: {
+    uri: 'fallback-marker-post',
+    cid: 'fake',
+    record: {},
+    author: {
+      did: 'did:fake',
+      handle: 'fake.com',
+    },
+    indexedAt: new Date().toISOString(),
+  },
+}
+
+export class HomeFeedAPI implements FeedAPI {
+  following: FollowingFeedAPI
+  discover: CustomFeedAPI
+  usingDiscover = false
+  itemCursor = 0
+
+  constructor() {
+    this.following = new FollowingFeedAPI()
+    this.discover = new CustomFeedAPI({feed: PROD_DEFAULT_FEED('whats-hot')})
+  }
+
+  reset() {
+    this.following = new FollowingFeedAPI()
+    this.discover = new CustomFeedAPI({feed: PROD_DEFAULT_FEED('whats-hot')})
+    this.usingDiscover = false
+    this.itemCursor = 0
+  }
+
+  async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> {
+    if (this.usingDiscover) {
+      return this.discover.peekLatest()
+    }
+    return this.following.peekLatest()
+  }
+
+  async fetch({
+    cursor,
+    limit,
+  }: {
+    cursor: string | undefined
+    limit: number
+  }): Promise<FeedAPIResponse> {
+    if (!cursor) {
+      this.reset()
+    }
+
+    let returnCursor
+    let posts: AppBskyFeedDefs.FeedViewPost[] = []
+
+    if (!this.usingDiscover) {
+      const res = await this.following.fetch({cursor, limit})
+      returnCursor = res.cursor
+      posts = posts.concat(res.feed)
+      if (res.feed.length === 0 || !cursor) {
+        posts.push(FALLBACK_MARKER_POST)
+        this.usingDiscover = true
+      }
+    }
+
+    if (this.usingDiscover) {
+      const res = await this.discover.fetch({cursor, limit})
+      returnCursor = res.cursor
+      posts = posts.concat(res.feed)
+    }
+
+    return {
+      cursor: returnCursor,
+      feed: posts,
+    }
+  }
+}
diff --git a/src/lib/api/feed/merge.ts b/src/lib/api/feed/merge.ts
index 2fef9db87..28bf143cb 100644
--- a/src/lib/api/feed/merge.ts
+++ b/src/lib/api/feed/merge.ts
@@ -26,7 +26,7 @@ export class MergeFeedAPI implements FeedAPI {
 
   reset() {
     this.following = new MergeFeedSource_Following(this.feedTuners)
-    this.customFeeds = [] // just empty the array, they will be captured in _fetchNext()
+    this.customFeeds = []
     this.feedCursor = 0
     this.itemCursor = 0
     this.sampleCursor = 0
diff --git a/src/state/queries/post-feed.ts b/src/state/queries/post-feed.ts
index dbb729133..82acf3974 100644
--- a/src/state/queries/post-feed.ts
+++ b/src/state/queries/post-feed.ts
@@ -18,6 +18,7 @@ import {LikesFeedAPI} from 'lib/api/feed/likes'
 import {CustomFeedAPI} from 'lib/api/feed/custom'
 import {ListFeedAPI} from 'lib/api/feed/list'
 import {MergeFeedAPI} from 'lib/api/feed/merge'
+import {HomeFeedAPI} from '#/lib/api/feed/home'
 import {logger} from '#/logger'
 import {STALE} from '#/state/queries'
 import {precacheFeedPosts as precacheResolvedUris} from './resolve-uri'
@@ -338,7 +339,11 @@ function createApi(
   feedTuners: FeedTunerFn[],
 ) {
   if (feedDesc === 'home') {
-    return new MergeFeedAPI(params, feedTuners)
+    if (params.mergeFeedEnabled) {
+      return new MergeFeedAPI(params, feedTuners)
+    } else {
+      return new HomeFeedAPI()
+    }
   } else if (feedDesc === 'following') {
     return new FollowingFeedAPI()
   } else if (feedDesc.startsWith('author')) {
diff --git a/src/view/com/modals/DeleteAccount.tsx b/src/view/com/modals/DeleteAccount.tsx
index 0cfc098d4..945d7bc89 100644
--- a/src/view/com/modals/DeleteAccount.tsx
+++ b/src/view/com/modals/DeleteAccount.tsx
@@ -160,7 +160,7 @@ export function Component({}: {}) {
             {/* TODO: Update this label to be more concise */}
             <Text
               type="lg"
-              style={styles.description}
+              style={[pal.text, styles.description]}
               nativeID="confirmationCode">
               <Trans>
                 Check your inbox for an email with the confirmation code to
@@ -180,7 +180,10 @@ export function Component({}: {}) {
                 msg`Input confirmation code for account deletion`,
               )}
             />
-            <Text type="lg" style={styles.description} nativeID="password">
+            <Text
+              type="lg"
+              style={[pal.text, styles.description]}
+              nativeID="password">
               <Trans>Please enter your password as well:</Trans>
             </Text>
             <TextInput
diff --git a/src/view/com/posts/DiscoverFallbackHeader.tsx b/src/view/com/posts/DiscoverFallbackHeader.tsx
new file mode 100644
index 000000000..dcfa3b012
--- /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
+          </Trans>{' '}
+          <TextLink
+            type="md-medium"
+            href="/profile/bsky.app/feed/whats-hot"
+            text="Discover"
+            style={pal.link}
+          />
+          .
+        </Text>
+      </View>
+    </View>
+  )
+}
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index cd9f26463..04753fe6c 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -30,6 +30,8 @@ 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__'}
@@ -265,6 +267,12 @@ let Feed = ({
         )
       } 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} />
     },
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 0e20a9cf7..7d6a40f02 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -19,7 +19,6 @@ import {useSession} from '#/state/session'
 import {loadString, saveString} from '#/lib/storage'
 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
 import {clamp} from '#/lib/numbers'
-import {PROD_DEFAULT_FEED} from '#/lib/constants'
 
 type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
 export function HomeScreen(props: Props) {
@@ -112,7 +111,7 @@ function HomeScreenReady({
       mergeFeedEnabled: Boolean(preferences.feedViewPrefs.lab_mergeFeedEnabled),
       mergeFeedSources: preferences.feedViewPrefs.lab_mergeFeedEnabled
         ? preferences.feeds.saved
-        : [PROD_DEFAULT_FEED('whats-hot')],
+        : [],
     }
   }, [preferences])