Factor our feed source model (#1887)
* Refactor first onboarding step * Replace old FeedSourceCard * Clean up CustomFeedEmbed * Remove discover feeds model * Refactor ProfileFeed screen * Remove useCustomFeed * Delete some unused models * Rip out more prefs * Factor out treeView from thread comp * Improve last commit
This commit is contained in:
parent
a01463788d
commit
06eb8b9a4c
21 changed files with 526 additions and 1356 deletions
|
@ -10,10 +10,8 @@ import {Button} from 'view/com/util/forms/Button'
|
|||
import {RecommendedFeedsItem} from './RecommendedFeedsItem'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useQuery} from '@tanstack/react-query'
|
||||
import {useStores} from 'state/index'
|
||||
import {FeedSourceModel} from 'state/models/content/feed-source'
|
||||
import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
|
||||
import {useSuggestedFeedsQuery} from '#/state/queries/suggested-feeds'
|
||||
|
||||
type Props = {
|
||||
next: () => void
|
||||
|
@ -21,35 +19,11 @@ type Props = {
|
|||
export const RecommendedFeeds = observer(function RecommendedFeedsImpl({
|
||||
next,
|
||||
}: Props) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isTabletOrMobile} = useWebMediaQueries()
|
||||
const {isLoading, data: recommendedFeeds} = useQuery({
|
||||
staleTime: Infinity, // fixed list rn, never refetch
|
||||
queryKey: ['onboarding', 'recommended_feeds'],
|
||||
async queryFn() {
|
||||
try {
|
||||
const {
|
||||
data: {feeds},
|
||||
success,
|
||||
} = await store.agent.app.bsky.feed.getSuggestedFeeds()
|
||||
const {isLoading, data} = useSuggestedFeedsQuery()
|
||||
|
||||
if (!success) {
|
||||
return []
|
||||
}
|
||||
|
||||
return (feeds.length ? feeds : []).map(feed => {
|
||||
const model = new FeedSourceModel(store, feed.uri)
|
||||
model.hydrateFeedGenerator(feed)
|
||||
return model
|
||||
})
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const hasFeeds = recommendedFeeds && recommendedFeeds.length
|
||||
const hasFeeds = data && data?.pages?.[0]?.feeds?.length
|
||||
|
||||
const title = (
|
||||
<>
|
||||
|
@ -118,7 +92,7 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({
|
|||
contentStyle={{paddingHorizontal: 0}}>
|
||||
{hasFeeds ? (
|
||||
<FlatList
|
||||
data={recommendedFeeds}
|
||||
data={data.pages[0].feeds}
|
||||
renderItem={({item}) => <RecommendedFeedsItem item={item} />}
|
||||
keyExtractor={item => item.uri}
|
||||
style={{flex: 1}}
|
||||
|
@ -146,7 +120,7 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({
|
|||
|
||||
{hasFeeds ? (
|
||||
<FlatList
|
||||
data={recommendedFeeds}
|
||||
data={data.pages[0].feeds}
|
||||
renderItem={({item}) => <RecommendedFeedsItem item={item} />}
|
||||
keyExtractor={item => item.uri}
|
||||
style={{flex: 1}}
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react'
|
|||
import {View} from 'react-native'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {AppBskyFeedDefs, RichText as BskRichText} from '@atproto/api'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {RichText} from 'view/com/util/text/RichText'
|
||||
import {Button} from 'view/com/util/forms/Button'
|
||||
|
@ -11,33 +12,58 @@ import {HeartIcon} from 'lib/icons'
|
|||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {FeedSourceModel} from 'state/models/content/feed-source'
|
||||
import {
|
||||
usePreferencesQuery,
|
||||
usePinFeedMutation,
|
||||
useRemoveFeedMutation,
|
||||
} from '#/state/queries/preferences'
|
||||
import {logger} from '#/logger'
|
||||
|
||||
export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({
|
||||
item,
|
||||
}: {
|
||||
item: FeedSourceModel
|
||||
item: AppBskyFeedDefs.GeneratorView
|
||||
}) {
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const pal = usePalette('default')
|
||||
if (!item) return null
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
const {
|
||||
mutateAsync: pinFeed,
|
||||
variables: pinnedFeed,
|
||||
reset: resetPinFeed,
|
||||
} = usePinFeedMutation()
|
||||
const {
|
||||
mutateAsync: removeFeed,
|
||||
variables: removedFeed,
|
||||
reset: resetRemoveFeed,
|
||||
} = useRemoveFeedMutation()
|
||||
|
||||
if (!item || !preferences) return null
|
||||
|
||||
const isPinned =
|
||||
!removedFeed?.uri &&
|
||||
(pinnedFeed?.uri || preferences.feeds.saved.includes(item.uri))
|
||||
|
||||
const onToggle = async () => {
|
||||
if (item.isSaved) {
|
||||
if (isPinned) {
|
||||
try {
|
||||
await item.unsave()
|
||||
await removeFeed({uri: item.uri})
|
||||
resetRemoveFeed()
|
||||
} catch (e) {
|
||||
Toast.show('There was an issue contacting your server')
|
||||
console.error('Failed to unsave feed', {e})
|
||||
logger.error('Failed to unsave feed', {error: e})
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await item.pin()
|
||||
await pinFeed({uri: item.uri})
|
||||
resetPinFeed()
|
||||
} catch (e) {
|
||||
Toast.show('There was an issue contacting your server')
|
||||
console.error('Failed to pin feed', {e})
|
||||
logger.error('Failed to pin feed', {error: e})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View testID={`feed-${item.displayName}`}>
|
||||
<View
|
||||
|
@ -66,10 +92,10 @@ export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({
|
|||
</Text>
|
||||
|
||||
<Text style={[pal.textLight, {marginBottom: 8}]} numberOfLines={1}>
|
||||
by {sanitizeHandle(item.creatorHandle, '@')}
|
||||
by {sanitizeHandle(item.creator.handle, '@')}
|
||||
</Text>
|
||||
|
||||
{item.descriptionRT ? (
|
||||
{item.description ? (
|
||||
<RichText
|
||||
type="xl"
|
||||
style={[
|
||||
|
@ -80,7 +106,7 @@ export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({
|
|||
marginBottom: 18,
|
||||
},
|
||||
]}
|
||||
richText={item.descriptionRT}
|
||||
richText={new BskRichText({text: item.description || ''})}
|
||||
numberOfLines={6}
|
||||
/>
|
||||
) : null}
|
||||
|
@ -97,7 +123,7 @@ export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({
|
|||
paddingRight: 2,
|
||||
gap: 6,
|
||||
}}>
|
||||
{item.isSaved ? (
|
||||
{isPinned ? (
|
||||
<>
|
||||
<FontAwesomeIcon
|
||||
icon="check"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue