diff --git a/src/lib/async/retry.ts b/src/lib/async/retry.ts index abf78de55f..3f749fc083 100644 --- a/src/lib/async/retry.ts +++ b/src/lib/async/retry.ts @@ -1,9 +1,11 @@ +import {timeout} from '#/lib/async/timeout' import {isNetworkError} from '#/lib/strings/errors' export async function retry
( retries: number, cond: (err: any) => boolean, fn: () => Promise
, + delay?: number, ): Promise
{ let lastErr while (retries > 0) { @@ -11,7 +13,11 @@ export async function retry
( return await fn() } catch (e: any) { lastErr = e + // should retry? if (cond(e)) { + if (delay) { + await timeout(delay) + } retries-- continue } diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 42f057803f..de8b5afbfc 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -47,6 +47,7 @@ import { type AppBskyFeedGetPostThread, type BskyAgent, type RichText, +AppBskyFeedGetPostThreadV2, } from '@atproto/api' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg, plural, Trans} from '@lingui/macro' @@ -56,6 +57,7 @@ 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 { MAX_GRAPHEME_LENGTH, SUPPORTED_MIME_TYPES, @@ -388,7 +390,8 @@ export const ComposePost = ({ setError('') setIsPublishing(true) - let postUri + let postUri: string | undefined + let posts: AppBskyFeedGetPostThreadV2.OutputSchema['thread'] = [] try { postUri = ( await apilib.post(agent, queryClient, { @@ -399,6 +402,20 @@ export const ComposePost = ({ }) ).uris[0] try { + if (postUri) { + posts = await retry(5, _e => true, async () => { + const res = await agent.app.bsky.feed.getPostThreadV2({ + uri: postUri!, + above: 0, + below: thread.posts.length - 1, + }) + if (res.data.thread.length !== thread.posts.length) { + throw new Error(`Not ready`) + } + return res.data.thread + }, 1e3) + } + await whenAppViewReady(agent, postUri, res => { const postedThread = res?.data?.thread return AppBskyFeedDefs.isThreadViewPost(postedThread) @@ -470,7 +487,7 @@ export const ComposePost = ({ return false }) } else { - onPost?.(postUri) + onPost?.(postUri, posts) } onClose() Toast.show( diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx index f6e2545dcf..eaf64206b0 100644 --- a/src/view/screens/PostThread.tsx +++ b/src/view/screens/PostThread.tsx @@ -165,6 +165,20 @@ export function Inner({uri}: {uri: string | undefined}) { [refetch], ) + const optimisticOnPostReply = ({ + post, + }: { + post: AppBskyFeedDefs.ThreadItemPost, + }) => (_: any, posts: AppBskyFeedDefs.ThreadItemPost[]) => { + const parentDepth = post.depth + if (posts.length) { + for (let i = 0; i < posts.length; i++) { + const p = posts[i] + p.depth = parentDepth + 1 + i + } + } + } + const {openComposer} = useOpenComposer() const onReplyToAnchor = () => { const anchorPost = data?.slices.find(slice => slice.type === 'threadSlice' && slice.ui.isAnchor) @@ -181,7 +195,7 @@ export function Inner({uri}: {uri: string | undefined}) { embed: post.embed, moderation: anchorPost.moderation, }, - onPost: onPostReply, + onPost: optimisticOnPostReply({post:anchorPost.slice}), }) } @@ -209,7 +223,7 @@ export function Inner({uri}: {uri: string | undefined}) { overrideBlur={ shownHiddenReplyKinds.has(HiddenReplyKind.Muted) && item.slice.depth > 0 } - onPostReply={onPostReply} + onPostReply={optimisticOnPostReply({post:item.slice})} hideTopBorder={index === 0} // && !item.slice.isParentLoading} // TODO />