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:
Eric Bailey 2023-11-13 15:53:57 -06:00 committed by GitHub
parent a01463788d
commit 06eb8b9a4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 526 additions and 1356 deletions

View file

@ -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}}

View file

@ -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"