about summary refs log tree commit diff
path: root/src/view/screens/Home.tsx
diff options
context:
space:
mode:
authordan <dan.abramov@gmail.com>2024-02-07 02:50:44 +0000
committerGitHub <noreply@github.com>2024-02-06 18:50:44 -0800
commit4583521b119983b2a00cd2133741644c8caa44d9 (patch)
treeaa3e9d08704980c8c2442e59e56798083fd279e7 /src/view/screens/Home.tsx
parentf393dda5281ada502327961ad55605cdbeed3c7e (diff)
downloadvoidsky-4583521b119983b2a00cd2133741644c8caa44d9.tar.zst
Refactor Home feed pager rendering logic (#2768)
* Use new persistence API for selected feed

* Refactor Home feeds pager data source
Diffstat (limited to 'src/view/screens/Home.tsx')
-rw-r--r--src/view/screens/Home.tsx129
1 files changed, 48 insertions, 81 deletions
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 1da276488..7228a9e1b 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -16,45 +16,25 @@ import {usePinnedFeedsInfos, FeedSourceInfo} from '#/state/queries/feed'
 import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
 import {emitSoftReset} from '#/state/events'
 import {useSession} from '#/state/session'
-import {loadString, saveString} from '#/lib/storage'
 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
-import {clamp} from '#/lib/numbers'
+import * as persisted from '#/state/persisted'
 
 type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
 export function HomeScreen(props: Props) {
   const {data: preferences} = usePreferencesQuery()
-  const {feeds: pinnedFeeds, isLoading: isPinnedFeedsLoading} =
+  const {feeds: pinnedFeedInfos, isLoading: isPinnedFeedsLoading} =
     usePinnedFeedsInfos()
   const {isDesktop} = useWebMediaQueries()
-  const [initialPage, setInitialPage] = React.useState<string | undefined>(
-    undefined,
+  const [rawInitialFeed] = React.useState<string>(
+    () => persisted.get('lastSelectedHomeFeed') ?? 'home',
   )
-
-  React.useEffect(() => {
-    const loadLastActivePage = async () => {
-      try {
-        const lastActivePage =
-          (await loadString('lastActivePage')) ?? 'Following'
-        setInitialPage(lastActivePage)
-      } catch {
-        setInitialPage('Following')
-      }
-    }
-    loadLastActivePage()
-  }, [])
-
-  if (
-    preferences &&
-    pinnedFeeds &&
-    initialPage !== undefined &&
-    !isPinnedFeedsLoading
-  ) {
+  if (preferences && pinnedFeedInfos && !isPinnedFeedsLoading) {
     return (
       <HomeScreenReady
         {...props}
         preferences={preferences}
-        pinnedFeeds={pinnedFeeds}
-        initialPage={isDesktop ? 'Following' : initialPage}
+        pinnedFeedInfos={pinnedFeedInfos}
+        rawInitialFeed={isDesktop ? 'home' : rawInitialFeed}
       />
     )
   } else {
@@ -68,35 +48,17 @@ export function HomeScreen(props: Props) {
 
 function HomeScreenReady({
   preferences,
-  pinnedFeeds,
-  initialPage,
+  pinnedFeedInfos,
+  rawInitialFeed,
 }: Props & {
   preferences: UsePreferencesQueryResponse
-  pinnedFeeds: FeedSourceInfo[]
-  initialPage: string
+  pinnedFeedInfos: FeedSourceInfo[]
+  rawInitialFeed: string
 }) {
-  const {hasSession} = useSession()
-  const setMinimalShellMode = useSetMinimalShellMode()
-  const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
-  const [selectedPage, setSelectedPage] = React.useState<string>(initialPage)
-
-  /**
-   * Used to ensure that we re-compute `customFeeds` AND force a re-render of
-   * the pager with the new order of feeds.
-   */
-  const pinnedFeedOrderKey = JSON.stringify(preferences.feeds.pinned)
-
-  const selectedPageIndex = React.useMemo(() => {
-    const index = ['Following', ...preferences.feeds.pinned].indexOf(
-      selectedPage,
-    )
-    return Math.max(index, 0)
-  }, [preferences.feeds.pinned, selectedPage])
-
-  const customFeeds = React.useMemo(() => {
-    const pinned = pinnedFeeds
+  const allFeeds = React.useMemo(() => {
     const feeds: FeedDescriptor[] = []
-    for (const {uri} of pinned) {
+    feeds.push('home')
+    for (const {uri} of pinnedFeedInfos) {
       if (uri.includes('app.bsky.feed.generator')) {
         feeds.push(`feedgen|${uri}`)
       } else if (uri.includes('app.bsky.graph.list')) {
@@ -104,41 +66,36 @@ function HomeScreenReady({
       }
     }
     return feeds
-  }, [pinnedFeeds])
+  }, [pinnedFeedInfos])
 
-  const homeFeedParams = React.useMemo<FeedParams>(() => {
-    return {
-      mergeFeedEnabled: Boolean(preferences.feedViewPrefs.lab_mergeFeedEnabled),
-      mergeFeedSources: preferences.feedViewPrefs.lab_mergeFeedEnabled
-        ? preferences.feeds.saved
-        : [],
-    }
-  }, [preferences])
+  const [rawSelectedFeed, setSelectedFeed] =
+    React.useState<string>(rawInitialFeed)
+  const maybeFoundIndex = allFeeds.indexOf(rawSelectedFeed as FeedDescriptor)
+  const selectedIndex = Math.max(0, maybeFoundIndex)
+  const selectedFeed = allFeeds[selectedIndex]
 
+  const {hasSession} = useSession()
+  const setMinimalShellMode = useSetMinimalShellMode()
+  const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
   useFocusEffect(
     React.useCallback(() => {
       setMinimalShellMode(false)
-      setDrawerSwipeDisabled(selectedPageIndex > 0)
+      setDrawerSwipeDisabled(selectedIndex > 0)
       return () => {
         setDrawerSwipeDisabled(false)
       }
-    }, [setDrawerSwipeDisabled, selectedPageIndex, setMinimalShellMode]),
+    }, [setDrawerSwipeDisabled, selectedIndex, setMinimalShellMode]),
   )
 
   const onPageSelected = React.useCallback(
     (index: number) => {
       setMinimalShellMode(false)
       setDrawerSwipeDisabled(index > 0)
-      const page = ['Following', ...preferences.feeds.pinned][index]
-      setSelectedPage(page)
-      saveString('lastActivePage', page)
+      const feed = allFeeds[index]
+      setSelectedFeed(feed)
+      persisted.write('lastSelectedHomeFeed', feed)
     },
-    [
-      setDrawerSwipeDisabled,
-      setSelectedPage,
-      setMinimalShellMode,
-      preferences.feeds.pinned,
-    ],
+    [setDrawerSwipeDisabled, setSelectedFeed, setMinimalShellMode, allFeeds],
   )
 
   const onPressSelected = React.useCallback(() => {
@@ -177,30 +134,40 @@ function HomeScreenReady({
     return <CustomFeedEmptyState />
   }, [])
 
+  const [homeFeed, ...customFeeds] = allFeeds
+  const homeFeedParams = React.useMemo<FeedParams>(() => {
+    return {
+      mergeFeedEnabled: Boolean(preferences.feedViewPrefs.lab_mergeFeedEnabled),
+      mergeFeedSources: preferences.feedViewPrefs.lab_mergeFeedEnabled
+        ? preferences.feeds.saved
+        : [],
+    }
+  }, [preferences])
+
   return hasSession ? (
     <Pager
-      key={pinnedFeedOrderKey}
+      key={allFeeds.join(',')}
       testID="homeScreen"
-      initialPage={clamp(selectedPageIndex, 0, customFeeds.length)}
+      initialPage={selectedIndex}
       onPageSelected={onPageSelected}
       onPageScrollStateChanged={onPageScrollStateChanged}
       renderTabBar={renderTabBar}>
       <FeedPage
-        key="1"
+        key={homeFeed}
         testID="followingFeedPage"
-        isPageFocused={selectedPageIndex === 0}
-        feed="home"
+        isPageFocused={selectedFeed === homeFeed}
+        feed={homeFeed}
         feedParams={homeFeedParams}
         renderEmptyState={renderFollowingEmptyState}
         renderEndOfFeed={FollowingEndOfFeed}
       />
-      {customFeeds.map((f, index) => {
+      {customFeeds.map(feed => {
         return (
           <FeedPage
-            key={f}
+            key={feed}
             testID="customFeedPage"
-            isPageFocused={selectedPageIndex === 1 + index}
-            feed={f}
+            isPageFocused={selectedFeed === feed}
+            feed={feed}
             renderEmptyState={renderCustomFeedEmptyState}
           />
         )