diff --git a/src/lib/api/feed-manip.ts b/src/lib/api/feed-manip.ts index 61de795a..c2b80ca0 100644 --- a/src/lib/api/feed-manip.ts +++ b/src/lib/api/feed-manip.ts @@ -23,6 +23,7 @@ type FeedSliceItem = { record: AppBskyFeedPost.Record parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined isParentBlocked: boolean + isParentNotFound: boolean } type AuthorContext = { @@ -68,6 +69,7 @@ export class FeedViewPostsSlice { } const parent = reply?.parent const isParentBlocked = AppBskyFeedDefs.isBlockedPost(parent) + const isParentNotFound = AppBskyFeedDefs.isNotFoundPost(parent) let parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined if (AppBskyFeedDefs.isPostView(parent)) { parentAuthor = parent.author @@ -77,6 +79,7 @@ export class FeedViewPostsSlice { record: post.record, parentAuthor, isParentBlocked, + isParentNotFound, }) if (!reply || reason) { return @@ -89,23 +92,40 @@ export class FeedViewPostsSlice { this.isOrphan = true 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 isGrandparentBlocked = Boolean( - grandparentAuthor?.viewer?.blockedBy || - grandparentAuthor?.viewer?.blocking || - grandparentAuthor?.viewer?.blockingByList, + grandparent && AppBskyFeedDefs.isBlockedPost(grandparent), + ) + const isGrandparentNotFound = Boolean( + grandparent && AppBskyFeedDefs.isNotFoundPost(grandparent), ) this.items.unshift({ post: parent, record: parent.record, parentAuthor: grandparentAuthor, isParentBlocked: isGrandparentBlocked, + isParentNotFound: isGrandparentNotFound, }) if (isGrandparentBlocked) { 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 ( !AppBskyFeedDefs.isPostView(root) || !AppBskyFeedPost.isRecord(root.record) || @@ -121,6 +141,7 @@ export class FeedViewPostsSlice { post: root, record: root.record, isParentBlocked: false, + isParentNotFound: false, parentAuthor: undefined, }) if (parent.record.reply?.parent.uri !== root.uri) { diff --git a/src/state/queries/post-feed.ts b/src/state/queries/post-feed.ts index 724043e5..ee3e2c14 100644 --- a/src/state/queries/post-feed.ts +++ b/src/state/queries/post-feed.ts @@ -80,6 +80,7 @@ export interface FeedPostSliceItem { moderation: ModerationDecision parentAuthor?: AppBskyActorDefs.ProfileViewBasic isParentBlocked?: boolean + isParentNotFound?: boolean } export interface FeedPostSlice { @@ -326,6 +327,7 @@ export function usePostFeedQuery( moderation: moderations[i], parentAuthor: item.parentAuthor, isParentBlocked: item.isParentBlocked, + isParentNotFound: item.isParentNotFound, } return feedPostSliceItem }), diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index 0071e240..0fef4c5a 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -63,6 +63,7 @@ interface FeedItemProps { feedContext: string | undefined hideTopBorder?: boolean isParentBlocked?: boolean + isParentNotFound?: boolean } export function FeedItem({ @@ -78,6 +79,7 @@ export function FeedItem({ isThreadParent, hideTopBorder, isParentBlocked, + isParentNotFound, }: FeedItemProps & {post: AppBskyFeedDefs.PostView}): React.ReactNode { const postShadowed = usePostShadow(post) const richText = useMemo( @@ -109,6 +111,7 @@ export function FeedItem({ isThreadParent={isThreadParent} hideTopBorder={hideTopBorder} isParentBlocked={isParentBlocked} + isParentNotFound={isParentNotFound} /> ) } @@ -129,6 +132,7 @@ let FeedItemInner = ({ isThreadParent, hideTopBorder, isParentBlocked, + isParentNotFound, }: FeedItemProps & { richText: RichTextAPI post: Shadow @@ -344,9 +348,14 @@ let FeedItemInner = ({ postHref={href} onOpenAuthor={onOpenAuthor} /> - {showReplyTo && (parentAuthor || isParentBlocked) && ( - - )} + {showReplyTo && + (parentAuthor || isParentBlocked || isParentNotFound) && ( + + )} Reply to a blocked post + } else if (notFound) { + label = Reply to an unknown post } else if (profile != null) { const isMe = profile.did === currentAccount?.did if (isMe) { diff --git a/src/view/com/posts/FeedSlice.tsx b/src/view/com/posts/FeedSlice.tsx index fcd1ec3b..9676eff1 100644 --- a/src/view/com/posts/FeedSlice.tsx +++ b/src/view/com/posts/FeedSlice.tsx @@ -36,6 +36,7 @@ let FeedSlice = ({ isThreadChild={isThreadChildAt(slice.items, 0)} hideTopBorder={hideTopBorder} isParentBlocked={slice.items[0].isParentBlocked} + isParentNotFound={slice.items[0].isParentNotFound} /> @@ -90,6 +93,7 @@ let FeedSlice = ({ isThreadChildAt(slice.items, i) && slice.items.length === i + 1 } isParentBlocked={slice.items[i].isParentBlocked} + isParentNotFound={slice.items[i].isParentNotFound} hideTopBorder={hideTopBorder && i === 0} /> ))}