From 8e2bdecc25faf1c44ef96ce781edac1fa4003667 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 19 May 2025 18:17:21 -0500 Subject: [PATCH] Update types --- src/state/queries/usePostThread/index.ts | 17 +- src/state/queries/usePostThread/queryCache.ts | 62 +++++--- src/state/queries/usePostThread/traversal.ts | 112 +++++++------ src/state/queries/usePostThread/types.ts | 26 +-- src/state/queries/usePostThread/views.ts | 148 +++++++++++------- src/view/com/composer/Composer.tsx | 44 +++--- src/view/screens/PostThread.tsx | 66 ++++---- 7 files changed, 283 insertions(+), 192 deletions(-) diff --git a/src/state/queries/usePostThread/index.ts b/src/state/queries/usePostThread/index.ts index 09c2c05012..bd1fa512fd 100644 --- a/src/state/queries/usePostThread/index.ts +++ b/src/state/queries/usePostThread/index.ts @@ -1,8 +1,11 @@ import {useQuery, useQueryClient} from '@tanstack/react-query' import {useModerationOpts} from '#/state/preferences/moderation-opts' -import {getThreadPlaceholder, createCacheMutator} from '#/state/queries/usePostThread/queryCache' -import {flatten,sort} from '#/state/queries/usePostThread/traversal' +import { + createCacheMutator, + getThreadPlaceholder, +} from '#/state/queries/usePostThread/queryCache' +import {flatten, sort} from '#/state/queries/usePostThread/traversal' import { createPostThreadQueryKey, HiddenReplyKind, @@ -31,9 +34,9 @@ export function usePostThread({ const enabled = isEnabled !== false && !!uri && !!moderationOpts const queryKey = createPostThreadQueryKey({ - uri, - params, - }) + uri, + params, + }) const query = useQuery({ enabled, @@ -41,7 +44,7 @@ export function usePostThread({ async queryFn() { const {data} = await agent.app.bsky.unspecced.getPostThreadV2({ uri: uri!, - branchingFactor: params.view === 'linear' ? 1 : 10, + nestedBranchingFactor: params.view === 'linear' ? 1 : 10, below: 10, sorting: mapSortOptionsToSortID(params.sort), }) @@ -91,7 +94,7 @@ export function usePostThread({ return { ...query, data: { - slices: items, + items, threadgate: query.data?.threadgate, }, insertReplies: mutator.insertReplies, diff --git a/src/state/queries/usePostThread/queryCache.ts b/src/state/queries/usePostThread/queryCache.ts index 0e8efdb80d..6353f82b2d 100644 --- a/src/state/queries/usePostThread/queryCache.ts +++ b/src/state/queries/usePostThread/queryCache.ts @@ -1,9 +1,4 @@ -import { - type $Typed, - AppBskyUnspeccedDefs, - type AppBskyUnspeccedGetPostThreadV2, - AtUri, -} from '@atproto/api' +import {type $Typed, AppBskyUnspeccedGetPostThreadV2, AtUri} from '@atproto/api' import {type QueryClient} from '@tanstack/react-query' import {findAllPostsInQueryData as findAllPostsInExploreFeedPreviewsQueryData} from '#/state/queries/explore-feed-previews' @@ -12,8 +7,8 @@ import {findAllPostsInQueryData as findAllPostsInFeedQueryData} from '#/state/qu import {findAllPostsInQueryData as findAllPostsInQuoteQueryData} from '#/state/queries/post-quotes' import {findAllPostsInQueryData as findAllPostsInSearchQueryData} from '#/state/queries/search-posts' import { + type createPostThreadQueryKey, postThreadQueryKeyRoot, - createPostThreadQueryKey, } from '#/state/queries/usePostThread/types' import { embedViewToThreadPlaceholder, @@ -30,8 +25,8 @@ export function createCacheMutator({ }) { return { insertReplies( - parent: AppBskyUnspeccedDefs.ThreadItemPost, - replies: AppBskyUnspeccedDefs.ThreadItemPost[], + parent: AppBskyUnspeccedGetPostThreadV2.ThreadItem, + replies: AppBskyUnspeccedGetPostThreadV2.ThreadItem[], ) { queryClient.setQueryData( queryKey, @@ -41,16 +36,23 @@ export function createCacheMutator({ const thread = [...queryData.thread] for (let i = 0; i < thread.length; i++) { - const anchor = thread[i] - if (!AppBskyUnspeccedDefs.isThreadItemPost(anchor)) continue - if (anchor.uri !== parent.uri) continue + const existingParent = thread[i] + if ( + !AppBskyUnspeccedGetPostThreadV2.isThreadItemPost( + existingParent.value, + ) + ) + continue + if (!AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(parent.value)) + continue + if (existingParent.uri !== parent.uri) continue /* * Update parent data */ - anchor.post = { - ...anchor.post, - replyCount: parent.post.replyCount, + existingParent.value.post = { + ...existingParent.value.post, + replyCount: parent.value.post.replyCount, } /* @@ -58,11 +60,14 @@ export function createCacheMutator({ */ for (let ri = 0; ri < replies.length; ri++) { const reply = replies[ri] - reply.depth = anchor.depth + 1 + ri + if ( + !AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(reply.value) + ) + continue const insertIndex = i + 1 + ri thread.splice(insertIndex, 0, { - $type: 'app.bsky.unspecced.defs#threadItemPost', ...reply, + depth: existingParent.depth + 1 + ri, }) } } @@ -74,14 +79,14 @@ export function createCacheMutator({ }, ) }, - deletePost(post: AppBskyUnspeccedDefs.ThreadItemPost) {}, + deletePost(_post: AppBskyUnspeccedGetPostThreadV2.ThreadItem) {}, } } export function getThreadPlaceholder( queryClient: QueryClient, uri: string, -): $Typed | void { +): $Typed | void { let partial for (let item of getThreadPlaceholderCandidates(queryClient, uri)) { /* @@ -92,7 +97,7 @@ export function getThreadPlaceholder( * * TODO can we send in feeds and quotes? */ - const hasAllInfo = item.post.likeCount != null + const hasAllInfo = item.value.post.likeCount != null if (hasAllInfo) { return item } else { @@ -106,7 +111,14 @@ export function getThreadPlaceholder( export function* getThreadPlaceholderCandidates( queryClient: QueryClient, uri: string, -): Generator<$Typed, void> { +): Generator< + $Typed< + Omit & { + value: $Typed + } + >, + void +> { const atUri = new AtUri(uri) /* @@ -123,15 +135,17 @@ export function* getThreadPlaceholderCandidates( const {thread} = queryData for (const item of thread) { - if (AppBskyUnspeccedDefs.isThreadItemPost(item)) { - if (didOrHandleUriMatches(atUri, item.post)) { + if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) { + if (didOrHandleUriMatches(atUri, item.value.post)) { yield { + $type: 'app.bsky.unspecced.getPostThreadV2#threadItem', ...item, depth: 0, + value: item.value, } } - const qp = getEmbeddedPost(item.post.embed) + const qp = getEmbeddedPost(item.value.post.embed) if (qp && didOrHandleUriMatches(atUri, qp)) { yield embedViewToThreadPlaceholder(qp) } diff --git a/src/state/queries/usePostThread/traversal.ts b/src/state/queries/usePostThread/traversal.ts index e57e0ddb39..013b17252b 100644 --- a/src/state/queries/usePostThread/traversal.ts +++ b/src/state/queries/usePostThread/traversal.ts @@ -1,6 +1,5 @@ import { - AppBskyUnspeccedDefs, - type AppBskyUnspeccedGetPostThreadV2, + AppBskyUnspeccedGetPostThreadV2, type ModerationDecision, type ModerationOpts, } from '@atproto/api' @@ -20,7 +19,7 @@ export function flatten( showHidden: boolean }, ) { - const flattened: Slice[] = sorted.slices + const flattened: Slice[] = sorted.items if (sorted.hidden.length) { if (showHidden) { @@ -58,8 +57,8 @@ export function flatten( if (hasSession) { for (let i = 0; i < flattened.length; i++) { - const slice = flattened[i] - if ('slice' in slice && slice.slice.depth === 0) { + const item = flattened[i] + if ('depth' in item && item.depth === 0) { flattened.splice(i + 1, 0, { type: 'replyComposer', key: 'replyComposer', @@ -82,32 +81,39 @@ export function sort( moderationOpts: ModerationOpts }, ) { - const slices: Slice[] = [] + const items: Slice[] = [] const hidden: Slice[] = [] const muted: Slice[] = [] traversal: for (let i = 0; i < thread.length; i++) { const item = thread[i] - // ignore unknowns - if (!('depth' in item)) continue - if (item.depth < 0) { /* * Parents are ignored until we find the highlighted post, then we walk * _up_ from there. */ } else if (item.depth === 0) { - if (AppBskyUnspeccedDefs.isThreadItemNoUnauthenticated(item)) { - slices.push(views.noUnauthenticated({item})) - } else if (AppBskyUnspeccedDefs.isThreadItemNotFound(item)) { - slices.push(views.notFound({item})) - } else if (AppBskyUnspeccedDefs.isThreadItemBlocked(item)) { - slices.push(views.blocked({item})) - } else if (AppBskyUnspeccedDefs.isThreadItemPost(item)) { - slices.push( - views.post({ - item, + if ( + AppBskyUnspeccedGetPostThreadV2.isThreadItemNoUnauthenticated( + item.value, + ) + ) { + items.push(views.threadPostNoUnauthenticated(item)) + } else if ( + AppBskyUnspeccedGetPostThreadV2.isThreadItemNotFound(item.value) + ) { + items.push(views.threadPostNotFound(item)) + } else if ( + AppBskyUnspeccedGetPostThreadV2.isThreadItemBlocked(item.value) + ) { + items.push(views.threadPostBlocked(item)) + } else if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) { + items.push( + views.threadPost({ + uri: item.uri, + depth: item.depth, + value: item.value, oneUp: thread[i - 1], oneDown: thread[i + 1], moderationOpts, @@ -119,19 +125,31 @@ export function sort( const parent = thread[pi] const parentOneUp = thread[pi - 1] - if (AppBskyUnspeccedDefs.isThreadItemNoUnauthenticated(parent)) { - slices.unshift(views.noUnauthenticated({item: parent})) + if ( + AppBskyUnspeccedGetPostThreadV2.isThreadItemNoUnauthenticated( + parent.value, + ) + ) { + items.unshift(views.threadPostNoUnauthenticated(parent)) break parentTraversal - } else if (AppBskyUnspeccedDefs.isThreadItemNotFound(parent)) { - slices.unshift(views.notFound({item: parent})) + } else if ( + AppBskyUnspeccedGetPostThreadV2.isThreadItemNotFound(parent.value) + ) { + items.unshift(views.threadPostNotFound(parent)) break parentTraversal - } else if (AppBskyUnspeccedDefs.isThreadItemBlocked(parent)) { - slices.unshift(views.blocked({item: parent})) + } else if ( + AppBskyUnspeccedGetPostThreadV2.isThreadItemBlocked(parent.value) + ) { + items.unshift(views.threadPostBlocked(parent)) break parentTraversal - } else if (AppBskyUnspeccedDefs.isThreadItemPost(parent)) { - slices.unshift( - views.post({ - item: parent, + } else if ( + AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(parent.value) + ) { + items.unshift( + views.threadPost({ + uri: parent.uri, + depth: parent.depth, + value: parent.value, oneUp: parentOneUp, oneDown: parentOneDown, moderationOpts, @@ -147,22 +165,26 @@ export function sort( * we could. */ const shouldBreak = - AppBskyUnspeccedDefs.isThreadItemNoUnauthenticated(item) || - AppBskyUnspeccedDefs.isThreadItemNotFound(item) || - AppBskyUnspeccedDefs.isThreadItemBlocked(item) + AppBskyUnspeccedGetPostThreadV2.isThreadItemNoUnauthenticated( + item.value, + ) || + AppBskyUnspeccedGetPostThreadV2.isThreadItemNotFound(item.value) || + AppBskyUnspeccedGetPostThreadV2.isThreadItemBlocked(item.value) if (shouldBreak) { const branch = getBranch(thread, i, item.depth) // could insert tombstone i = branch.end continue traversal - } else if (AppBskyUnspeccedDefs.isThreadItemPost(item)) { - const lastSlice = slices[slices.length - 1] + } else if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) { + const lastSlice = items[items.length - 1] const isFirstReply = lastSlice.type === 'replyComposer' || - (lastSlice.type === 'threadSlice' && lastSlice.slice.depth === 0) - const parent = views.post({ - item, + (lastSlice.type === 'threadPost' && lastSlice.depth === 0) + const parent = views.threadPost({ + uri: item.uri, + depth: item.depth, + value: item.value, oneUp: isFirstReply ? undefined : thread[i - 1], oneDown: thread[i + 1], moderationOpts, @@ -177,7 +199,7 @@ export function sort( /* * Not hidden, so show it */ - slices.push(parent) + items.push(parent) } else { const branch = getBranch(thread, i, item.depth) const sortArray = parentMod.muted ? muted : hidden @@ -191,9 +213,13 @@ export function sort( for (let ci = startIndex; ci <= branch.end; ci++) { const child = thread[ci] - if (AppBskyUnspeccedDefs.isThreadItemPost(child)) { - const childPost = views.post({ - item: child, + if ( + AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(child.value) + ) { + const childPost = views.threadPost({ + uri: child.uri, + depth: child.depth, + value: child.value, oneUp: thread[ci - 1], oneDown: thread[ci + 1], moderationOpts, @@ -231,7 +257,7 @@ export function sort( } return { - slices, + items, hidden, muted, } @@ -262,8 +288,6 @@ function getBranch( for (let ci = branchStartIndex + 1; ci < thread.length; ci++) { const next = thread[ci] - // ignore unknowns - if (!('depth' in next)) continue if (next.depth > branchStartDepth) { end = ci } else { diff --git a/src/state/queries/usePostThread/types.ts b/src/state/queries/usePostThread/types.ts index 4b4bae3ae8..13d561c223 100644 --- a/src/state/queries/usePostThread/types.ts +++ b/src/state/queries/usePostThread/types.ts @@ -1,7 +1,7 @@ import { type AppBskyFeedDefs, type AppBskyFeedPost, - type AppBskyUnspeccedDefs, + type AppBskyUnspeccedGetPostThreadV2, type BskyThreadViewPreference, type ModerationDecision, } from '@atproto/api' @@ -34,9 +34,11 @@ export enum HiddenReplyKind { export type Slice = | { - type: 'threadSlice' + type: 'threadPost' key: string - slice: Omit & { + uri: string + depth: number + value: Omit & { post: Omit & { record: AppBskyFeedPost.Record } @@ -49,19 +51,25 @@ export type Slice = } } | { - type: 'threadSliceNoUnauthenticated' + type: 'threadPostNoUnauthenticated' key: string - slice: AppBskyUnspeccedDefs.ThreadItemNoUnauthenticated + uri: string + depth: number + value: AppBskyUnspeccedGetPostThreadV2.ThreadItemNoUnauthenticated } | { - type: 'threadSliceNotFound' + type: 'threadPostNotFound' key: string - slice: AppBskyUnspeccedDefs.ThreadItemNotFound + uri: string + depth: number + value: AppBskyUnspeccedGetPostThreadV2.ThreadItemNotFound } | { - type: 'threadSliceBlocked' + type: 'threadPostBlocked' key: string - slice: AppBskyUnspeccedDefs.ThreadItemBlocked + uri: string + depth: number + value: AppBskyUnspeccedGetPostThreadV2.ThreadItemBlocked } | { type: 'replyComposer' diff --git a/src/state/queries/usePostThread/views.ts b/src/state/queries/usePostThread/views.ts index b2f4563374..dd0f083008 100644 --- a/src/state/queries/usePostThread/views.ts +++ b/src/state/queries/usePostThread/views.ts @@ -3,7 +3,6 @@ import { type AppBskyEmbedRecord, type AppBskyFeedDefs, type AppBskyFeedPost, - type AppBskyUnspeccedDefs, type AppBskyUnspeccedGetPostThreadV2, moderatePost, type ModerationOpts, @@ -12,102 +11,137 @@ import { import {type Slice} from '#/state/queries/usePostThread/types' import {embedViewRecordToPostView} from '#/state/queries/util' -export function noUnauthenticated({ - item, -}: { - item: AppBskyUnspeccedDefs.ThreadItemNoUnauthenticated -}): Extract { +export function threadPostNoUnauthenticated({ + uri, + depth, + value, +}: AppBskyUnspeccedGetPostThreadV2.ThreadItem): Extract< + Slice, + {type: 'threadPostNoUnauthenticated'} +> { return { - type: 'threadSliceNoUnauthenticated', - key: item.uri, - slice: item, + type: 'threadPostNoUnauthenticated', + key: uri, + uri, + depth, + value: value as AppBskyUnspeccedGetPostThreadV2.ThreadItemNoUnauthenticated, } } -export function notFound({ - item, -}: { - item: AppBskyUnspeccedDefs.ThreadItemNotFound -}): Extract { +export function threadPostNotFound({ + uri, + depth, + value, +}: AppBskyUnspeccedGetPostThreadV2.ThreadItem): Extract< + Slice, + {type: 'threadPostNotFound'} +> { return { - type: 'threadSliceNotFound', - key: item.uri, - slice: item, + type: 'threadPostNotFound', + key: uri, + uri, + depth, + value: value as AppBskyUnspeccedGetPostThreadV2.ThreadItemNotFound, } } -export function blocked({ - item, -}: { - item: AppBskyUnspeccedDefs.ThreadItemBlocked -}): Extract { +export function threadPostBlocked({ + uri, + depth, + value, +}: AppBskyUnspeccedGetPostThreadV2.ThreadItem): Extract< + Slice, + {type: 'threadPostBlocked'} +> { return { - type: 'threadSliceBlocked', - key: item.uri, - slice: item, + type: 'threadPostBlocked', + key: uri, + uri, + depth, + value: value as AppBskyUnspeccedGetPostThreadV2.ThreadItemBlocked, } } -export function post({ - item, +export function threadPost({ + uri, + depth, + value, oneUp, oneDown, moderationOpts, }: { - item: AppBskyUnspeccedDefs.ThreadItemPost + uri: string + depth: number + value: $Typed oneUp?: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'][number] oneDown?: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'][number] moderationOpts: ModerationOpts -}): Extract { +}): Extract { return { - type: 'threadSlice', - key: item.uri, - slice: { - ...item, + type: 'threadPost', + key: uri, + uri, + depth, + value: { + ...value, post: { - ...item.post, - record: item.post.record as AppBskyFeedPost.Record, + ...value.post, + record: value.post.record as AppBskyFeedPost.Record, }, }, - moderation: moderatePost(item.post, moderationOpts), + moderation: moderatePost(value.post, moderationOpts), ui: { - isAnchor: item.depth === 0, - showParentReplyLine: - !!oneUp && 'depth' in oneUp && oneUp.depth < item.depth, - showChildReplyLine: - !!oneDown && 'depth' in oneDown && oneDown.depth > item.depth, + isAnchor: depth === 0, + showParentReplyLine: !!oneUp && oneUp.depth < depth, + showChildReplyLine: !!oneDown && oneDown.depth > depth, }, } } export function postViewToThreadPlaceholder( post: AppBskyFeedDefs.PostView, -): $Typed { +): $Typed< + Omit & { + value: $Typed + } +> { return { - $type: 'app.bsky.unspecced.defs#threadItemPost', + $type: 'app.bsky.unspecced.getPostThreadV2#threadItem', uri: post.uri, - post, depth: 0, // reset to 0 for highlighted post - isOPThread: false, // unknown - hasOPLike: false, // unknown - hasUnhydratedReplies: false, // unknown - // TODO test - hasUnhydratedParents: !!(post.record as AppBskyFeedPost.Record).reply, // unknown + value: { + $type: 'app.bsky.unspecced.getPostThreadV2#threadItemPost', + post, + isOPThread: false, // unknown + hasOPLike: false, // unknown + // @ts-expect-error + hasUnhydratedReplies: false, // unknown + // TODO test + hasUnhydratedParents: !!(post.record as AppBskyFeedPost.Record).reply, // unknown + }, } } export function embedViewToThreadPlaceholder( record: AppBskyEmbedRecord.ViewRecord, -): $Typed { +): $Typed< + Omit & { + value: $Typed + } +> { return { - $type: 'app.bsky.unspecced.defs#threadItemPost', + $type: 'app.bsky.unspecced.getPostThreadV2#threadItem', uri: record.uri, - post: embedViewRecordToPostView(record), depth: 0, // reset to 0 for highlighted post - isOPThread: false, // unknown - hasOPLike: false, // unknown - hasUnhydratedReplies: false, // unknown - // TODO test - hasUnhydratedParents: !!(record.value as AppBskyFeedPost.Record).reply, // unknown + value: { + $type: 'app.bsky.unspecced.getPostThreadV2#threadItemPost', + post: embedViewRecordToPostView(record), + isOPThread: false, // unknown + hasOPLike: false, // unknown + // @ts-expect-error + hasUnhydratedReplies: false, // unknown + // TODO test + hasUnhydratedParents: !!(record.value as AppBskyFeedPost.Record).reply, // unknown + }, } } diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 763f19681d..49c87dd4fd 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -44,11 +44,10 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context' import {type ImagePickerAsset} from 'expo-image-picker' import { AppBskyFeedDefs, - AppBskyUnspeccedDefs, type AppBskyFeedGetPostThread, + type AppBskyUnspeccedGetPostThreadV2, type BskyAgent, type RichText, -AppBskyFeedGetPostThreadV2, } from '@atproto/api' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg, plural, Trans} from '@lingui/macro' @@ -57,8 +56,8 @@ import {useQueryClient} from '@tanstack/react-query' import * as apilib from '#/lib/api/index' import {EmbeddingDisabledError} from '#/lib/api/resolve' -import {until} from '#/lib/async/until' import {retry} from '#/lib/async/retry' +import {until} from '#/lib/async/until' import { MAX_GRAPHEME_LENGTH, SUPPORTED_MIME_TYPES, @@ -392,7 +391,7 @@ export const ComposePost = ({ setIsPublishing(true) let postUri: string | undefined - let posts: AppBskyFeedGetPostThreadV2.OutputSchema['thread'] = [] + let posts: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'] = [] try { postUri = ( await apilib.post(agent, queryClient, { @@ -404,22 +403,27 @@ export const ComposePost = ({ ).uris[0] try { if (postUri) { - posts = await retry(5, _e => true, async () => { - const res = await agent.app.bsky.unspecced.getPostThreadV2({ - uri: postUri!, - above: 1, - below: thread.posts.length - 1, - branchingFactor: 1, - }) - const parent = res.data.thread.at(0) - if (!AppBskyUnspeccedDefs.isThreadItemPost(parent)) { - throw new Error(`Not ready`) - } - if (res.data.thread.length !== thread.posts.length + 1) { - throw new Error(`Not ready`) - } - return res.data.thread - }, 1e3) + posts = await retry( + 5, + _e => true, + async () => { + const res = await agent.app.bsky.unspecced.getPostThreadV2({ + uri: postUri!, + above: 1, + below: thread.posts.length - 1, + nestedBranchingFactor: 1, + }) + const parent = res.data.thread.at(0) + if (!parent) { + throw new Error(`Not ready`) + } + if (res.data.thread.length !== thread.posts.length + 1) { + throw new Error(`Not ready`) + } + return res.data.thread + }, + 1e3, + ) } await whenAppViewReady(agent, postUri, res => { diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx index 943ce5ae23..55d009f9d7 100644 --- a/src/view/screens/PostThread.tsx +++ b/src/view/screens/PostThread.tsx @@ -1,12 +1,15 @@ import {useCallback, useMemo, useRef, useState} from 'react' import {useWindowDimensions, View} from 'react-native' -import {type AppBskyUnspeccedDefs} from '@atproto/api' +import {type AppBskyUnspeccedGetPostThreadV2} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useFocusEffect} from '@react-navigation/native' import {HITSLOP_10} from '#/lib/constants' -import {type CommonNavigatorParams, type NativeStackScreenProps} from '#/lib/routes/types' +import { + type CommonNavigatorParams, + type NativeStackScreenProps, +} from '#/lib/routes/types' import {cleanError} from '#/lib/strings/errors' import {makeRecordUri} from '#/lib/strings/url-helpers' import {isNative} from '#/platform/detection' @@ -157,31 +160,31 @@ export function Inner({uri}: {uri: string | undefined}) { const layoutHeaderRef = useRef(null) const anchorPostRef = useRef(null) - const optimisticOnPostReply = - ({post}: {post: AppBskyUnspeccedDefs.ThreadItemPost}) => - (_: any, posts: AppBskyUnspeccedDefs.ThreadItemPost[]) => { - if (posts.length) { - console.log('insert', posts) - const parent = posts.at(0) - const replies = posts.slice(1) - if (parent && replies.length) { - insertReplies(parent, replies) - } + const optimisticOnPostReply = ( + _: any, + posts: AppBskyUnspeccedGetPostThreadV2.ThreadItem[], + ) => { + if (posts.length) { + const parent = posts.at(0) + const replies = posts.slice(1) + if (parent && replies.length) { + insertReplies(parent, replies) } } + } const {openComposer} = useOpenComposer() const onReplyToAnchor = () => { - const anchorPost = data?.slices.find( - slice => slice.type === 'threadSlice' && slice.ui.isAnchor, + const anchorPost = data?.items.find( + slice => slice.type === 'threadPost' && slice.ui.isAnchor, ) - if (anchorPost?.type !== 'threadSlice') { + if (anchorPost?.type !== 'threadPost') { return } - const post = anchorPost.slice.post + const post = anchorPost.value.post openComposer({ replyTo: { - uri: anchorPost.slice.uri, + uri: anchorPost.uri, cid: post.cid, text: post.record.text, author: post.author, @@ -189,42 +192,43 @@ export function Inner({uri}: {uri: string | undefined}) { moderation: anchorPost.moderation, }, // @ts-expect-error TODO - onPost: optimisticOnPostReply({post: anchorPost.slice}), + onPost: optimisticOnPostReply, }) } const renderItem = ({item, index}: {item: Slice; index: number}) => { - if (item.type === 'threadSlice') { + if (item.type === 'threadPost') { return ( 0 + shownHiddenReplyKinds.has(HiddenReplyKind.Muted) && item.depth > 0 } // @ts-expect-error TODO - onPostReply={optimisticOnPostReply({post: item.slice})} - hideTopBorder={index === 0} // && !item.slice.isParentLoading} // TODO + onPostReply={optimisticOnPostReply} + hideTopBorder={index === 0} // && !item.isParentLoading} // TODO /> ) - } else if (item.type === 'threadSliceBlocked') { + } else if (item.type === 'threadPostBlocked') { return ( ) - } else if (item.type === 'threadSliceNotFound') { + } else if (item.type === 'threadPostNotFound') { return (