diff options
Diffstat (limited to 'src/view/screens')
-rw-r--r-- | src/view/screens/Home.tsx | 9 | ||||
-rw-r--r-- | src/view/screens/Profile.tsx | 19 | ||||
-rw-r--r-- | src/view/screens/ProfileFeed.tsx | 7 | ||||
-rw-r--r-- | src/view/screens/ProfileList.tsx | 55 |
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} |