Sorta working linear view optimistic state

This commit is contained in:
Eric Bailey
2025-05-20 12:29:05 -05:00
parent 8e2bdecc25
commit 912aaac3f6
4 changed files with 119 additions and 15 deletions
+2
View File
@@ -74,6 +74,7 @@ export function usePostThread({
const items = flatten( const items = flatten(
sort(query.data?.thread || [], { sort(query.data?.thread || [], {
view: params.view,
threadgateHiddenReplies: mergeThreadgateHiddenReplies( threadgateHiddenReplies: mergeThreadgateHiddenReplies(
query.data?.threadgate?.record, query.data?.threadgate?.record,
), ),
@@ -85,6 +86,7 @@ export function usePostThread({
showHidden: state.shownHiddenReplyKinds.has(HiddenReplyKind.Hidden), showHidden: state.shownHiddenReplyKinds.has(HiddenReplyKind.Hidden),
}, },
) )
console.log(items)
const mutator = createCacheMutator({ const mutator = createCacheMutator({
queryKey, queryKey,
+110 -15
View File
@@ -1,10 +1,11 @@
import { import {
AtUri,
AppBskyUnspeccedGetPostThreadV2, AppBskyUnspeccedGetPostThreadV2,
type ModerationDecision, type ModerationDecision,
type ModerationOpts, type ModerationOpts,
} from '@atproto/api' } from '@atproto/api'
import {HiddenReplyKind,type Slice} from '#/state/queries/usePostThread/types' import {HiddenReplyKind, type PostThreadParams, type Slice} from '#/state/queries/usePostThread/types'
import * as views from '#/state/queries/usePostThread/views' import * as views from '#/state/queries/usePostThread/views'
export function flatten( export function flatten(
@@ -58,12 +59,13 @@ export function flatten(
if (hasSession) { if (hasSession) {
for (let i = 0; i < flattened.length; i++) { for (let i = 0; i < flattened.length; i++) {
const item = flattened[i] const item = flattened[i]
if ('depth' in item && item.depth === 0) {
// TODO should not insert if not found post etc
if (item.type === 'threadPost' && item.depth === 0) {
flattened.splice(i + 1, 0, { flattened.splice(i + 1, 0, {
type: 'replyComposer', type: 'replyComposer',
key: 'replyComposer', key: 'replyComposer',
}) })
break
} }
} }
} }
@@ -74,9 +76,11 @@ export function flatten(
export function sort( export function sort(
thread: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'], thread: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'],
{ {
view,
threadgateHiddenReplies, threadgateHiddenReplies,
moderationOpts, moderationOpts,
}: { }: {
view: PostThreadParams['view']
threadgateHiddenReplies: Set<string> threadgateHiddenReplies: Set<string>
moderationOpts: ModerationOpts moderationOpts: ModerationOpts
}, },
@@ -181,29 +185,97 @@ export function sort(
const isFirstReply = const isFirstReply =
lastSlice.type === 'replyComposer' || lastSlice.type === 'replyComposer' ||
(lastSlice.type === 'threadPost' && lastSlice.depth === 0) (lastSlice.type === 'threadPost' && lastSlice.depth === 0)
const parent = views.threadPost({ const oneUp = isFirstReply ? undefined : thread.at(i - 1)
const oneDown = thread.at(i + 1)
const post = views.threadPost({
uri: item.uri, uri: item.uri,
depth: item.depth, depth: item.depth,
value: item.value, value: item.value,
oneUp: isFirstReply ? undefined : thread[i - 1], oneUp,
oneDown: thread[i + 1], oneDown,
moderationOpts, moderationOpts,
}) })
const parentMod = getModerationState(parent.moderation) const postMod = getModerationState(post.moderation)
const parentIsHidden = threadgateHiddenReplies.has(item.uri) const postIsHidden = threadgateHiddenReplies.has(item.uri)
const parentIsTopLevelReply = item.depth === 1 const postIsModerated =
const parentIsModerated = postIsHidden || postMod.blurred || postMod.muted
parentIsHidden || parentMod.blurred || parentMod.muted
if (!parentIsModerated) { if (!postIsModerated) {
/* /*
* Not hidden, so show it * Not moderated, probably need to insert it
*/ */
items.push(parent) // items.push(post)
if (view === 'tree') {
items.push(post)
} else {
if (post.depth > 1) {
const maybeNextSiblingIndex = getBranch(thread, i, post.depth).end + 1
const maybeNextSibling = thread.at(maybeNextSiblingIndex)
/*
* If we've got two replies at the same depth, we need to decide
* which one to show.
*/
if (post.depth === maybeNextSibling?.depth) {
// continue with next sibling
i = maybeNextSiblingIndex - 1
debugger;
continue traversal
} else {
const maybePrevSiblingIndex = getBranchUp(thread, i - 1, post.depth).end
const maybePrevSibling = thread.at(maybePrevSiblingIndex)
if (post.depth === maybePrevSibling?.depth) {
const post = views.threadPost({
uri: item.uri,
depth: item.depth,
value: item.value,
oneUp: thread.at(maybePrevSiblingIndex - 1),
oneDown,
moderationOpts,
})
debugger;
items.push(post)
} else {
items.push(post)
}
}
/*
if (post.depth === oneDown?.depth) {
const opDid = new AtUri(post.value.post.record.reply?.root?.uri).host
const postAuthorDid = new AtUri(post.uri).host
debugger;
if (postAuthorDid === opDid) {
// prioritize OP optimistic reply
items.push(post)
// skip next reply
i = getBranch(thread, i, oneDown.depth).end
debugger;
continue traversal
} else {
i = getBranch(thread, i, post.depth).end
debugger;
continue traversal
}
}
*/
} else {
items.push(post)
}
}
} else { } else {
const branch = getBranch(thread, i, item.depth) /*
* Moderated in some way, we're going to walk children
*/
const parent = post
const parentMod = postMod
const parentIsTopLevelReply = parent.depth === 1
const sortArray = parentMod.muted ? muted : hidden const sortArray = parentMod.muted ? muted : hidden
// get sub tree
const branch = getBranch(thread, i, item.depth)
if (parentIsTopLevelReply) { if (parentIsTopLevelReply) {
// push branch anchor into sorted array // push branch anchor into sorted array
sortArray.push(parent) sortArray.push(parent)
@@ -302,6 +374,29 @@ function getBranch(
} }
} }
function getBranchUp(
thread: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'],
branchStartIndex: number,
branchEndDepth: number,
) {
let start = branchStartIndex
for (let ci = branchStartIndex; ci >= 0; ci--) {
const next = thread[ci]
if (next.depth > branchEndDepth) {
start = ci
} else {
start = ci
break
}
}
return {
start,
end: branchStartIndex,
}
}
export function getModerationState(moderation: ModerationDecision) { export function getModerationState(moderation: ModerationDecision) {
const modui = moderation.ui('contentList') const modui = moderation.ui('contentList')
const blurred = modui.blur || modui.filter const blurred = modui.blur || modui.filter
+5
View File
@@ -80,3 +80,8 @@ export type Slice =
key: string key: string
kind: HiddenReplyKind kind: HiddenReplyKind
} }
| {
type: 'threadPostNoOp'
key: string
comment: string
}
+2
View File
@@ -98,6 +98,8 @@ export function threadPost({
} }
} }
// export function threadPostNoOp({ })
export function postViewToThreadPlaceholder( export function postViewToThreadPlaceholder(
post: AppBskyFeedDefs.PostView, post: AppBskyFeedDefs.PostView,
): $Typed< ): $Typed<