Show replies in context of their threads (#4871)

* Don't reconstruct threads from separate posts

* Remove post-level dedupe for now

* Change repost dedupe condition to look just at length

* Delete unused isThread

* Delete another isThread field

It is now meaningless because there's nothing special about author threads.

* Narrow down slice item shape so it does not need reply

* Consolidate slice validation criteria in one place

* Show replies in context

* Make fallback marker work

* Remove misleading and now-unused property

It was called rootUri but it was actually the leaf URI. Regardless, it's not used anymore.

* Add by-thread dedupe to non-author feeds

* Add post-level dedupe

* Always count from the start

This is easier to think about.

* Only tuner state need to be untouched on dry run

* Account for threads in reply filtering

* Remove repost deduping

This is already being taken care of by item-level deduping. It's also now wrong and removing too much (since it wasn't filtering for reposts directly).

* Calculate rootUri correctly

* Apply Following settings to all lists

* Don't dedupe intentional reposts by thread

* Show reply parent when ambiguous

* Explicitly remove orphaned replies from following/lists

* Fix thread dedupe to work across pages

* Mark grandparent-blocked as orphaned

* Guard tuner state change by dryRun

* Remove dead code

* Don't dedupe feedgen threads

* Revert "Apply Following settings to all lists"

This reverts commit aff86be6d37b60cc5d0ac38f22c31a4808342cf4.

Let's not do this yet and have a bit more discussion. This is a chunky change already.

* Reason belongs to a slice, not item

* Logically feedContext belongs to the slice

* Update comment to reflect latest behavior
This commit is contained in:
dan 2024-08-05 20:51:41 +01:00 committed by GitHub
parent 18b423396b
commit 74b0318d89
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 279 additions and 300 deletions

View file

@ -14,7 +14,6 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useQueryClient} from '@tanstack/react-query'
import {FALLBACK_MARKER_POST} from '#/lib/api/feed/home'
import {DISCOVER_FEED_URI, KNOWN_SHUTDOWN_FEEDS} from '#/lib/constants'
import {logEvent, useGate} from '#/lib/statsig/statsig'
import {logger} from '#/logger'
@ -472,7 +471,7 @@ let Feed = ({
} else if (item.type === progressGuideInterstitialType) {
return <ProgressGuide />
} else if (item.type === 'slice') {
if (item.slice.rootUri === FALLBACK_MARKER_POST.post.uri) {
if (item.slice.isFallbackMarker) {
// HACK
// tell the user we fell back to discover
// see home.ts (feed api) for more info

View file

@ -345,11 +345,9 @@ let FeedItemInner = ({
postHref={href}
onOpenAuthor={onOpenAuthor}
/>
{!isThreadChild &&
showReplyTo &&
(parentAuthor || isParentBlocked) && (
<ReplyToLabel blocked={isParentBlocked} profile={parentAuthor} />
)}
{showReplyTo && (parentAuthor || isParentBlocked) && (
<ReplyToLabel blocked={isParentBlocked} profile={parentAuthor} />
)}
<LabelsOnMyPost post={post} />
<PostContent
moderation={moderation}

View file

@ -18,7 +18,7 @@ let FeedSlice = ({
slice: FeedPostSlice
hideTopBorder?: boolean
}): React.ReactNode => {
if (slice.isThread && slice.items.length > 3) {
if (slice.isIncompleteThread && slice.items.length >= 3) {
const beforeLast = slice.items.length - 2
const last = slice.items.length - 1
return (
@ -27,25 +27,28 @@ let FeedSlice = ({
key={slice.items[0]._reactKey}
post={slice.items[0].post}
record={slice.items[0].record}
reason={slice.items[0].reason}
feedContext={slice.items[0].feedContext}
reason={slice.reason}
feedContext={slice.feedContext}
parentAuthor={slice.items[0].parentAuthor}
showReplyTo={true}
showReplyTo={false}
moderation={slice.items[0].moderation}
isThreadParent={isThreadParentAt(slice.items, 0)}
isThreadChild={isThreadChildAt(slice.items, 0)}
hideTopBorder={hideTopBorder}
isParentBlocked={slice.items[0].isParentBlocked}
/>
<ViewFullThread slice={slice} />
<ViewFullThread uri={slice.items[0].uri} />
<FeedItem
key={slice.items[beforeLast]._reactKey}
post={slice.items[beforeLast].post}
record={slice.items[beforeLast].record}
reason={slice.items[beforeLast].reason}
feedContext={slice.items[beforeLast].feedContext}
reason={undefined}
feedContext={slice.feedContext}
parentAuthor={slice.items[beforeLast].parentAuthor}
showReplyTo={false}
showReplyTo={
slice.items[beforeLast].parentAuthor?.did !==
slice.items[beforeLast].post.author.did
}
moderation={slice.items[beforeLast].moderation}
isThreadParent={isThreadParentAt(slice.items, beforeLast)}
isThreadChild={isThreadChildAt(slice.items, beforeLast)}
@ -55,8 +58,8 @@ let FeedSlice = ({
key={slice.items[last]._reactKey}
post={slice.items[last].post}
record={slice.items[last].record}
reason={slice.items[last].reason}
feedContext={slice.items[last].feedContext}
reason={undefined}
feedContext={slice.feedContext}
parentAuthor={slice.items[last].parentAuthor}
showReplyTo={false}
moderation={slice.items[last].moderation}
@ -76,8 +79,8 @@ let FeedSlice = ({
key={item._reactKey}
post={slice.items[i].post}
record={slice.items[i].record}
reason={slice.items[i].reason}
feedContext={slice.items[i].feedContext}
reason={i === 0 ? slice.reason : undefined}
feedContext={slice.feedContext}
moderation={slice.items[i].moderation}
parentAuthor={slice.items[i].parentAuthor}
showReplyTo={i === 0}
@ -96,12 +99,12 @@ let FeedSlice = ({
FeedSlice = memo(FeedSlice)
export {FeedSlice}
function ViewFullThread({slice}: {slice: FeedPostSlice}) {
function ViewFullThread({uri}: {uri: string}) {
const pal = usePalette('default')
const itemHref = React.useMemo(() => {
const urip = new AtUri(slice.rootUri)
const urip = new AtUri(uri)
return makeProfileLink({did: urip.hostname, handle: ''}, 'post', urip.rkey)
}, [slice.rootUri])
}, [uri])
return (
<Link style={[styles.viewFullThread]} href={itemHref} asAnchor noFeedback>