From 3a19d5c69df5015d0db6bc84a3e7ee6d201b498f Mon Sep 17 00:00:00 2001 From: scanash00 Date: Sat, 29 Nov 2025 23:10:01 -0900 Subject: [PATCH] implement redrafting --- .../PostControls/PostMenu/PostMenuItems.tsx | 111 ++++++++++++++++++ src/view/com/composer/Composer.tsx | 4 +- 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/src/components/PostControls/PostMenu/PostMenuItems.tsx b/src/components/PostControls/PostMenu/PostMenuItems.tsx index eb8bc8b09..ee40c0aa9 100644 --- a/src/components/PostControls/PostMenu/PostMenuItems.tsx +++ b/src/components/PostControls/PostMenu/PostMenuItems.tsx @@ -8,6 +8,7 @@ import { import * as Clipboard from 'expo-clipboard' import { type AppBskyEmbedExternal, + type AppBskyEmbedImages, type AppBskyEmbedRecordWithMedia, type AppBskyEmbedVideo, type AppBskyFeedDefs, @@ -15,6 +16,7 @@ import { type AppBskyFeedThreadgate, AtUri, type RichText as RichTextAPI, + AppBskyEmbedRecord, } from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -79,6 +81,7 @@ import { import {Eye_Stroke2_Corner0_Rounded as Eye} from '#/components/icons/Eye' import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter' +import {Pencil_Stroke2_Corner0_Rounded as Pen} from '#/components/icons/Pencil' import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' import {PersonX_Stroke2_Corner0_Rounded as PersonX} from '#/components/icons/Person' @@ -96,6 +99,7 @@ import { } from '#/components/moderation/ReportDialog' import * as Prompt from '#/components/Prompt' import {IS_INTERNAL} from '#/env' +import {useOpenComposer} from '#/lib/hooks/useOpenComposer' import * as bsky from '#/types/bsky' let PostMenuItems = ({ @@ -141,6 +145,7 @@ let PostMenuItems = ({ const postInteractionSettingsDialogControl = useDialogControl() const quotePostDetachConfirmControl = useDialogControl() const hideReplyConfirmControl = useDialogControl() + const redraftPromptControl = useDialogControl() const {mutateAsync: toggleReplyVisibility} = useToggleReplyVisibilityMutation() @@ -214,6 +219,95 @@ let PostMenuItems = ({ ) } + const {openComposer} = useOpenComposer() + const onRedraftPost = () => { + redraftPromptControl.open() + } + + const onConfirmRedraft = () => { + let imageUris: { + uri: string + width: number + height: number + altText?: string + }[] = [] + + if (post.embed?.$type === 'app.bsky.embed.images#view') { + const embed = post.embed as AppBskyEmbedImages.View + imageUris = embed.images.map(img => ({ + uri: img.fullsize, + width: img.aspectRatio?.width ?? 1000, + height: img.aspectRatio?.height ?? 1000, + altText: img.alt, + })) + } else if (post.embed?.$type === 'app.bsky.embed.recordWithMedia#view') { + const embed = post.embed as AppBskyEmbedRecordWithMedia.View + if (embed.media.$type === 'app.bsky.embed.images#view') { + const images = embed.media as AppBskyEmbedImages.View + imageUris = images.images.map(img => ({ + uri: img.fullsize, + width: img.aspectRatio?.width ?? 1000, + height: img.aspectRatio?.height ?? 1000, + altText: img.alt, + })) + } + } + + let quotePost: AppBskyFeedDefs.PostView | undefined + + if (post.embed?.$type === 'app.bsky.embed.record#view') { + const embed = post.embed as AppBskyEmbedRecord.View + if ( + AppBskyEmbedRecord.isViewRecord(embed.record) && + AppBskyFeedPost.isRecord(embed.record.value) + ) { + quotePost = { + uri: embed.record.uri, + cid: embed.record.cid, + author: embed.record.author, + record: embed.record.value, + indexedAt: embed.record.indexedAt, + } as AppBskyFeedDefs.PostView + } + } else if (post.embed?.$type === 'app.bsky.embed.recordWithMedia#view') { + const embed = post.embed as AppBskyEmbedRecordWithMedia.View + if ( + AppBskyEmbedRecord.isViewRecord(embed.record.record) && + AppBskyFeedPost.isRecord(embed.record.record.value) + ) { + const record = embed.record.record + quotePost = { + uri: record.uri, + cid: record.cid, + author: record.author, + record: record.value, + indexedAt: record.indexedAt, + } as AppBskyFeedDefs.PostView + } + } + + let replyTo: any + if (record.reply) { + const parent = record.reply.parent || record.reply.root + if (parent) { + replyTo = { + uri: parent.uri, + cid: parent.cid, + } + } + } + + openComposer({ + text: record.text, + imageUris, + onPost: () => { + onDeletePost() + }, + quote: quotePost, + replyTo, + }) + } + const onToggleThreadMute = () => { try { if (isThreadMuted) { @@ -508,6 +602,16 @@ let PostMenuItems = ({ return ( <> + {isAuthor && ( <> @@ -531,6 +635,13 @@ let PostMenuItems = ({ position="right" /> + + {_(msg`Redraft`)} + + diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 0d1a51043..69f5d935c 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -770,7 +770,9 @@ export const ComposePost = ({ keyboardShouldPersistTaps="always" onContentSizeChange={onScrollViewContentSizeChange} onLayout={onScrollViewLayout}> - {replyTo ? : undefined} + {replyTo && replyTo.text && replyTo.author ? ( + + ) : undefined} {thread.posts.map((post, index) => (