Refactor feeds to use react-query (#1862)
* Update to react-query v5 * Introduce post-feed react query * Add feed refresh behaviors * Only fetch feeds of visible pages * Implement polling for latest on feeds * Add moderation filtering to slices * Handle block errors * Update feed error messages * Remove old models * Replace simple-feed option with disable-tuner option * Add missing useMemo * Implement the mergefeed and fixes to polling * Correctly handle failed load more state * Improve error and empty state behaviors * Clearer naming
This commit is contained in:
parent
51f04b9620
commit
c8c308e31e
31 changed files with 904 additions and 1081 deletions
|
|
@ -1,24 +1,40 @@
|
|||
import React from 'react'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {PostsFeedSliceModel} from 'state/models/feeds/posts-slice'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {FeedPostSlice} from '#/state/queries/post-feed'
|
||||
import {AtUri, moderatePost} from '@atproto/api'
|
||||
import {Link} from '../util/Link'
|
||||
import {Text} from '../util/text/Text'
|
||||
import Svg, {Circle, Line} from 'react-native-svg'
|
||||
import {FeedItem} from './FeedItem'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {useStores} from '#/state'
|
||||
|
||||
export const FeedSlice = observer(function FeedSliceImpl({
|
||||
slice,
|
||||
dataUpdatedAt,
|
||||
ignoreFilterFor,
|
||||
}: {
|
||||
slice: PostsFeedSliceModel
|
||||
slice: FeedPostSlice
|
||||
dataUpdatedAt: number
|
||||
ignoreFilterFor?: string
|
||||
}) {
|
||||
if (slice.shouldFilter(ignoreFilterFor)) {
|
||||
return null
|
||||
const store = useStores()
|
||||
const moderations = React.useMemo(() => {
|
||||
return slice.items.map(item =>
|
||||
moderatePost(item.post, store.preferences.moderationOpts),
|
||||
)
|
||||
}, [slice, store.preferences.moderationOpts])
|
||||
|
||||
// apply moderation filter
|
||||
for (let i = 0; i < slice.items.length; i++) {
|
||||
if (
|
||||
moderations[i]?.content.filter &&
|
||||
slice.items[i].post.author.did !== ignoreFilterFor
|
||||
) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
if (slice.isThread && slice.items.length > 3) {
|
||||
|
|
@ -27,23 +43,34 @@ export const FeedSlice = observer(function FeedSliceImpl({
|
|||
<>
|
||||
<FeedItem
|
||||
key={slice.items[0]._reactKey}
|
||||
item={slice.items[0]}
|
||||
source={slice.source}
|
||||
isThreadParent={slice.isThreadParentAt(0)}
|
||||
isThreadChild={slice.isThreadChildAt(0)}
|
||||
post={slice.items[0].post}
|
||||
record={slice.items[0].record}
|
||||
reason={slice.items[0].reason}
|
||||
moderation={moderations[0]}
|
||||
dataUpdatedAt={dataUpdatedAt}
|
||||
isThreadParent={isThreadParentAt(slice.items, 0)}
|
||||
isThreadChild={isThreadChildAt(slice.items, 0)}
|
||||
/>
|
||||
<FeedItem
|
||||
key={slice.items[1]._reactKey}
|
||||
item={slice.items[1]}
|
||||
isThreadParent={slice.isThreadParentAt(1)}
|
||||
isThreadChild={slice.isThreadChildAt(1)}
|
||||
post={slice.items[1].post}
|
||||
record={slice.items[1].record}
|
||||
reason={slice.items[1].reason}
|
||||
moderation={moderations[1]}
|
||||
dataUpdatedAt={dataUpdatedAt}
|
||||
isThreadParent={isThreadParentAt(slice.items, 1)}
|
||||
isThreadChild={isThreadChildAt(slice.items, 1)}
|
||||
/>
|
||||
<ViewFullThread slice={slice} />
|
||||
<FeedItem
|
||||
key={slice.items[last]._reactKey}
|
||||
item={slice.items[last]}
|
||||
isThreadParent={slice.isThreadParentAt(last)}
|
||||
isThreadChild={slice.isThreadChildAt(last)}
|
||||
post={slice.items[last].post}
|
||||
record={slice.items[last].record}
|
||||
reason={slice.items[last].reason}
|
||||
moderation={moderations[last]}
|
||||
dataUpdatedAt={dataUpdatedAt}
|
||||
isThreadParent={isThreadParentAt(slice.items, last)}
|
||||
isThreadChild={isThreadChildAt(slice.items, last)}
|
||||
isThreadLastChild
|
||||
/>
|
||||
</>
|
||||
|
|
@ -55,12 +82,15 @@ export const FeedSlice = observer(function FeedSliceImpl({
|
|||
{slice.items.map((item, i) => (
|
||||
<FeedItem
|
||||
key={item._reactKey}
|
||||
item={item}
|
||||
source={i === 0 ? slice.source : undefined}
|
||||
isThreadParent={slice.isThreadParentAt(i)}
|
||||
isThreadChild={slice.isThreadChildAt(i)}
|
||||
post={slice.items[i].post}
|
||||
record={slice.items[i].record}
|
||||
reason={slice.items[i].reason}
|
||||
moderation={moderations[i]}
|
||||
dataUpdatedAt={dataUpdatedAt}
|
||||
isThreadParent={isThreadParentAt(slice.items, i)}
|
||||
isThreadChild={isThreadChildAt(slice.items, i)}
|
||||
isThreadLastChild={
|
||||
slice.isThreadChildAt(i) && slice.items.length === i + 1
|
||||
isThreadChildAt(slice.items, i) && slice.items.length === i + 1
|
||||
}
|
||||
/>
|
||||
))}
|
||||
|
|
@ -68,12 +98,12 @@ export const FeedSlice = observer(function FeedSliceImpl({
|
|||
)
|
||||
})
|
||||
|
||||
function ViewFullThread({slice}: {slice: PostsFeedSliceModel}) {
|
||||
function ViewFullThread({slice}: {slice: FeedPostSlice}) {
|
||||
const pal = usePalette('default')
|
||||
const itemHref = React.useMemo(() => {
|
||||
const urip = new AtUri(slice.rootItem.post.uri)
|
||||
return makeProfileLink(slice.rootItem.post.author, 'post', urip.rkey)
|
||||
}, [slice.rootItem.post.uri, slice.rootItem.post.author])
|
||||
const urip = new AtUri(slice.rootUri)
|
||||
return makeProfileLink({did: urip.hostname, handle: ''}, 'post', urip.rkey)
|
||||
}, [slice.rootUri])
|
||||
|
||||
return (
|
||||
<Link
|
||||
|
|
@ -115,3 +145,17 @@ const styles = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
},
|
||||
})
|
||||
|
||||
function isThreadParentAt<T>(arr: Array<T>, i: number) {
|
||||
if (arr.length === 1) {
|
||||
return false
|
||||
}
|
||||
return i < arr.length - 1
|
||||
}
|
||||
|
||||
function isThreadChildAt<T>(arr: Array<T>, i: number) {
|
||||
if (arr.length === 1) {
|
||||
return false
|
||||
}
|
||||
return i > 0
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue