about summary refs log tree commit diff
path: root/src/view/screens/Home.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/screens/Home.tsx')
-rw-r--r--src/view/screens/Home.tsx284
1 files changed, 154 insertions, 130 deletions
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index c58175327..e8001e973 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -1,154 +1,178 @@
 import React from 'react'
-import {useWindowDimensions} from 'react-native'
-import {useFocusEffect} from '@react-navigation/native'
-import {observer} from 'mobx-react-lite'
-import isEqual from 'lodash.isequal'
+import {View, ActivityIndicator, StyleSheet} from 'react-native'
+import {useFocusEffect, useIsFocused} from '@react-navigation/native'
 import {NativeStackScreenProps, HomeTabNavigatorParams} from 'lib/routes/types'
-import {PostsFeedModel} from 'state/models/feeds/posts'
-import {withAuthRequired} from 'view/com/auth/withAuthRequired'
+import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
 import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState'
 import {FollowingEndOfFeed} from 'view/com/posts/FollowingEndOfFeed'
 import {CustomFeedEmptyState} from 'view/com/posts/CustomFeedEmptyState'
 import {FeedsTabBar} from '../com/pager/FeedsTabBar'
-import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
-import {useStores} from 'state/index'
-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {Pager, RenderTabBarFnProps} from 'view/com/pager/Pager'
 import {FeedPage} from 'view/com/feeds/FeedPage'
 import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell'
-
-export const POLL_FREQ = 30e3 // 30sec
+import {usePreferencesQuery} from '#/state/queries/preferences'
+import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
+import {emitSoftReset} from '#/state/events'
+import {useSession} from '#/state/session'
 
 type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
