import React, {useMemo, useRef, useState} from 'react' import {NativeStackScreenProps} from '@react-navigation/native-stack' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 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' import {useSetTitle} from 'lib/hooks/useSetTitle' import {shareUrl} from 'lib/sharing' import {toShareUrl} from 'lib/strings/url-helpers' import {Haptics} from 'lib/haptics' import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' type Props = NativeStackScreenProps export const CustomFeedScreen = 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 isPinned = store.me.savedFeeds.isPinned(uri) const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll(store) useSetTitle(currentFeed?.displayName) const onToggleSaved = React.useCallback(async () => { try { Haptics.default() 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 () => { Haptics.default() 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 onTogglePinned = React.useCallback(async () => { Haptics.default() store.me.savedFeeds.togglePinnedFeed(currentFeed!).catch(e => { Toast.show('There was an issue contacting the server') store.log.error('Failed to toggle pinned feed', {e}) }) }, [store, currentFeed]) const onPressShare = React.useCallback(() => { const url = toShareUrl(`/profile/${name}/feed/${rkey}`) shareUrl(url) }, [name, rkey]) const onScrollToTop = React.useCallback(() => { scrollElRef.current?.scrollToOffset({offset: 0, animated: true}) resetMainScroll() }, [scrollElRef, resetMainScroll]) const renderHeaderBtns = React.useCallback(() => { return ( )} {currentFeed?.data.description ? ( {currentFeed.data.description} ) : null} {currentFeed ? ( ) : null} Feed ) }, [ pal, currentFeed, store.me.did, onToggleSaved, onToggleLiked, onPressShare, name, rkey, isPinned, onTogglePinned, ]) return ( {isScrolledDown ? ( ) : null} ) }), ) const styles = StyleSheet.create({ header: { flexDirection: 'row', gap: 12, paddingHorizontal: 16, paddingTop: 12, paddingBottom: 16, borderTopWidth: 1, }, headerBtns: { flexDirection: 'row', gap: 8, marginTop: 10, }, headerDetails: { paddingHorizontal: 16, paddingBottom: 16, }, headerDetailsFooter: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, fakeSelector: { flexDirection: 'row', paddingHorizontal: isDesktopWeb ? 16 : 6, }, fakeSelectorItem: { paddingHorizontal: 12, paddingBottom: 8, borderBottomWidth: 3, }, liked: { color: colors.red3, }, })