Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client
122
fork

Configure Feed

Select the types of activity you want to include in your feed.

implement redrafting

authored by

scanash00 and committed by
Tangled
dc02ee76 cfc7acce

+114 -1
+111
src/components/PostControls/PostMenu/PostMenuItems.tsx
··· 8 8 import * as Clipboard from 'expo-clipboard' 9 9 import { 10 10 type AppBskyEmbedExternal, 11 + type AppBskyEmbedImages, 11 12 type AppBskyEmbedRecordWithMedia, 12 13 type AppBskyEmbedVideo, 13 14 type AppBskyFeedDefs, ··· 15 16 type AppBskyFeedThreadgate, 16 17 AtUri, 17 18 type RichText as RichTextAPI, 19 + AppBskyEmbedRecord, 18 20 } from '@atproto/api' 19 21 import {msg} from '@lingui/macro' 20 22 import {useLingui} from '@lingui/react' ··· 79 81 import {Eye_Stroke2_Corner0_Rounded as Eye} from '#/components/icons/Eye' 80 82 import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' 81 83 import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter' 84 + import {Pencil_Stroke2_Corner0_Rounded as Pen} from '#/components/icons/Pencil' 82 85 import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' 83 86 import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' 84 87 import {PersonX_Stroke2_Corner0_Rounded as PersonX} from '#/components/icons/Person' ··· 96 99 } from '#/components/moderation/ReportDialog' 97 100 import * as Prompt from '#/components/Prompt' 98 101 import {IS_INTERNAL} from '#/env' 102 + import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 99 103 import * as bsky from '#/types/bsky' 100 104 101 105 let PostMenuItems = ({ ··· 141 145 const postInteractionSettingsDialogControl = useDialogControl() 142 146 const quotePostDetachConfirmControl = useDialogControl() 143 147 const hideReplyConfirmControl = useDialogControl() 148 + const redraftPromptControl = useDialogControl() 144 149 const {mutateAsync: toggleReplyVisibility} = 145 150 useToggleReplyVisibilityMutation() 146 151 ··· 214 219 ) 215 220 } 216 221 222 + const {openComposer} = useOpenComposer() 223 + const onRedraftPost = () => { 224 + redraftPromptControl.open() 225 + } 226 + 227 + const onConfirmRedraft = () => { 228 + let imageUris: { 229 + uri: string 230 + width: number 231 + height: number 232 + altText?: string 233 + }[] = [] 234 + 235 + if (post.embed?.$type === 'app.bsky.embed.images#view') { 236 + const embed = post.embed as AppBskyEmbedImages.View 237 + imageUris = embed.images.map(img => ({ 238 + uri: img.fullsize, 239 + width: img.aspectRatio?.width ?? 1000, 240 + height: img.aspectRatio?.height ?? 1000, 241 + altText: img.alt, 242 + })) 243 + } else if (post.embed?.$type === 'app.bsky.embed.recordWithMedia#view') { 244 + const embed = post.embed as AppBskyEmbedRecordWithMedia.View 245 + if (embed.media.$type === 'app.bsky.embed.images#view') { 246 + const images = embed.media as AppBskyEmbedImages.View 247 + imageUris = images.images.map(img => ({ 248 + uri: img.fullsize, 249 + width: img.aspectRatio?.width ?? 1000, 250 + height: img.aspectRatio?.height ?? 1000, 251 + altText: img.alt, 252 + })) 253 + } 254 + } 255 + 256 + let quotePost: AppBskyFeedDefs.PostView | undefined 257 + 258 + if (post.embed?.$type === 'app.bsky.embed.record#view') { 259 + const embed = post.embed as AppBskyEmbedRecord.View 260 + if ( 261 + AppBskyEmbedRecord.isViewRecord(embed.record) && 262 + AppBskyFeedPost.isRecord(embed.record.value) 263 + ) { 264 + quotePost = { 265 + uri: embed.record.uri, 266 + cid: embed.record.cid, 267 + author: embed.record.author, 268 + record: embed.record.value, 269 + indexedAt: embed.record.indexedAt, 270 + } as AppBskyFeedDefs.PostView 271 + } 272 + } else if (post.embed?.$type === 'app.bsky.embed.recordWithMedia#view') { 273 + const embed = post.embed as AppBskyEmbedRecordWithMedia.View 274 + if ( 275 + AppBskyEmbedRecord.isViewRecord(embed.record.record) && 276 + AppBskyFeedPost.isRecord(embed.record.record.value) 277 + ) { 278 + const record = embed.record.record 279 + quotePost = { 280 + uri: record.uri, 281 + cid: record.cid, 282 + author: record.author, 283 + record: record.value, 284 + indexedAt: record.indexedAt, 285 + } as AppBskyFeedDefs.PostView 286 + } 287 + } 288 + 289 + let replyTo: any 290 + if (record.reply) { 291 + const parent = record.reply.parent || record.reply.root 292 + if (parent) { 293 + replyTo = { 294 + uri: parent.uri, 295 + cid: parent.cid, 296 + } 297 + } 298 + } 299 + 300 + openComposer({ 301 + text: record.text, 302 + imageUris, 303 + onPost: () => { 304 + onDeletePost() 305 + }, 306 + quote: quotePost, 307 + replyTo, 308 + }) 309 + } 310 + 217 311 const onToggleThreadMute = () => { 218 312 try { 219 313 if (isThreadMuted) { ··· 508 602 509 603 return ( 510 604 <> 605 + <Prompt.Basic 606 + control={redraftPromptControl} 607 + title={_(msg`Redraft this post?`)} 608 + description={_( 609 + msg`This will delete the original post and open the composer with its content.`, 610 + )} 611 + onConfirm={onConfirmRedraft} 612 + confirmButtonCta={_(msg`Redraft`)} 613 + confirmButtonColor="primary" 614 + /> 511 615 <Menu.Outer> 512 616 {isAuthor && ( 513 617 <> ··· 530 634 icon={isPinPending ? Loader : PinIcon} 531 635 position="right" 532 636 /> 637 + </Menu.Item> 638 + <Menu.Item 639 + testID="redraftPostBtn" 640 + label={_(msg`Redraft`)} 641 + onPress={onRedraftPost}> 642 + <Menu.ItemText>{_(msg`Redraft`)}</Menu.ItemText> 643 + <Menu.ItemIcon icon={Pen} position="right" /> 533 644 </Menu.Item> 534 645 </Menu.Group> 535 646 <Menu.Divider />
+3 -1
src/view/com/composer/Composer.tsx
··· 770 770 keyboardShouldPersistTaps="always" 771 771 onContentSizeChange={onScrollViewContentSizeChange} 772 772 onLayout={onScrollViewLayout}> 773 - {replyTo ? <ComposerReplyTo replyTo={replyTo} /> : undefined} 773 + {replyTo && replyTo.text && replyTo.author ? ( 774 + <ComposerReplyTo replyTo={replyTo} /> 775 + ) : undefined} 774 776 {thread.posts.map((post, index) => ( 775 777 <React.Fragment key={post.id}> 776 778 <ComposerPost