-export const HomeScreen = withAuthRequired(
-  observer(function HomeScreenImpl({}: Props) {
-    const store = useStores()
-    const setMinimalShellMode = useSetMinimalShellMode()
-    const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
-    const pagerRef = React.useRef<PagerRef>(null)
-    const [selectedPage, setSelectedPage] = React.useState(0)
-    const [customFeeds, setCustomFeeds] = React.useState<PostsFeedModel[]>([])
-    const [requestedCustomFeeds, setRequestedCustomFeeds] = React.useState<
-      string[]
-    >([])
+export function HomeScreen(props: Props) {
+  const {data: preferences} = usePreferencesQuery()
+
+  if (preferences) {
+    return <HomeScreenReady {...props} preferences={preferences} />
+  } else {
+    return (
+      <View style={styles.loading}>
+        <ActivityIndicator size="large" />
+      </View>
+    )
+  }
+}
+
+function HomeScreenReady({
+  preferences,
+}: Props & {
+  preferences: UsePreferencesQueryResponse
+}) {
+  const {hasSession} = useSession()
+  const setMinimalShellMode = useSetMinimalShellMode()
+  const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
+  const [selectedPage, setSelectedPage] = React.useState(0)
+  const isPageFocused = useIsFocused()
 
-    React.useEffect(() => {
-      const pinned = store.preferences.pinnedFeeds
+  /**
+   * 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)
 
-      if (isEqual(pinned, requestedCustomFeeds)) {
-        // no changes
-        return
+  const customFeeds = React.useMemo(() => {
+    const pinned = preferences.feeds.pinned
+    const feeds: FeedDescriptor[] = []
+    for (const uri of pinned) {
+      if (uri.includes('app.bsky.feed.generator')) {
+        feeds.push(`feedgen|${uri}`)
+      } else if (uri.includes('app.bsky.graph.list')) {
+        feeds.push(`list|${uri}`)
       }
+    }
+    return feeds
+  }, [preferences.feeds.pinned])
 
-      const feeds = []
-      for (const uri of pinned) {
-        if (uri.includes('app.bsky.feed.generator')) {
-          const model = new PostsFeedModel(store, 'custom', {feed: uri})
-          feeds.push(model)
-        } else if (uri.includes('app.bsky.graph.list')) {
-          const model = new PostsFeedModel(store, 'list', {list: uri})
-          feeds.push(model)
-        }
+  const homeFeedParams = React.useMemo<FeedParams>(() => {
+    return {
+      mergeFeedEnabled: Boolean(preferences.feedViewPrefs.lab_mergeFeedEnabled),
+      mergeFeedSources: preferences.feeds.saved,
+    }
+  }, [preferences])
+
+  useFocusEffect(
+    React.useCallback(() => {
+      setMinimalShellMode(false)
+      setDrawerSwipeDisabled(selectedPage > 0)
+      return () => {
+        setDrawerSwipeDisabled(false)
       }
-      pagerRef.current?.setPage(0)
-      setCustomFeeds(feeds)
-      setRequestedCustomFeeds(pinned)
-    }, [
-      store,
-      store.preferences.pinnedFeeds,
-      customFeeds,
-      setCustomFeeds,
-      pagerRef,
-      requestedCustomFeeds,
-      setRequestedCustomFeeds,
-    ])
+    }, [setDrawerSwipeDisabled, selectedPage, setMinimalShellMode]),
+  )
 
-    useFocusEffect(
-      React.useCallback(() => {
-        setMinimalShellMode(false)
-        setDrawerSwipeDisabled(selectedPage > 0)
-        return () => {
-          setDrawerSwipeDisabled(false)
-        }
-      }, [setDrawerSwipeDisabled, selectedPage, setMinimalShellMode]),
-    )
+  const onPageSelected = React.useCallback(
+    (index: number) => {
+      setMinimalShellMode(false)
+      setSelectedPage(index)
+      setDrawerSwipeDisabled(index > 0)
+    },
+    [setDrawerSwipeDisabled, setSelectedPage, setMinimalShellMode],
+  )
+
+  const onPressSelected = React.useCallback(() => {
+    emitSoftReset()
+  }, [])
 
-    const onPageSelected = React.useCallback(
-      (index: number) => {
+  const onPageScrollStateChanged = React.useCallback(
+    (state: 'idle' | 'dragging' | 'settling') => {
+      if (state === 'dragging') {
         setMinimalShellMode(false)
-        setSelectedPage(index)
-        setDrawerSwipeDisabled(index > 0)
-      },
-      [setDrawerSwipeDisabled, setSelectedPage, setMinimalShellMode],
-    )
+      }
+    },
+    [setMinimalShellMode],
+  )
 
-    const onPressSelected = React.useCallback(() => {
-      store.emitScreenSoftReset()
-    }, [store])
+  const renderTabBar = React.useCallback(
+    (props: RenderTabBarFnProps) => {
+      return (
+        <FeedsTabBar
+          key="FEEDS_TAB_BAR"
+          selectedPage={props.selectedPage}
+          onSelect={props.onSelect}
+          testID="homeScreenFeedTabs"
+          onPressSelected={onPressSelected}
+        />
+      )
+    },
+    [onPressSelected],
+  )
 
-    const renderTabBar = React.useCallback(
-      (props: RenderTabBarFnProps) => {
+  const renderFollowingEmptyState = React.useCallback(() => {
+    return <FollowingEmptyState />
+  }, [])
+
+  const renderCustomFeedEmptyState = React.useCallback(() => {
+    return <CustomFeedEmptyState />
+  }, [])
+
+  return hasSession ? (
+    <Pager
+      key={pinnedFeedOrderKey}
+      testID="homeScreen"
+      onPageSelected={onPageSelected}
+      onPageScrollStateChanged={onPageScrollStateChanged}
+      renderTabBar={renderTabBar}
+      tabBarPosition="top">
+      <FeedPage
+        key="1"
+        testID="followingFeedPage"
+        isPageFocused={selectedPage === 0 && isPageFocused}
+        feed={homeFeedParams.mergeFeedEnabled ? 'home' : 'following'}
+        feedParams={homeFeedParams}
+        renderEmptyState={renderFollowingEmptyState}
+        renderEndOfFeed={FollowingEndOfFeed}
+      />
+      {customFeeds.map((f, index) => {
         return (
-          <FeedsTabBar
-            key="FEEDS_TAB_BAR"
-            selectedPage={props.selectedPage}
-            onSelect={props.onSelect}
-            testID="homeScreenFeedTabs"
-            onPressSelected={onPressSelected}
+          <FeedPage
+            key={f}
+            testID="customFeedPage"
+            isPageFocused={selectedPage === 1 + index && isPageFocused}
+            feed={f}
+            renderEmptyState={renderCustomFeedEmptyState}
           />
         )
-      },
-      [onPressSelected],
-    )
-
-    const renderFollowingEmptyState = React.useCallback(() => {
-      return <FollowingEmptyState />
-    }, [])
-
-    const renderCustomFeedEmptyState = React.useCallback(() => {
-      return <CustomFeedEmptyState />
-    }, [])
-
-    return (
-      <Pager
-        ref={pagerRef}
-        testID="homeScreen"
-        onPageSelected={onPageSelected}
-        renderTabBar={renderTabBar}
-        tabBarPosition="top">
-        <FeedPage
-          key="1"
-          testID="followingFeedPage"
-          isPageFocused={selectedPage === 0}
-          feed={store.me.mainFeed}
-          renderEmptyState={renderFollowingEmptyState}
-          renderEndOfFeed={FollowingEndOfFeed}
-        />
-        {customFeeds.map((f, index) => {
-          return (
-            <FeedPage
-              key={f.reactKey}
-              testID="customFeedPage"
-              isPageFocused={selectedPage === 1 + index}
-              feed={f}
-              renderEmptyState={renderCustomFeedEmptyState}
-            />
-          )
-        })}
-      </Pager>
-    )
-  }),
-)
-
-export function useHeaderOffset() {
-  const {isDesktop, isTablet} = useWebMediaQueries()
-  const {fontScale} = useWindowDimensions()
-  if (isDesktop) {
-    return 0
-  }
-  if (isTablet) {
-    return 50
-  }
-  // default text takes 44px, plus 34px of pad
-  // scale the 44px by the font scale
-  return 34 + 44 * fontScale
+      })}
+    </Pager>
+  ) : (
+    <Pager
+      testID="homeScreen"
+      onPageSelected={onPageSelected}
+      onPageScrollStateChanged={onPageScrollStateChanged}
+      renderTabBar={renderTabBar}
+      tabBarPosition="top">
+      <FeedPage
+        testID="customFeedPage"
+        isPageFocused={isPageFocused}
+        feed={`feedgen|at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot`}
+        renderEmptyState={renderCustomFeedEmptyState}
+      />
+    </Pager>
+  )
 }
+
+const styles = StyleSheet.create({
+  loading: {
+    height: '100%',
+    alignContent: 'center',
+    justifyContent: 'center',
+    paddingBottom: 100,
+  },
+})