Fix orphaned feed slices, handle blocks (#4944)
* Fix orphaned feed slices, handle blocks * Revert to filerting out orphan threads * Support NotFoundPost views too * Just kidding, use ReplyRef.root as source of grandparent data * Fixeszio/stable
parent
2939ee7df7
commit
3976d6738b
|
@ -23,6 +23,7 @@ type FeedSliceItem = {
|
||||||
record: AppBskyFeedPost.Record
|
record: AppBskyFeedPost.Record
|
||||||
parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
|
parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||||
isParentBlocked: boolean
|
isParentBlocked: boolean
|
||||||
|
isParentNotFound: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthorContext = {
|
type AuthorContext = {
|
||||||
|
@ -68,6 +69,7 @@ export class FeedViewPostsSlice {
|
||||||
}
|
}
|
||||||
const parent = reply?.parent
|
const parent = reply?.parent
|
||||||
const isParentBlocked = AppBskyFeedDefs.isBlockedPost(parent)
|
const isParentBlocked = AppBskyFeedDefs.isBlockedPost(parent)
|
||||||
|
const isParentNotFound = AppBskyFeedDefs.isNotFoundPost(parent)
|
||||||
let parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
|
let parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||||
if (AppBskyFeedDefs.isPostView(parent)) {
|
if (AppBskyFeedDefs.isPostView(parent)) {
|
||||||
parentAuthor = parent.author
|
parentAuthor = parent.author
|
||||||
|
@ -77,6 +79,7 @@ export class FeedViewPostsSlice {
|
||||||
record: post.record,
|
record: post.record,
|
||||||
parentAuthor,
|
parentAuthor,
|
||||||
isParentBlocked,
|
isParentBlocked,
|
||||||
|
isParentNotFound,
|
||||||
})
|
})
|
||||||
if (!reply || reason) {
|
if (!reply || reason) {
|
||||||
return
|
return
|
||||||
|
@ -89,23 +92,40 @@ export class FeedViewPostsSlice {
|
||||||
this.isOrphan = true
|
this.isOrphan = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const root = reply.root
|
||||||
|
const rootIsView =
|
||||||
|
AppBskyFeedDefs.isPostView(root) ||
|
||||||
|
AppBskyFeedDefs.isBlockedPost(root) ||
|
||||||
|
AppBskyFeedDefs.isNotFoundPost(root)
|
||||||
|
/*
|
||||||
|
* If the parent is also the root, we just so happen to have the data we
|
||||||
|
* need to compute if the parent's parent (grandparent) is blocked. This
|
||||||
|
* doesn't always happen, of course, but we can take advantage of it when
|
||||||
|
* it does.
|
||||||
|
*/
|
||||||
|
const grandparent =
|
||||||
|
rootIsView && parent.record.reply?.parent.uri === root.uri
|
||||||
|
? root
|
||||||
|
: undefined
|
||||||
const grandparentAuthor = reply.grandparentAuthor
|
const grandparentAuthor = reply.grandparentAuthor
|
||||||
const isGrandparentBlocked = Boolean(
|
const isGrandparentBlocked = Boolean(
|
||||||
grandparentAuthor?.viewer?.blockedBy ||
|
grandparent && AppBskyFeedDefs.isBlockedPost(grandparent),
|
||||||
grandparentAuthor?.viewer?.blocking ||
|
)
|
||||||
grandparentAuthor?.viewer?.blockingByList,
|
const isGrandparentNotFound = Boolean(
|
||||||
|
grandparent && AppBskyFeedDefs.isNotFoundPost(grandparent),
|
||||||
)
|
)
|
||||||
this.items.unshift({
|
this.items.unshift({
|
||||||
post: parent,
|
post: parent,
|
||||||
record: parent.record,
|
record: parent.record,
|
||||||
parentAuthor: grandparentAuthor,
|
parentAuthor: grandparentAuthor,
|
||||||
isParentBlocked: isGrandparentBlocked,
|
isParentBlocked: isGrandparentBlocked,
|
||||||
|
isParentNotFound: isGrandparentNotFound,
|
||||||
})
|
})
|
||||||
if (isGrandparentBlocked) {
|
if (isGrandparentBlocked) {
|
||||||
this.isOrphan = true
|
this.isOrphan = true
|
||||||
// Keep going, it might still have a root.
|
// Keep going, it might still have a root, and we need this for thread
|
||||||
|
// de-deduping
|
||||||
}
|
}
|
||||||
const root = reply.root
|
|
||||||
if (
|
if (
|
||||||
!AppBskyFeedDefs.isPostView(root) ||
|
!AppBskyFeedDefs.isPostView(root) ||
|
||||||
!AppBskyFeedPost.isRecord(root.record) ||
|
!AppBskyFeedPost.isRecord(root.record) ||
|
||||||
|
@ -121,6 +141,7 @@ export class FeedViewPostsSlice {
|
||||||
post: root,
|
post: root,
|
||||||
record: root.record,
|
record: root.record,
|
||||||
isParentBlocked: false,
|
isParentBlocked: false,
|
||||||
|
isParentNotFound: false,
|
||||||
parentAuthor: undefined,
|
parentAuthor: undefined,
|
||||||
})
|
})
|
||||||
if (parent.record.reply?.parent.uri !== root.uri) {
|
if (parent.record.reply?.parent.uri !== root.uri) {
|
||||||
|
|
|
@ -80,6 +80,7 @@ export interface FeedPostSliceItem {
|
||||||
moderation: ModerationDecision
|
moderation: ModerationDecision
|
||||||
parentAuthor?: AppBskyActorDefs.ProfileViewBasic
|
parentAuthor?: AppBskyActorDefs.ProfileViewBasic
|
||||||
isParentBlocked?: boolean
|
isParentBlocked?: boolean
|
||||||
|
isParentNotFound?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FeedPostSlice {
|
export interface FeedPostSlice {
|
||||||
|
@ -326,6 +327,7 @@ export function usePostFeedQuery(
|
||||||
moderation: moderations[i],
|
moderation: moderations[i],
|
||||||
parentAuthor: item.parentAuthor,
|
parentAuthor: item.parentAuthor,
|
||||||
isParentBlocked: item.isParentBlocked,
|
isParentBlocked: item.isParentBlocked,
|
||||||
|
isParentNotFound: item.isParentNotFound,
|
||||||
}
|
}
|
||||||
return feedPostSliceItem
|
return feedPostSliceItem
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -63,6 +63,7 @@ interface FeedItemProps {
|
||||||
feedContext: string | undefined
|
feedContext: string | undefined
|
||||||
hideTopBorder?: boolean
|
hideTopBorder?: boolean
|
||||||
isParentBlocked?: boolean
|
isParentBlocked?: boolean
|
||||||
|
isParentNotFound?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FeedItem({
|
export function FeedItem({
|
||||||
|
@ -78,6 +79,7 @@ export function FeedItem({
|
||||||
isThreadParent,
|
isThreadParent,
|
||||||
hideTopBorder,
|
hideTopBorder,
|
||||||
isParentBlocked,
|
isParentBlocked,
|
||||||
|
isParentNotFound,
|
||||||
}: FeedItemProps & {post: AppBskyFeedDefs.PostView}): React.ReactNode {
|
}: FeedItemProps & {post: AppBskyFeedDefs.PostView}): React.ReactNode {
|
||||||
const postShadowed = usePostShadow(post)
|
const postShadowed = usePostShadow(post)
|
||||||
const richText = useMemo(
|
const richText = useMemo(
|
||||||
|
@ -109,6 +111,7 @@ export function FeedItem({
|
||||||
isThreadParent={isThreadParent}
|
isThreadParent={isThreadParent}
|
||||||
hideTopBorder={hideTopBorder}
|
hideTopBorder={hideTopBorder}
|
||||||
isParentBlocked={isParentBlocked}
|
isParentBlocked={isParentBlocked}
|
||||||
|
isParentNotFound={isParentNotFound}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -129,6 +132,7 @@ let FeedItemInner = ({
|
||||||
isThreadParent,
|
isThreadParent,
|
||||||
hideTopBorder,
|
hideTopBorder,
|
||||||
isParentBlocked,
|
isParentBlocked,
|
||||||
|
isParentNotFound,
|
||||||
}: FeedItemProps & {
|
}: FeedItemProps & {
|
||||||
richText: RichTextAPI
|
richText: RichTextAPI
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>
|
post: Shadow<AppBskyFeedDefs.PostView>
|
||||||
|
@ -344,8 +348,13 @@ let FeedItemInner = ({
|
||||||
postHref={href}
|
postHref={href}
|
||||||
onOpenAuthor={onOpenAuthor}
|
onOpenAuthor={onOpenAuthor}
|
||||||
/>
|
/>
|
||||||
{showReplyTo && (parentAuthor || isParentBlocked) && (
|
{showReplyTo &&
|
||||||
<ReplyToLabel blocked={isParentBlocked} profile={parentAuthor} />
|
(parentAuthor || isParentBlocked || isParentNotFound) && (
|
||||||
|
<ReplyToLabel
|
||||||
|
blocked={isParentBlocked}
|
||||||
|
notFound={isParentNotFound}
|
||||||
|
profile={parentAuthor}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<LabelsOnMyPost post={post} />
|
<LabelsOnMyPost post={post} />
|
||||||
<PostContent
|
<PostContent
|
||||||
|
@ -438,9 +447,11 @@ PostContent = memo(PostContent)
|
||||||
function ReplyToLabel({
|
function ReplyToLabel({
|
||||||
profile,
|
profile,
|
||||||
blocked,
|
blocked,
|
||||||
|
notFound,
|
||||||
}: {
|
}: {
|
||||||
profile: AppBskyActorDefs.ProfileViewBasic | undefined
|
profile: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||||
blocked?: boolean
|
blocked?: boolean
|
||||||
|
notFound?: boolean
|
||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
|
@ -448,6 +459,8 @@ function ReplyToLabel({
|
||||||
let label
|
let label
|
||||||
if (blocked) {
|
if (blocked) {
|
||||||
label = <Trans context="description">Reply to a blocked post</Trans>
|
label = <Trans context="description">Reply to a blocked post</Trans>
|
||||||
|
} else if (notFound) {
|
||||||
|
label = <Trans context="description">Reply to an unknown post</Trans>
|
||||||
} else if (profile != null) {
|
} else if (profile != null) {
|
||||||
const isMe = profile.did === currentAccount?.did
|
const isMe = profile.did === currentAccount?.did
|
||||||
if (isMe) {
|
if (isMe) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ let FeedSlice = ({
|
||||||
isThreadChild={isThreadChildAt(slice.items, 0)}
|
isThreadChild={isThreadChildAt(slice.items, 0)}
|
||||||
hideTopBorder={hideTopBorder}
|
hideTopBorder={hideTopBorder}
|
||||||
isParentBlocked={slice.items[0].isParentBlocked}
|
isParentBlocked={slice.items[0].isParentBlocked}
|
||||||
|
isParentNotFound={slice.items[0].isParentNotFound}
|
||||||
/>
|
/>
|
||||||
<ViewFullThread uri={slice.items[0].uri} />
|
<ViewFullThread uri={slice.items[0].uri} />
|
||||||
<FeedItem
|
<FeedItem
|
||||||
|
@ -53,6 +54,7 @@ let FeedSlice = ({
|
||||||
isThreadParent={isThreadParentAt(slice.items, beforeLast)}
|
isThreadParent={isThreadParentAt(slice.items, beforeLast)}
|
||||||
isThreadChild={isThreadChildAt(slice.items, beforeLast)}
|
isThreadChild={isThreadChildAt(slice.items, beforeLast)}
|
||||||
isParentBlocked={slice.items[beforeLast].isParentBlocked}
|
isParentBlocked={slice.items[beforeLast].isParentBlocked}
|
||||||
|
isParentNotFound={slice.items[beforeLast].isParentNotFound}
|
||||||
/>
|
/>
|
||||||
<FeedItem
|
<FeedItem
|
||||||
key={slice.items[last]._reactKey}
|
key={slice.items[last]._reactKey}
|
||||||
|
@ -66,6 +68,7 @@ let FeedSlice = ({
|
||||||
isThreadParent={isThreadParentAt(slice.items, last)}
|
isThreadParent={isThreadParentAt(slice.items, last)}
|
||||||
isThreadChild={isThreadChildAt(slice.items, last)}
|
isThreadChild={isThreadChildAt(slice.items, last)}
|
||||||
isParentBlocked={slice.items[last].isParentBlocked}
|
isParentBlocked={slice.items[last].isParentBlocked}
|
||||||
|
isParentNotFound={slice.items[last].isParentNotFound}
|
||||||
isThreadLastChild
|
isThreadLastChild
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -90,6 +93,7 @@ let FeedSlice = ({
|
||||||
isThreadChildAt(slice.items, i) && slice.items.length === i + 1
|
isThreadChildAt(slice.items, i) && slice.items.length === i + 1
|
||||||
}
|
}
|
||||||
isParentBlocked={slice.items[i].isParentBlocked}
|
isParentBlocked={slice.items[i].isParentBlocked}
|
||||||
|
isParentNotFound={slice.items[i].isParentNotFound}
|
||||||
hideTopBorder={hideTopBorder && i === 0}
|
hideTopBorder={hideTopBorder && i === 0}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
Loading…
Reference in New Issue