diff --git a/src/Navigation.tsx b/src/Navigation.tsx
index 4521068f..025020af 100644
--- a/src/Navigation.tsx
+++ b/src/Navigation.tsx
@@ -40,6 +40,7 @@ import {SettingsScreen} from './view/screens/Settings'
import {ProfileScreen} from './view/screens/Profile'
import {ProfileFollowersScreen} from './view/screens/ProfileFollowers'
import {ProfileFollowsScreen} from './view/screens/ProfileFollows'
+import {ProfileCustomFeed} from './view/screens/ProfileCustomFeed'
import {ProfileListScreen} from './view/screens/ProfileList'
import {PostThreadScreen} from './view/screens/PostThread'
import {PostLikedByScreen} from './view/screens/PostLikedBy'
@@ -56,7 +57,6 @@ import {ModerationMutedAccounts} from 'view/screens/ModerationMutedAccounts'
import {ModerationBlockedAccounts} from 'view/screens/ModerationBlockedAccounts'
import {getRoutingInstrumentation} from 'lib/sentry'
import {SavedFeeds} from './view/screens/SavedFeeds'
-import {CustomFeed} from './view/screens/CustomFeed'
import {PinnedFeeds} from 'view/screens/PinnedFeeds'
import {bskyTitle} from 'lib/strings/headings'
@@ -127,6 +127,7 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
title: title(`People followed by @${route.params.name}`),
})}
/>
+
-
>
)
}
diff --git a/src/lib/hooks/useCustomFeed.ts b/src/lib/hooks/useCustomFeed.ts
index ee40cf49..d7a27050 100644
--- a/src/lib/hooks/useCustomFeed.ts
+++ b/src/lib/hooks/useCustomFeed.ts
@@ -2,9 +2,9 @@ import {useEffect, useState} from 'react'
import {useStores} from 'state/index'
import {CustomFeedModel} from 'state/models/feeds/custom-feed'
-export function useCustomFeed(uri: string) {
+export function useCustomFeed(uri: string): CustomFeedModel | undefined {
const store = useStores()
- const [item, setItem] = useState()
+ const [item, setItem] = useState()
useEffect(() => {
async function fetchView() {
const res = await store.agent.app.bsky.feed.getFeedGenerator({
diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts
index 8b96aaad..52d0e9af 100644
--- a/src/lib/routes/types.ts
+++ b/src/lib/routes/types.ts
@@ -13,11 +13,11 @@ export type CommonNavigatorParams = {
Profile: {name: string; hideBackButton?: boolean}
ProfileFollowers: {name: string}
ProfileFollows: {name: string}
+ ProfileCustomFeed: {name: string; rkey: string}
ProfileList: {name: string; rkey: string}
PostThread: {name: string; rkey: string}
PostLikedBy: {name: string; rkey: string}
PostRepostedBy: {name: string; rkey: string}
- CustomFeed: {name: string; rkey: string; displayName?: string}
Debug: undefined
Log: undefined
Support: undefined
diff --git a/src/view/com/feeds/CustomFeed.tsx b/src/view/com/feeds/CustomFeed.tsx
index 8e1a7845..5a93020a 100644
--- a/src/view/com/feeds/CustomFeed.tsx
+++ b/src/view/com/feeds/CustomFeed.tsx
@@ -40,10 +40,9 @@ export const CustomFeed = observer(
accessibilityRole="button"
style={[styles.container, pal.border, style]}
onPress={() => {
- navigation.navigate('CustomFeed', {
+ navigation.navigate('ProfileCustomFeed', {
name: item.data.creator.did,
rkey: new AtUri(item.data.uri).rkey,
- displayName: item.displayName,
})
}}
key={item.data.uri}>
diff --git a/src/view/screens/CustomFeed.tsx b/src/view/screens/CustomFeed.tsx
deleted file mode 100644
index 76125fa5..00000000
--- a/src/view/screens/CustomFeed.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-import {NativeStackScreenProps} from '@react-navigation/native-stack'
-import {usePalette} from 'lib/hooks/usePalette'
-import {HeartIcon, HeartIconSolid} from 'lib/icons'
-import {CommonNavigatorParams} from 'lib/routes/types'
-import {makeRecordUri} from 'lib/strings/url-helpers'
-import {colors, s} from 'lib/styles'
-import {observer} from 'mobx-react-lite'
-import React, {useMemo, useRef} from 'react'
-import {FlatList, StyleSheet, TouchableOpacity, View} from 'react-native'
-import {useStores} from 'state/index'
-import {PostsFeedModel} from 'state/models/feeds/posts'
-import {useCustomFeed} from 'lib/hooks/useCustomFeed'
-import {withAuthRequired} from 'view/com/auth/withAuthRequired'
-import {Feed} from 'view/com/posts/Feed'
-import {Link} from 'view/com/util/Link'
-import {UserAvatar} from 'view/com/util/UserAvatar'
-import {ViewHeader} from 'view/com/util/ViewHeader'
-import {Button} from 'view/com/util/forms/Button'
-import {Text} from 'view/com/util/text/Text'
-
-type Props = NativeStackScreenProps
-export const CustomFeed = withAuthRequired(
- observer(({route}: Props) => {
- const rootStore = useStores()
- const {rkey, name, displayName} = route.params
- const uri = useMemo(
- () => makeRecordUri(name, 'app.bsky.feed.generator', rkey),
- [rkey, name],
- )
- const currentFeed = useCustomFeed(uri)
- const scrollElRef = useRef(null)
- const algoFeed: PostsFeedModel = useMemo(() => {
- const feed = new PostsFeedModel(rootStore, 'custom', {
- feed: uri,
- })
- feed.setup()
- return feed
- }, [rootStore, uri])
-
- return (
-
-
- }
- extraData={uri}
- />
-
- )
- }),
-)
-
-const ListHeaderComponent = observer(({uri}: {uri: string}) => {
- const currentFeed = useCustomFeed(uri)
- const pal = usePalette('default')
- const rootStore = useStores()
- return (
-
-
-
-
-
-
- @{currentFeed?.data.creator.handle}
-
-
-
- {currentFeed?.data.description}
-
-
-
-
-
- )
-})
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- headerContainer: {
- alignItems: 'center',
- justifyContent: 'center',
- gap: 8,
- marginBottom: 12,
- },
- header: {
- alignItems: 'center',
- gap: 4,
- },
- avatarContainer: {
- flexDirection: 'row',
- alignItems: 'center',
- gap: 8,
- },
- buttonsContainer: {
- flexDirection: 'row',
- gap: 8,
- },
- saveButton: {
- minWidth: 100,
- alignItems: 'center',
- },
- liked: {
- color: colors.red3,
- },
- notLiked: {
- color: colors.gray3,
- },
- likeButton: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'center',
- paddingVertical: 4,
- paddingHorizontal: 8,
- borderRadius: 24,
- gap: 4,
- },
-})
diff --git a/src/view/screens/ProfileCustomFeed.tsx b/src/view/screens/ProfileCustomFeed.tsx
new file mode 100644
index 00000000..1113ebf0
--- /dev/null
+++ b/src/view/screens/ProfileCustomFeed.tsx
@@ -0,0 +1,291 @@
+import React, {useMemo, useRef} from 'react'
+import {NativeStackScreenProps} from '@react-navigation/native-stack'
+import {usePalette} from 'lib/hooks/usePalette'
+import {HeartIcon, HeartIconSolid} from 'lib/icons'
+import {CommonNavigatorParams} from 'lib/routes/types'
+import {makeRecordUri} from 'lib/strings/url-helpers'
+import {colors, s} from 'lib/styles'
+import {observer} from 'mobx-react-lite'
+import {FlatList, StyleSheet, View} from 'react-native'
+import {useStores} from 'state/index'
+import {PostsFeedModel} from 'state/models/feeds/posts'
+import {useCustomFeed} from 'lib/hooks/useCustomFeed'
+import {withAuthRequired} from 'view/com/auth/withAuthRequired'
+import {Feed} from 'view/com/posts/Feed'
+import {pluralize} from 'lib/strings/helpers'
+import {TextLink} from 'view/com/util/Link'
+import {UserAvatar} from 'view/com/util/UserAvatar'
+import {ViewHeader} from 'view/com/util/ViewHeader'
+import {Button} from 'view/com/util/forms/Button'
+import {Text} from 'view/com/util/text/Text'
+import * as Toast from 'view/com/util/Toast'
+import {isDesktopWeb} from 'platform/detection'
+
+type Props = NativeStackScreenProps
+export const ProfileCustomFeed = withAuthRequired(
+ observer(({route}: Props) => {
+ const store = useStores()
+ const pal = usePalette('default')
+ const {rkey, name} = route.params
+ const uri = useMemo(
+ () => makeRecordUri(name, 'app.bsky.feed.generator', rkey),
+ [rkey, name],
+ )
+ const scrollElRef = useRef(null)
+ const currentFeed = useCustomFeed(uri)
+ const algoFeed: PostsFeedModel = useMemo(() => {
+ const feed = new PostsFeedModel(store, 'custom', {
+ feed: uri,
+ })
+ feed.setup()
+ return feed
+ }, [store, uri])
+
+ const onToggleSaved = React.useCallback(async () => {
+ try {
+ if (currentFeed.isSaved) {
+ await currentFeed.unsave()
+ } else {
+ await currentFeed.save()
+ }
+ } catch (err) {
+ Toast.show(
+ 'There was an an issue updating your feeds, please check your internet connection and try again.',
+ )
+ store.log.error('Failed up update feeds', {err})
+ }
+ }, [store, currentFeed])
+
+ const onToggleLiked = React.useCallback(async () => {
+ try {
+ if (currentFeed.isLiked) {
+ await currentFeed.unlike()
+ } else {
+ await currentFeed.like()
+ }
+ } catch (err) {
+ Toast.show(
+ 'There was an an issue contacting the server, please check your internet connection and try again.',
+ )
+ store.log.error('Failed up toggle like', {err})
+ }
+ }, [store, currentFeed])
+
+ const renderHeaderBtns = React.useCallback(() => {
+ return (
+
+
+
+
+ )
+ }, [
+ pal,
+ currentFeed?.isSaved,
+ currentFeed?.isLiked,
+ onToggleSaved,
+ onToggleLiked,
+ ])
+
+ const renderListHeaderComponent = React.useCallback(() => {
+ return (
+ <>
+
+
+
+ {currentFeed?.displayName}
+
+ {currentFeed && (
+
+ by{' '}
+ {currentFeed.data.creator.did === store.me.did ? (
+ 'you'
+ ) : (
+
+ )}
+
+ )}
+
+
+
+
+
+
+ {currentFeed?.data.description ? (
+
+ {currentFeed.data.description}
+
+ ) : null}
+
+ Liked by {currentFeed?.data.likeCount}{' '}
+ {pluralize(currentFeed?.data.likeCount || 0, 'user')}
+
+ {isDesktopWeb && (
+
+
+
+
+
+ )}
+
+
+
+
+ Feed
+
+
+
+ >
+ )
+ }, [store.me.did, pal, currentFeed, onToggleLiked, onToggleSaved])
+
+ return (
+
+
+
+
+ )
+ }),
+)
+
+/*
+
+
+
+
+
+
+
+ @{currentFeed?.data.creator.handle}
+
+
+
+ {currentFeed?.data.description}
+
+
+
+
+
+ */
+
+const styles = StyleSheet.create({
+ headerBtns: {
+ flexDirection: 'row',
+ gap: 8,
+ },
+ header: {
+ flexDirection: 'row',
+ gap: 12,
+ paddingHorizontal: 16,
+ paddingTop: 12,
+ paddingBottom: 16,
+ borderTopWidth: 1,
+ },
+ headerDetails: {
+ paddingHorizontal: 16,
+ paddingBottom: 16,
+ },
+ fakeSelector: {
+ flexDirection: 'row',
+ paddingHorizontal: isDesktopWeb ? 16 : 6,
+ },
+ fakeSelectorItem: {
+ paddingHorizontal: 12,
+ paddingBottom: 8,
+ borderBottomWidth: 3,
+ },
+ liked: {
+ color: colors.red3,
+ },
+
+ /* headerContainer: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ gap: 8,
+ marginBottom: 12,
+ },
+ header: {
+ alignItems: 'center',
+ gap: 4,
+ },
+ avatarContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 8,
+ },
+ buttonsContainer: {
+ flexDirection: 'row',
+ gap: 8,
+ },
+ saveButton: {
+ minWidth: 100,
+ alignItems: 'center',
+ },
+ liked: {
+ color: colors.red3,
+ },
+ notLiked: {
+ color: colors.gray3,
+ },
+ likeButton: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ paddingVertical: 4,
+ paddingHorizontal: 8,
+ borderRadius: 24,
+ gap: 4,
+ },*/
+})
diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx
index 01f27bae..7c3ed831 100644
--- a/src/view/screens/ProfileList.tsx
+++ b/src/view/screens/ProfileList.tsx
@@ -87,7 +87,7 @@ export const ProfileListScreen = withAuthRequired(
return
}, [])
- const renderHeaderBtn = React.useCallback(() => {
+ const renderHeaderBtns = React.useCallback(() => {
return (
{list?.isOwner && (
@@ -148,7 +148,7 @@ export const ProfileListScreen = withAuthRequired(
pal.border,
]}
testID="moderationMutelistsScreen">
-
+
{
- navigation.navigate('CustomFeed', {
+ navigation.navigate('ProfileCustomFeed', {
name: item.data.creator.did,
rkey: new AtUri(item.data.uri).rkey,
- displayName:
- item.data.displayName ??
- `${item.data.creator.displayName}'s feed`,
})
}}
style={styles.pinnedItem}>