Checkpoint, need to fix blocked posts
This commit is contained in:
@@ -2,7 +2,6 @@ import {View} from 'react-native'
|
|||||||
import {msg, Plural, Trans} from '@lingui/macro'
|
import {msg, Plural, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
|
||||||
import {type PostThreadParams, type Slice} from '#/state/queries/usePostThread'
|
import {type PostThreadParams, type Slice} from '#/state/queries/usePostThread'
|
||||||
import {
|
import {
|
||||||
LINEAR_AVI_WIDTH,
|
LINEAR_AVI_WIDTH,
|
||||||
@@ -28,19 +27,22 @@ export function ReadMore({
|
|||||||
const indent = Math.max(0, item.indent - 1)
|
const indent = Math.max(0, item.indent - 1)
|
||||||
|
|
||||||
const spacers = isTreeView
|
const spacers = isTreeView
|
||||||
? Array.from(Array(indent)).map((_, n: number) => (
|
? Array.from(Array(indent)).map((_, n: number) => {
|
||||||
|
const isSkipped = item.skippedIndents.has(n)
|
||||||
|
return (
|
||||||
<View
|
<View
|
||||||
key={`${item.key}-padding-${n}`}
|
key={`${item.key}-padding-${n}`}
|
||||||
style={[
|
style={[
|
||||||
t.atoms.border_contrast_low,
|
t.atoms.border_contrast_low,
|
||||||
{
|
{
|
||||||
borderRightWidth: REPLY_LINE_WIDTH,
|
borderRightWidth: isSkipped ? 0 : REPLY_LINE_WIDTH,
|
||||||
width: TREE_INDENT + TREE_AVI_WIDTH / 2,
|
width: TREE_INDENT + TREE_AVI_WIDTH / 2,
|
||||||
left: 1,
|
left: 1,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
))
|
)
|
||||||
|
})
|
||||||
: null
|
: null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -63,14 +65,7 @@ export function ReadMore({
|
|||||||
/>
|
/>
|
||||||
<Link
|
<Link
|
||||||
label={_(msg`Read more replies`)}
|
label={_(msg`Read more replies`)}
|
||||||
to={makeProfileLink(
|
to={item.href}
|
||||||
{
|
|
||||||
did: item.nextAnchorUri.host,
|
|
||||||
handle: item.nextAnchor.value.post.author.handle,
|
|
||||||
},
|
|
||||||
'post',
|
|
||||||
item.nextAnchorUri.rkey,
|
|
||||||
)}
|
|
||||||
style={[a.pt_sm, a.pb_md, a.gap_xs]}>
|
style={[a.pt_sm, a.pb_md, a.gap_xs]}>
|
||||||
{({hovered, pressed}) => {
|
{({hovered, pressed}) => {
|
||||||
return (
|
return (
|
||||||
@@ -83,8 +78,8 @@ export function ReadMore({
|
|||||||
(hovered || pressed) && a.underline,
|
(hovered || pressed) && a.underline,
|
||||||
]}>
|
]}>
|
||||||
<Trans>
|
<Trans>
|
||||||
Read {item.replyCount} more{' '}
|
Read {item.moreReplies} more{' '}
|
||||||
<Plural one="reply" other="replies" value={item.replyCount} />
|
<Plural one="reply" other="replies" value={item.moreReplies} />
|
||||||
</Trans>
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function usePostThread({
|
|||||||
const {data} = await agent.app.bsky.unspecced.getPostThreadV2({
|
const {data} = await agent.app.bsky.unspecced.getPostThreadV2({
|
||||||
anchor: params.anchor!,
|
anchor: params.anchor!,
|
||||||
branchingFactor: params.view === 'linear' ? 1 : 3, // 100 TODO
|
branchingFactor: params.view === 'linear' ? 1 : 3, // 100 TODO
|
||||||
below: 6,
|
below: 3,
|
||||||
sort: params.sort,
|
sort: params.sort,
|
||||||
prioritizeFollowedUsers: params.prioritizeFollowedUsers,
|
prioritizeFollowedUsers: params.prioritizeFollowedUsers,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ export function flatten(
|
|||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
const flattened: Slice[] = sorted.items
|
const flattened: Slice[] = sorted.items
|
||||||
const parents = []
|
|
||||||
|
|
||||||
for (let i = 0; i < flattened.length; i++) {
|
for (let i = 0; i < flattened.length; i++) {
|
||||||
const item = flattened[i]
|
const item = flattened[i]
|
||||||
@@ -49,103 +48,6 @@ export function flatten(
|
|||||||
key: 'replyComposer',
|
key: 'replyComposer',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const deepestParent = parents[parents.length - 1]
|
|
||||||
|
|
||||||
if (deepestParent) {
|
|
||||||
// next item is a sibling or an aunt/uncle
|
|
||||||
if (item.depth <= deepestParent.depth) {
|
|
||||||
for (let pi = parents.length - 1; pi >= 0; pi--) {
|
|
||||||
const parent = parents[pi]
|
|
||||||
|
|
||||||
if (item.depth <= parent.depth) {
|
|
||||||
/*
|
|
||||||
* Find the previous post item and set the read more flags
|
|
||||||
*/
|
|
||||||
for (let ui = i - 1; ui >= 0; ui--) {
|
|
||||||
let prev = flattened[ui]
|
|
||||||
if (prev.type === 'threadPost') {
|
|
||||||
prev.ui.precedesParentReadMore =
|
|
||||||
prev.ui.indent - 1 === parent.ui.indent // true
|
|
||||||
prev.ui.precedesChildReadMore =
|
|
||||||
prev.ui.indent === item.ui.indent
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flattened.splice(
|
|
||||||
i + 1 + (pi - parents.length),
|
|
||||||
0,
|
|
||||||
views.readMore({
|
|
||||||
parent,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
parents.pop()
|
|
||||||
|
|
||||||
// skip next iteration
|
|
||||||
i++
|
|
||||||
|
|
||||||
if (view === 'linear') {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.value.moreReplies > 0) {
|
|
||||||
parents.push(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
const isLastIteration = i === flattened.length - 1
|
|
||||||
|
|
||||||
if (isLastIteration) {
|
|
||||||
const deepestParent = parents[parents.length - 1]
|
|
||||||
|
|
||||||
if (deepestParent) {
|
|
||||||
// next item is a sibling or an aunt/uncle
|
|
||||||
if (deepestParent.depth <= item.depth) {
|
|
||||||
for (let pi = parents.length - 1; pi >= 0; pi--) {
|
|
||||||
const parent = parents[pi]
|
|
||||||
if (parent.depth <= item.depth) {
|
|
||||||
/*
|
|
||||||
* Find the previous post item and set the read more flags
|
|
||||||
*/
|
|
||||||
for (let ui = i; ui >= 0; ui--) {
|
|
||||||
let prev = flattened[ui]
|
|
||||||
if (prev.type === 'threadPost') {
|
|
||||||
prev.ui.precedesParentReadMore =
|
|
||||||
prev.ui.indent - 1 === parent.ui.indent
|
|
||||||
prev.ui.precedesChildReadMore =
|
|
||||||
prev.ui.indent === item.ui.indent
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flattened.splice(
|
|
||||||
i + 2 + (pi - parents.length),
|
|
||||||
0,
|
|
||||||
views.readMore({
|
|
||||||
parent,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
parents.pop()
|
|
||||||
|
|
||||||
// skip next iteration
|
|
||||||
i++
|
|
||||||
|
|
||||||
if (view === 'linear') {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,10 +212,23 @@ export function sort(
|
|||||||
continue traversal
|
continue traversal
|
||||||
} else if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) {
|
} else if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) {
|
||||||
if (parentMetadata) {
|
if (parentMetadata) {
|
||||||
|
if (metadata) {
|
||||||
|
metadata.replyIndex = parentMetadata.seenReplies
|
||||||
|
}
|
||||||
|
|
||||||
parentMetadata.seenReplies += 1
|
parentMetadata.seenReplies += 1
|
||||||
|
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
metadata.isLastSibling =
|
metadata.isLastSibling =
|
||||||
parentMetadata.replies === parentMetadata.seenReplies
|
parentMetadata.replies - parentMetadata.unhydratedReplies ===
|
||||||
|
parentMetadata.seenReplies
|
||||||
|
|
||||||
|
if (
|
||||||
|
parentMetadata.unhydratedReplies > 0 &&
|
||||||
|
metadata.isLastSibling
|
||||||
|
) {
|
||||||
|
metadata.upcomingParentReadMore = parentMetadata
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,8 +284,16 @@ export function sort(
|
|||||||
if (childParentMetadata) {
|
if (childParentMetadata) {
|
||||||
childParentMetadata.seenReplies += 1
|
childParentMetadata.seenReplies += 1
|
||||||
childMetadata.isLastSibling =
|
childMetadata.isLastSibling =
|
||||||
childParentMetadata.replies ===
|
childParentMetadata.replies -
|
||||||
|
childParentMetadata.unhydratedReplies ===
|
||||||
childParentMetadata.seenReplies
|
childParentMetadata.seenReplies
|
||||||
|
|
||||||
|
if (
|
||||||
|
childParentMetadata.unhydratedReplies > 0 &&
|
||||||
|
childMetadata.isLastSibling
|
||||||
|
) {
|
||||||
|
childMetadata.upcomingParentReadMore = childParentMetadata
|
||||||
|
}
|
||||||
}
|
}
|
||||||
metadatas.set(item.uri, childMetadata)
|
metadatas.set(item.uri, childMetadata)
|
||||||
metadatas.set(childMetadata.text, childMetadata) // TODO debugging
|
metadatas.set(childMetadata.text, childMetadata) // TODO debugging
|
||||||
@@ -418,7 +341,9 @@ export function sort(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const item of items) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
const item = items[i]
|
||||||
|
|
||||||
if (item.type === 'threadPost') {
|
if (item.type === 'threadPost') {
|
||||||
const metadata = metadatas.get(item.uri)
|
const metadata = metadatas.get(item.uri)
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
@@ -426,9 +351,31 @@ export function sort(
|
|||||||
metadata.skippedIndents = new Set([
|
metadata.skippedIndents = new Set([
|
||||||
...metadata.parentMetadata.skippedIndents,
|
...metadata.parentMetadata.skippedIndents,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
if (
|
||||||
|
metadata.isLastSibling &&
|
||||||
|
metadata.parentMetadata.unhydratedReplies <= 0
|
||||||
|
) {
|
||||||
|
metadata.skippedIndents.add(item.depth - 2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (metadata.isLastSibling) {
|
|
||||||
metadata.skippedIndents.add(item.depth - 2)
|
if (
|
||||||
|
metadata.unhydratedReplies > 0 &&
|
||||||
|
(metadata.nextItemDepth === undefined ||
|
||||||
|
metadata.nextItemDepth <= item.depth)
|
||||||
|
) {
|
||||||
|
items.splice(i + 1, 0, views.readMore(metadata))
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.upcomingParentReadMore && metadata.isDeadEnd) {
|
||||||
|
items.splice(
|
||||||
|
i + 1,
|
||||||
|
0,
|
||||||
|
views.readMore(metadata.upcomingParentReadMore),
|
||||||
|
)
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
item.ui = getThreadPostUI(metadata)
|
item.ui = getThreadPostUI(metadata)
|
||||||
@@ -436,8 +383,6 @@ export function sort(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log(metadatas)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items,
|
items,
|
||||||
hidden,
|
hidden,
|
||||||
|
|||||||
@@ -101,14 +101,13 @@ export type Slice =
|
|||||||
type: 'readMore'
|
type: 'readMore'
|
||||||
key: string
|
key: string
|
||||||
indent: number
|
indent: number
|
||||||
replyCount: number
|
href: string
|
||||||
nextAnchor: Extract<Slice, {type: 'threadPost'}>
|
moreReplies: number
|
||||||
nextAnchorUri: AtUri
|
skippedIndents: Set<number>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TraversalMetadata = {
|
export type TraversalMetadata = {
|
||||||
depth: number
|
depth: number
|
||||||
indent: number
|
|
||||||
replies: number
|
replies: number
|
||||||
unhydratedReplies: number
|
unhydratedReplies: number
|
||||||
seenReplies: number
|
seenReplies: number
|
||||||
|
|||||||
@@ -65,11 +65,9 @@ export function getTraversalMetadata({
|
|||||||
const hasBranchingReplies = replies > 1 && replies - unhydratedReplies > 1
|
const hasBranchingReplies = replies > 1 && replies - unhydratedReplies > 1
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
uri: item.uri,
|
||||||
depth: item.depth,
|
depth: item.depth,
|
||||||
// TODO maybe not used
|
authorHandle: item.value.post.author.handle,
|
||||||
indent: parentMetadata?.hasBranchingReplies
|
|
||||||
? item.depth
|
|
||||||
: parentMetadata?.indent || item.depth,
|
|
||||||
replies,
|
replies,
|
||||||
unhydratedReplies,
|
unhydratedReplies,
|
||||||
seenReplies: 0,
|
seenReplies: 0,
|
||||||
@@ -79,6 +77,13 @@ export function getTraversalMetadata({
|
|||||||
skippedIndents: new Set(),
|
skippedIndents: new Set(),
|
||||||
prevItemDepth: prevItem?.depth,
|
prevItemDepth: prevItem?.depth,
|
||||||
nextItemDepth: nextItem?.depth,
|
nextItemDepth: nextItem?.depth,
|
||||||
|
/*
|
||||||
|
* If there are no slices below this one, or the next slice is less
|
||||||
|
* indented than the computed indent for this post.
|
||||||
|
*/
|
||||||
|
isDeadEnd: nextItem?.depth === undefined || nextItem?.depth < item.depth,
|
||||||
|
|
||||||
|
upcomingParentReadMore: parentMetadata?.upcomingParentReadMore || undefined,
|
||||||
|
|
||||||
// TODO non-spec
|
// TODO non-spec
|
||||||
text: getPostRecord(item.value.post).text,
|
text: getPostRecord(item.value.post).text,
|
||||||
@@ -87,25 +92,27 @@ export function getTraversalMetadata({
|
|||||||
|
|
||||||
export function getThreadPostUI({
|
export function getThreadPostUI({
|
||||||
depth,
|
depth,
|
||||||
indent,
|
|
||||||
replies,
|
replies,
|
||||||
parentMetadata,
|
parentMetadata,
|
||||||
prevItemDepth,
|
prevItemDepth,
|
||||||
nextItemDepth,
|
isDeadEnd,
|
||||||
skippedIndents,
|
skippedIndents,
|
||||||
|
seenReplies,
|
||||||
|
unhydratedReplies,
|
||||||
}: TraversalMetadata): Extract<Slice, {type: 'threadPost'}>['ui'] {
|
}: TraversalMetadata): Extract<Slice, {type: 'threadPost'}>['ui'] {
|
||||||
|
const isReplyAndHasReplies = depth > 0 && replies > 0 && ((replies - unhydratedReplies) === seenReplies || seenReplies > 0)
|
||||||
return {
|
return {
|
||||||
isAnchor: depth === 0,
|
isAnchor: depth === 0,
|
||||||
showParentReplyLine:
|
showParentReplyLine:
|
||||||
!!prevItemDepth && prevItemDepth !== 0 && prevItemDepth < depth,
|
!!prevItemDepth && prevItemDepth !== 0 && prevItemDepth < depth,
|
||||||
showChildReplyLine: replies > 0,
|
showChildReplyLine: depth < 0 || isReplyAndHasReplies,
|
||||||
indent: depth,
|
indent: depth,
|
||||||
parentHasBranchingReplies: !!parentMetadata?.hasBranchingReplies,
|
parentHasBranchingReplies: !!parentMetadata?.hasBranchingReplies,
|
||||||
/*
|
/*
|
||||||
* If there are no slices below this one, or the next slice is less
|
* If there are no slices below this one, or the next slice is less
|
||||||
* indented than the computed indent for this post.
|
* indented than the computed indent for this post.
|
||||||
*/
|
*/
|
||||||
isDeadEnd: nextItemDepth === undefined || nextItemDepth < indent,
|
isDeadEnd, //nextItemDepth === undefined || nextItemDepth < depth,
|
||||||
skippedIndents,
|
skippedIndents,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import {
|
|||||||
type ModerationOpts,
|
type ModerationOpts,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
|
|
||||||
import {type Slice} from '#/state/queries/usePostThread/types'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
|
import {type Slice, type TraversalMetadata} from '#/state/queries/usePostThread/types'
|
||||||
|
|
||||||
export function threadPostNoUnauthenticated({
|
export function threadPostNoUnauthenticated({
|
||||||
uri,
|
uri,
|
||||||
@@ -94,19 +95,28 @@ export function threadPost({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function readMore({
|
export function readMore({
|
||||||
parent,
|
uri,
|
||||||
}: {
|
authorHandle,
|
||||||
parent: Extract<Slice, {type: 'threadPost'}>
|
unhydratedReplies: moreReplies,
|
||||||
}) {
|
depth: indent,
|
||||||
|
skippedIndents,
|
||||||
|
}: TraversalMetadata): Extract<Slice, {type: 'readMore'}> {
|
||||||
|
const urip = new AtUri(uri)
|
||||||
|
const href = makeProfileLink(
|
||||||
|
{
|
||||||
|
did: urip.host,
|
||||||
|
handle: authorHandle,
|
||||||
|
},
|
||||||
|
'post',
|
||||||
|
urip.rkey,
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
type: 'readMore' as const,
|
type: 'readMore' as const,
|
||||||
key: `readMore:${parent.uri}`,
|
key: `readMore:${uri}`,
|
||||||
indent: parent.ui.parentHasBranchingReplies
|
href,
|
||||||
? parent.depth
|
moreReplies,
|
||||||
: parent.ui.indent,
|
indent,
|
||||||
replyCount: parent.value.moreReplies,
|
skippedIndents,
|
||||||
nextAnchor: parent,
|
|
||||||
nextAnchorUri: new AtUri(parent.uri),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user