about summary refs log tree commit diff
path: root/src/view/screens
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/screens')
-rw-r--r--src/view/screens/Home.tsx9
-rw-r--r--src/view/screens/Profile.tsx19
-rw-r--r--src/view/screens/ProfileFeed.tsx7
-rw-r--r--src/view/screens/ProfileList.tsx55
4 files changed, 68 insertions, 22 deletions
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 6100d42db..d07fa0434 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -1,6 +1,6 @@
 import React from 'react'
 import {View, ActivityIndicator, StyleSheet} from 'react-native'
-import {useFocusEffect} from '@react-navigation/native'
+import {useFocusEffect, useIsFocused} from '@react-navigation/native'
 import {NativeStackScreenProps, HomeTabNavigatorParams} from 'lib/routes/types'
 import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
 import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState'
@@ -65,6 +65,7 @@ function HomeScreenReady({
   const {hasSession} = useSession()
   const setMinimalShellMode = useSetMinimalShellMode()
   const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
+  const isPageFocused = useIsFocused()
   const [selectedPage, setSelectedPage] = React.useState<string>(initialPage)
 
   /**
@@ -174,7 +175,7 @@ function HomeScreenReady({
       <FeedPage
         key="1"
         testID="followingFeedPage"
-        isPageFocused={selectedPageIndex === 0}
+        isPageFocused={selectedPageIndex === 0 && isPageFocused}
         feed={homeFeedParams.mergeFeedEnabled ? 'home' : 'following'}
         feedParams={homeFeedParams}
         renderEmptyState={renderFollowingEmptyState}
@@ -185,7 +186,7 @@ function HomeScreenReady({
           <FeedPage
             key={f}
             testID="customFeedPage"
-            isPageFocused={selectedPageIndex === 1 + index}
+            isPageFocused={selectedPageIndex === 1 + index && isPageFocused}
             feed={f}
             renderEmptyState={renderCustomFeedEmptyState}
           />
@@ -201,7 +202,7 @@ function HomeScreenReady({
       tabBarPosition="top">
       <FeedPage
         testID="customFeedPage"
-        isPageFocused
+        isPageFocused={isPageFocused}
         feed={`feedgen|at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot`}
         renderEmptyState={renderCustomFeedEmptyState}
       />
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index d5e378ccb..ea19515b5 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -2,7 +2,7 @@ import React, {useMemo} from 'react'
 import {StyleSheet, View} from 'react-native'
 import {useFocusEffect} from '@react-navigation/native'
 import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
-import {msg} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
 import {CenteredView, FlatList} from '../com/util/Views'
@@ -36,6 +36,8 @@ import {useQueryClient} from '@tanstack/react-query'
 import {useComposerControls} from '#/state/shell/composer'
 import {listenSoftReset} from '#/state/events'
 import {truncateAndInvalidate} from '#/state/queries/util'
+import {Text} from '#/view/com/util/text/Text'
+import {usePalette} from 'lib/hooks/usePalette'
 
 interface SectionRef {
   scrollToTop: () => void
@@ -420,6 +422,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
       <View>
         <Feed
           testID="postsFeed"
+          enabled={isFocused}
           feed={feed}
           pollInterval={30e3}
           scrollElRef={scrollElRef}
@@ -428,7 +431,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
           scrollEventThrottle={1}
           renderEmptyState={renderPostsEmpty}
           headerOffset={headerHeight}
-          enabled={isFocused}
+          renderEndOfFeed={ProfileEndOfFeed}
         />
         {(isScrolledDown || hasNew) && (
           <LoadLatestBtn
@@ -442,6 +445,18 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
   },
 )
 
+function ProfileEndOfFeed() {
+  const pal = usePalette('default')
+
+  return (
+    <View style={[pal.border, {paddingTop: 32, borderTopWidth: 1}]}>
+      <Text style={[pal.textLight, pal.border, {textAlign: 'center'}]}>
+        <Trans>End of feed</Trans>
+      </Text>
+    </View>
+  )
+}
+
 const styles = StyleSheet.create({
   container: {
     flexDirection: 'column',
diff --git a/src/view/screens/ProfileFeed.tsx b/src/view/screens/ProfileFeed.tsx
index 659560a25..3a0bdcc0f 100644
--- a/src/view/screens/ProfileFeed.tsx
+++ b/src/view/screens/ProfileFeed.tsx
@@ -402,7 +402,7 @@ export function ProfileFeedScreenInner({
         isHeaderReady={true}
         renderHeader={renderHeader}
         onCurrentPageSelected={onCurrentPageSelected}>
-        {({onScroll, headerHeight, isScrolledDown, scrollElRef}) =>
+        {({onScroll, headerHeight, isScrolledDown, scrollElRef, isFocused}) =>
           isPublic ? (
             <FeedSection
               ref={feedSectionRef}
@@ -413,6 +413,7 @@ export function ProfileFeedScreenInner({
               scrollElRef={
                 scrollElRef as React.MutableRefObject<FlatList<any> | null>
               }
+              isFocused={isFocused}
             />
           ) : (
             <CenteredView sideBorders style={[{paddingTop: headerHeight}]}>
@@ -492,10 +493,11 @@ interface FeedSectionProps {
   headerHeight: number
   isScrolledDown: boolean
   scrollElRef: React.MutableRefObject<FlatList<any> | null>
+  isFocused: boolean
 }
 const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
   function FeedSectionImpl(
-    {feed, onScroll, headerHeight, isScrolledDown, scrollElRef},
+    {feed, onScroll, headerHeight, isScrolledDown, scrollElRef, isFocused},
     ref,
   ) {
     const [hasNew, setHasNew] = React.useState(false)
@@ -518,6 +520,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
     return (
       <View>
         <Feed
+          enabled={isFocused}
           feed={feed}
           pollInterval={30e3}
           scrollElRef={scrollElRef}
diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx
index 1396b8269..3e568c8cc 100644
--- a/src/view/screens/ProfileList.tsx
+++ b/src/view/screens/ProfileList.tsx
@@ -56,6 +56,12 @@ import {useSession} from '#/state/session'
 import {useComposerControls} from '#/state/shell/composer'
 import {isWeb} from '#/platform/detection'
 import {truncateAndInvalidate} from '#/state/queries/util'
+import {
+  usePreferencesQuery,
+  usePinFeedMutation,
+  useUnpinFeedMutation,
+} from '#/state/queries/preferences'
+import {logger} from '#/logger'
 
 const SECTION_TITLES_CURATE = ['Posts', 'About']
 const SECTION_TITLES_MOD = ['About']
@@ -129,7 +135,6 @@ function ProfileListScreenLoaded({
       list,
       onChange() {
         if (isCurateList) {
-          // TODO(eric) should construct these strings with a fn too
           truncateAndInvalidate(queryClient, FEED_RQKEY(`list|${list.uri}`))
         }
       },
@@ -159,7 +164,13 @@ function ProfileListScreenLoaded({
           isHeaderReady={true}
           renderHeader={renderHeader}
           onCurrentPageSelected={onCurrentPageSelected}>
-          {({onScroll, headerHeight, isScrolledDown, scrollElRef}) => (
+          {({
+            onScroll,
+            headerHeight,
+            isScrolledDown,
+            scrollElRef,
+            isFocused,
+          }) => (
             <FeedSection
               ref={feedSectionRef}
               feed={`list|${uri}`}
@@ -169,6 +180,7 @@ function ProfileListScreenLoaded({
               onScroll={onScroll}
               headerHeight={headerHeight}
               isScrolledDown={isScrolledDown}
+              isFocused={isFocused}
             />
           )}
           {({onScroll, headerHeight, isScrolledDown, scrollElRef}) => (
@@ -247,19 +259,31 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
   const listDeleteMutation = useListDeleteMutation()
   const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist'
   const isModList = list.purpose === 'app.bsky.graph.defs#modlist'
-  const isPinned = false // TODO
   const isBlocking = !!list.viewer?.blocked
   const isMuting = !!list.viewer?.muted
   const isOwner = list.creator.did === currentAccount?.did
+  const {isPending: isPinPending, mutateAsync: pinFeed} = usePinFeedMutation()
+  const {isPending: isUnpinPending, mutateAsync: unpinFeed} =
+    useUnpinFeedMutation()
+  const isPending = isPinPending || isUnpinPending
+  const {data: preferences} = usePreferencesQuery()
 
-  const onTogglePinned = useCallback(async () => {
+  const isPinned = preferences?.feeds?.pinned?.includes(list.uri)
+
+  const onTogglePinned = React.useCallback(async () => {
     Haptics.default()
-    // TODO
-    // list.togglePin().catch(e => {
-    //   Toast.show('There was an issue contacting the server')
-    //   logger.error('Failed to toggle pinned list', {error: e})
-    // })
-  }, [])
+
+    try {
+      if (isPinned) {
+        await unpinFeed({uri: list.uri})
+      } else {
+        await pinFeed({uri: list.uri})
+      }
+    } catch (e) {
+      Toast.show('There was an issue contacting the server')
+      logger.error('Failed to toggle pinned feed', {error: e})
+    }
+  }, [list.uri, isPinned, pinFeed, unpinFeed])
 
   const onSubscribeMute = useCallback(() => {
     openModal({
@@ -466,10 +490,11 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
       avatarType="list">
       {isCurateList || isPinned ? (
         <Button
-          testID={list.isPinned ? 'unpinBtn' : 'pinBtn'}
-          type={list.isPinned ? 'default' : 'inverted'}
-          label={list.isPinned ? 'Unpin' : 'Pin to home'}
+          testID={isPinned ? 'unpinBtn' : 'pinBtn'}
+          type={isPinned ? 'default' : 'inverted'}
+          label={isPinned ? 'Unpin' : 'Pin to home'}
           onPress={onTogglePinned}
+          disabled={isPending}
         />
       ) : isModList ? (
         isBlocking ? (
@@ -519,10 +544,11 @@ interface FeedSectionProps {
   headerHeight: number
   isScrolledDown: boolean
   scrollElRef: React.MutableRefObject<FlatList<any> | null>
+  isFocused: boolean
 }
 const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
   function FeedSectionImpl(
-    {feed, scrollElRef, onScroll, headerHeight, isScrolledDown},
+    {feed, scrollElRef, onScroll, headerHeight, isScrolledDown, isFocused},
     ref,
   ) {
     const queryClient = useQueryClient()
@@ -545,6 +571,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
       <View>
         <Feed
           testID="listFeed"
+          enabled={isFocused}
           feed={feed}
           pollInterval={30e3}
           scrollElRef={scrollElRef}