From 056d5789656277c03cce1822c868ded92c645a86 Mon Sep 17 00:00:00 2001 From: Hampus Date: Tue, 6 Jan 2026 19:33:11 +0100 Subject: [PATCH] fix(embed): hide remove buttons when unapplicable (#66) --- .../components/channel/MessageAttachments.tsx | 55 +- .../src/components/channel/embeds/Embed.tsx | 32 +- .../channel/embeds/attachments/Attachment.tsx | 108 +-- .../embeds/attachments/AttachmentFile.tsx | 11 +- .../embeds/attachments/AttachmentMosaic.tsx | 795 +++++++++--------- .../channel/embeds/media/EmbedAudio.tsx | 19 +- .../channel/embeds/media/EmbedGifv.tsx | 20 +- .../channel/embeds/media/EmbedImage.tsx | 9 +- .../channel/embeds/media/EmbedVideo.tsx | 9 +- .../channel/embeds/media/MediaButtonUtils.tsx | 9 +- 10 files changed, 579 insertions(+), 488 deletions(-) diff --git a/fluxer_app/src/components/channel/MessageAttachments.tsx b/fluxer_app/src/components/channel/MessageAttachments.tsx index 55e15919..f4304078 100644 --- a/fluxer_app/src/components/channel/MessageAttachments.tsx +++ b/fluxer_app/src/components/channel/MessageAttachments.tsx @@ -145,6 +145,7 @@ const ForwardedFromSource = observer(({message}: {message: MessageRecord}) => { }); const ForwardedMessageContent = observer(({message, snapshot}: {message: MessageRecord; snapshot: MessageSnapshot}) => { + const snapshotIsPreview = true; return (
@@ -177,12 +178,14 @@ const ForwardedMessageContent = observer(({message, snapshot}: {message: Message ); return ( <> - {shouldUseMosaic && } + {shouldUseMosaic && ( + + )} {enrichedAttachments.map((attachment: MessageAttachment) => ( @@ -193,23 +196,24 @@ const ForwardedMessageContent = observer(({message, snapshot}: {message: Message
)} - {snapshot.embeds && snapshot.embeds.length > 0 && UserSettingsStore.getRenderEmbeds() && ( -
- {snapshot.embeds.map((embed: MessageEmbed, index: number) => { - const embedKey = `${embed.id}-${index}`; - return ( - {}} - /> - ); - })} -
- )} + {snapshot.embeds && snapshot.embeds.length > 0 && UserSettingsStore.getRenderEmbeds() && ( +
+ {snapshot.embeds.map((embed: MessageEmbed, index: number) => { + const embedKey = `${embed.id}-${index}`; + return ( + {}} + isPreview={snapshotIsPreview} + /> + ); + })} +
+ )}
@@ -315,7 +319,9 @@ export const MessageAttachments = observer(() => { const shouldWrapInMosaic = inlineMedia && mediaAttachments.length > 0; return ( <> - {shouldWrapInMosaic && } + {shouldWrapInMosaic && ( + + )} {enrichedAttachments.map((attachment) => ( { message.embeds.map((embed, index) => { const embedKey = `${embed.id}-${index}`; return ( - + ); })} diff --git a/fluxer_app/src/components/channel/embeds/Embed.tsx b/fluxer_app/src/components/channel/embeds/Embed.tsx index 21f851a8..4f70cb38 100644 --- a/fluxer_app/src/components/channel/embeds/Embed.tsx +++ b/fluxer_app/src/components/channel/embeds/Embed.tsx @@ -74,6 +74,7 @@ interface EmbedProps { embedIndex?: number; onDelete?: (bypassConfirm?: boolean) => void; contextualEmbeds?: ReadonlyArray; + isPreview?: boolean; } interface LinkComponentProps { @@ -432,7 +433,8 @@ const EmbedMediaRenderer: FC<{ message: MessageRecord; embedIndex?: number; onDelete?: (bypassConfirm?: boolean) => void; -}> = observer(({embed, message, embedIndex, onDelete}) => { + isPreview?: boolean; +}> = observer(({embed, message, embedIndex, onDelete, isPreview}) => { const {video, image, thumbnail} = embed; if (!isValidMedia(video) && !isValidMedia(image) && !isValidMedia(thumbnail)) { @@ -466,6 +468,7 @@ const EmbedMediaRenderer: FC<{ contentHash={video.content_hash} embedIndex={embedIndex} onDelete={onDelete} + isPreview={isPreview} /> ); @@ -491,6 +494,7 @@ const EmbedMediaRenderer: FC<{ contentHash={image.content_hash} embedIndex={embedIndex} onDelete={onDelete} + isPreview={isPreview} /> ); @@ -514,6 +518,7 @@ const EmbedMediaRenderer: FC<{ contentHash={image.content_hash} embedIndex={embedIndex} onDelete={onDelete} + isPreview={isPreview} /> ); @@ -570,7 +575,7 @@ const EmbedMediaRenderer: FC<{ return null; }); -const RichEmbed: FC = observer(({embed, message, embedIndex, contextualEmbeds, onDelete}) => { +const RichEmbed: FC = observer(({embed, message, embedIndex, contextualEmbeds, onDelete, isPreview}) => { const embedList = contextualEmbeds ?? message.embeds; const hasVideo = isValidMedia(embed.video); const hasImage = isValidMedia(embed.image); @@ -640,9 +645,20 @@ const RichEmbed: FC = observer(({embed, message, embedIndex, context {!shouldRenderInlineThumbnail && hasAnyMedia && (
{showGallery && galleryAttachments ? ( - + ) : ( - + )}
)} @@ -683,6 +699,7 @@ const RichEmbed: FC = observer(({embed, message, embedIndex, context contentHash={embed.thumbnail.content_hash} embedIndex={embedIndex} onDelete={onDelete} + isPreview={isPreview} /> @@ -693,7 +710,7 @@ const RichEmbed: FC = observer(({embed, message, embedIndex, context ); }); -export const Embed: FC = observer(({embed, message, embedIndex, contextualEmbeds, onDelete}) => { +export const Embed: FC = observer(({embed, message, embedIndex, contextualEmbeds, onDelete, isPreview}) => { const {t} = useLingui(); const {enabled: isMobile} = MobileLayoutStore; const channel = ChannelStore.getChannel(message.channelId); @@ -725,7 +742,8 @@ export const Embed: FC = observer(({embed, message, embedIndex, cont ModalActionCreators.push(modal(() => )); }, [message]); - const showSuppressButton = !isMobile && canSuppressEmbeds() && AccessibilityStore.showSuppressEmbedsButton; + const showSuppressButton = + !isMobile && canSuppressEmbeds() && AccessibilityStore.showSuppressEmbedsButton && !isPreview; const spoileredUrls = useMemo(() => extractSpoileredUrls(message.content), [message.content]); const {isSpoilerEmbed, matchingSpoilerUrls} = useMemo(() => { @@ -820,6 +838,7 @@ export const Embed: FC = observer(({embed, message, embedIndex, cont contentHash={embed.audio.content_hash} embedIndex={embedIndex} onDelete={onDelete} + isPreview={isPreview} /> @@ -1072,6 +1091,7 @@ export const Embed: FC = observer(({embed, message, embedIndex, cont embedIndex={embedIndex} contextualEmbeds={contextualEmbeds} onDelete={onDelete} + isPreview={isPreview} /> , ); diff --git a/fluxer_app/src/components/channel/embeds/attachments/Attachment.tsx b/fluxer_app/src/components/channel/embeds/attachments/Attachment.tsx index 785a56bd..aa09b47e 100644 --- a/fluxer_app/src/components/channel/embeds/attachments/Attachment.tsx +++ b/fluxer_app/src/components/channel/embeds/attachments/Attachment.tsx @@ -67,35 +67,38 @@ const isUploading = (flags: number): boolean => (flags & 0x1000) !== 0; const hasValidDimensions = (attachment: MessageAttachment): boolean => typeof attachment.width === 'number' && typeof attachment.height === 'number'; -const AnimatedAttachment: FC = observer(({attachment, message}) => { - const embedUrl = attachment.url ?? ''; - const proxyUrl = attachment.proxy_url ?? embedUrl; - const animatedProxyURL = buildMediaProxyURL(proxyUrl, { - animated: true, - }); - const nsfw = attachment.nsfw || (attachment.flags & MessageAttachmentFlags.CONTAINS_EXPLICIT_MEDIA) !== 0; +const AnimatedAttachment: FC = observer( + ({attachment, message, isPreview}) => { + const embedUrl = attachment.url ?? ''; + const proxyUrl = attachment.proxy_url ?? embedUrl; + const animatedProxyURL = buildMediaProxyURL(proxyUrl, { + animated: true, + }); + const nsfw = attachment.nsfw || (attachment.flags & MessageAttachmentFlags.CONTAINS_EXPLICIT_MEDIA) !== 0; - return ( - - - - ); -}); + return ( + + + + ); + }, +); -const VideoAttachment: FC = observer( - ({attachment, message, mediaAttachments = []}) => { +const VideoAttachment: FC = observer( + ({attachment, message, mediaAttachments = [], isPreview}) => { const embedUrl = attachment.url ?? ''; const proxyUrl = attachment.proxy_url ?? embedUrl; const nsfw = attachment.nsfw || (attachment.flags & MessageAttachmentFlags.CONTAINS_EXPLICIT_MEDIA) !== 0; @@ -132,6 +135,7 @@ const VideoAttachment: FC = ob message={message} contentHash={attachment.content_hash} mediaAttachments={mediaAttachments} + isPreview={isPreview} /> @@ -139,29 +143,32 @@ const VideoAttachment: FC = ob }, ); -const AudioAttachment: FC = observer(({attachment, message}) => ( - -
- -
-
-)); +const AudioAttachment: FC = observer( + ({attachment, message, isPreview}) => ( + +
+ +
+
+ ), +); -const AttachmentMedia: FC = observer( - ({attachment, message, mediaAttachments = []}) => { +const AttachmentMedia: FC = observer( + ({attachment, message, mediaAttachments = [], isPreview}) => { const nsfw = attachment.nsfw || (attachment.flags & MessageAttachmentFlags.CONTAINS_EXPLICIT_MEDIA) !== 0; if (isAnimated(attachment.flags) || isGifType(attachment.content_type)) { - return ; + return ; } const attachmentDimensions = getAttachmentMediaDimensions(message); @@ -208,6 +215,7 @@ const AttachmentMedia: FC = ob message={message} contentHash={attachment.content_hash} mediaAttachments={mediaAttachments} + isPreview={isPreview} /> @@ -283,7 +291,7 @@ export const Attachment: FC = observer(({attachment, isPreview, wrapSpoiler(
{effectiveExpired &&
{t`This attachment has expired`}
} - +
, ), ); @@ -304,7 +312,7 @@ export const Attachment: FC = observer(({attachment, isPreview, wrapSpoiler(
{effectiveExpired &&
{t`This attachment has expired`}
} - +
, ), ); @@ -315,7 +323,7 @@ export const Attachment: FC = observer(({attachment, isPreview, wrapSpoiler(
{effectiveExpired &&
{t`This attachment has expired`}
} - +
, ), ); diff --git a/fluxer_app/src/components/channel/embeds/attachments/AttachmentFile.tsx b/fluxer_app/src/components/channel/embeds/attachments/AttachmentFile.tsx index 704416ba..57a52009 100644 --- a/fluxer_app/src/components/channel/embeds/attachments/AttachmentFile.tsx +++ b/fluxer_app/src/components/channel/embeds/attachments/AttachmentFile.tsx @@ -37,6 +37,7 @@ import {clsx} from 'clsx'; import {observer} from 'mobx-react-lite'; import * as ContextMenuActionCreators from '~/actions/ContextMenuActionCreators'; import {splitFilename} from '~/components/channel/embeds/EmbedUtils'; +import {useMaybeMessageViewContext} from '~/components/channel/MessageViewContext'; import {canDeleteAttachmentUtil} from '~/components/channel/messageActionUtils'; import {MediaContextMenu} from '~/components/uikit/ContextMenu/MediaContextMenu'; import {Tooltip} from '~/components/uikit/Tooltip/Tooltip'; @@ -54,7 +55,7 @@ interface AttachmentFileProps { message?: MessageRecord; } -export const AttachmentFile = observer(({attachment, message}: AttachmentFileProps) => { +export const AttachmentFile = observer(({attachment, message, isPreview}: AttachmentFileProps) => { const {t} = useLingui(); const {enabled: isMobile} = MobileLayoutStore; const isExpired = Boolean(attachment.expired); @@ -131,9 +132,11 @@ export const AttachmentFile = observer(({attachment, message}: AttachmentFilePro const handleDelete = useDeleteAttachment(message, attachment.id); const canDelete = canDeleteAttachmentUtil(message) && !isMobile; + const showDeleteButton = canDelete && !isPreview; + const messageViewContext = useMaybeMessageViewContext(); const handleContextMenu = (e: React.MouseEvent) => { - if (!message) return; + if (!message || isPreview) return; e.preventDefault(); e.stopPropagation(); @@ -148,7 +151,7 @@ export const AttachmentFile = observer(({attachment, message}: AttachmentFilePro defaultName={attachment.filename} defaultAltText={attachment.filename} onClose={onClose} - onDelete={() => {}} + onDelete={isPreview ? () => {} : (messageViewContext?.handleDelete ?? (() => {}))} /> )); }; @@ -156,7 +159,7 @@ export const AttachmentFile = observer(({attachment, message}: AttachmentFilePro return ( // biome-ignore lint/a11y/noStaticElementInteractions: context menu on container is intentional
- {canDelete && ( + {showDeleteButton && (
- )} - - , - ); -}); + )} -const SingleAttachment: FC = observer(({attachment, message, mediaAttachments}) => { + {(isVideo || isAudio) && ( +
+
+
+
+ )} + + , + ); + }, +); + +const SingleAttachment: FC = observer(({attachment, message, mediaAttachments, isPreview}) => { const isVideo = isVideoType(attachment.content_type); const isAnimatedGif = isAnimated(attachment.flags) || isGifType(attachment.content_type); const isSpoiler = (attachment.flags & MessageAttachmentFlags.IS_SPOILER) !== 0; @@ -452,6 +462,7 @@ const SingleAttachment: FC = observer(({attachment, messa height={dimensions.height} title={attachment.title || attachment.filename} mediaAttachments={mediaAttachments} + isPreview={isPreview} /> @@ -474,6 +485,7 @@ const SingleAttachment: FC = observer(({attachment, messa proxyURL={animatedProxyURL} naturalWidth={attachment.width!} naturalHeight={attachment.height!} + isPreview={isPreview} /> @@ -501,184 +513,193 @@ const SingleAttachment: FC = observer(({attachment, messa height={dimensions.height} constrain={true} mediaAttachments={mediaAttachments} + isPreview={isPreview} />, ); }); -const AttachmentMosaicComponent: FC = observer(({attachments, message, hideExpiryFootnote}) => { - const {t} = useLingui(); +const AttachmentMosaicComponent: FC = observer( + ({attachments, message, hideExpiryFootnote, isPreview}) => { + const {t} = useLingui(); - const mediaAttachments = attachments.filter(isMediaAttachment); - const count = mediaAttachments.length; - const aggregateExpiry = getEarliestAttachmentExpiry(attachments); + const mediaAttachments = attachments.filter(isMediaAttachment); + const count = mediaAttachments.length; + const aggregateExpiry = getEarliestAttachmentExpiry(attachments); - const renderFootnote = () => { - if (hideExpiryFootnote) { + const renderFootnote = () => { + if (hideExpiryFootnote) { + return null; + } + + const earliest = formatAttachmentDate(aggregateExpiry.expiresAt); + const latest = formatAttachmentDate(aggregateExpiry.latestAt); + + let label: string; + if (earliest && latest && earliest !== latest) { + label = aggregateExpiry.isExpired + ? t`Expired between ${earliest} and ${latest}` + : t`Expires between ${earliest} and ${latest}`; + } else if (earliest) { + label = aggregateExpiry.isExpired ? t`Expired on ${earliest}` : t`Expires on ${earliest}`; + } else { + return null; + } + + return AccessibilityStore.showAttachmentExpiryIndicator ? ( + + ) : null; + }; + + if (count === 0) { return null; } - const earliest = formatAttachmentDate(aggregateExpiry.expiresAt); - const latest = formatAttachmentDate(aggregateExpiry.latestAt); + const renderMosaicItem = (attachment: MessageAttachment, key?: string) => ( + + ); - let label: string; - if (earliest && latest && earliest !== latest) { - label = aggregateExpiry.isExpired - ? t`Expired between ${earliest} and ${latest}` - : t`Expires between ${earliest} and ${latest}`; - } else if (earliest) { - label = aggregateExpiry.isExpired ? t`Expired on ${earliest}` : t`Expires on ${earliest}`; - } else { - return null; - } - - return AccessibilityStore.showAttachmentExpiryIndicator ? ( - - ) : null; - }; - - if (count === 0) { - return null; - } - - const renderMosaicItem = (attachment: MessageAttachment, key?: string) => ( - - ); - - const renderGrid = (items: ReadonlyArray, gridClassName: string) => ( -
-
-
{items.map((attachment) => renderMosaicItem(attachment))}
+ const renderGrid = (items: ReadonlyArray, gridClassName: string) => ( +
+
+
{items.map((attachment) => renderMosaicItem(attachment))}
+
+ {renderFootnote()}
- {renderFootnote()} -
- ); + ); - switch (count) { - case 1: - return ( -
-
- -
- {renderFootnote()} -
- ); - - case 2: - return ( -
-
-
- {mediaAttachments.map((attachment) => ( -
- {renderMosaicItem(attachment)} -
- ))} + switch (count) { + case 1: + return ( +
+
+
+ {renderFootnote()}
- {renderFootnote()} -
- ); + ); - case 3: - return ( -
-
-
-
{renderMosaicItem(mediaAttachments[0])}
-
-
-
{renderMosaicItem(mediaAttachments[1])}
-
{renderMosaicItem(mediaAttachments[2])}
+ case 2: + return ( +
+
+
+ {mediaAttachments.map((attachment) => ( +
+ {renderMosaicItem(attachment)} +
+ ))} +
+
+ {renderFootnote()} +
+ ); + + case 3: + return ( +
+
+
+
{renderMosaicItem(mediaAttachments[0])}
+
+
+
{renderMosaicItem(mediaAttachments[1])}
+
{renderMosaicItem(mediaAttachments[2])}
+
+ {renderFootnote()}
- {renderFootnote()} -
- ); + ); - case 4: - return renderGrid(mediaAttachments, styles.twoByTwoGrid); + case 4: + return renderGrid(mediaAttachments, styles.twoByTwoGrid); - case 5: - return ( -
-
-
+ case 5: + return ( +
+
+
+
+
{renderMosaicItem(mediaAttachments[0])}
+
{renderMosaicItem(mediaAttachments[1])}
+
+
+ {mediaAttachments.slice(2, 5).map((attachment) => renderMosaicItem(attachment))} +
+
+
+ {renderFootnote()} +
+ ); + + case 6: + return renderGrid(mediaAttachments, styles.threeByThreeGrid); + + case 7: + return ( +
+
+
+ {renderMosaicItem(mediaAttachments[0])} +
+
+ {mediaAttachments.slice(1, 7).map((attachment) => renderMosaicItem(attachment))} +
+
+ {renderFootnote()} +
+ ); + + case 8: + return ( +
+
{renderMosaicItem(mediaAttachments[0])}
{renderMosaicItem(mediaAttachments[1])}
- {mediaAttachments.slice(2, 5).map((attachment) => renderMosaicItem(attachment))} + {mediaAttachments.slice(2, 8).map((attachment) => renderMosaicItem(attachment))}
+ {renderFootnote()}
- {renderFootnote()} -
- ); + ); - case 6: - return renderGrid(mediaAttachments, styles.threeByThreeGrid); + case 9: + return renderGrid(mediaAttachments, styles.threeByThreeGrid); - case 7: - return ( -
-
-
- {renderMosaicItem(mediaAttachments[0])} -
-
- {mediaAttachments.slice(1, 7).map((attachment) => renderMosaicItem(attachment))} + case 10: + return ( +
+
+
+ {renderMosaicItem(mediaAttachments[0])} +
+
+ {mediaAttachments.slice(1, 10).map((attachment) => renderMosaicItem(attachment))} +
+ {renderFootnote()}
- {renderFootnote()} -
- ); + ); - case 8: - return ( -
-
-
-
{renderMosaicItem(mediaAttachments[0])}
-
{renderMosaicItem(mediaAttachments[1])}
-
-
- {mediaAttachments.slice(2, 8).map((attachment) => renderMosaicItem(attachment))} -
-
- {renderFootnote()} -
- ); - - case 9: - return renderGrid(mediaAttachments, styles.threeByThreeGrid); - - case 10: - return ( -
-
-
- {renderMosaicItem(mediaAttachments[0])} -
-
- {mediaAttachments.slice(1, 10).map((attachment) => renderMosaicItem(attachment))} -
-
- {renderFootnote()} -
- ); - - default: - throw new Error('This should never happen'); - } -}); + default: + throw new Error('This should never happen'); + } + }, +); export const AttachmentMosaic: FC = AttachmentMosaicComponent; diff --git a/fluxer_app/src/components/channel/embeds/media/EmbedAudio.tsx b/fluxer_app/src/components/channel/embeds/media/EmbedAudio.tsx index 01ea66e7..645495bf 100644 --- a/fluxer_app/src/components/channel/embeds/media/EmbedAudio.tsx +++ b/fluxer_app/src/components/channel/embeds/media/EmbedAudio.tsx @@ -25,8 +25,8 @@ import {type FC, useCallback, useEffect, useRef, useState} from 'react'; import * as ContextMenuActionCreators from '~/actions/ContextMenuActionCreators'; import * as MediaViewerActionCreators from '~/actions/MediaViewerActionCreators'; import {deriveDefaultNameFromMessage, splitFilename} from '~/components/channel/embeds/EmbedUtils'; +import {getMediaButtonVisibility} from '~/components/channel/embeds/media/MediaButtonUtils'; import type {BaseMediaProps} from '~/components/channel/embeds/media/MediaTypes'; -import {canDeleteAttachmentUtil} from '~/components/channel/messageActionUtils'; import {InlineAudioPlayer} from '~/components/media-player/components/InlineAudioPlayer'; import {MediaContextMenu} from '~/components/uikit/ContextMenu/MediaContextMenu'; import {Tooltip} from '~/components/uikit/Tooltip/Tooltip'; @@ -47,6 +47,7 @@ type EmbedAudioProps = BaseMediaProps & { embedUrl?: string; fileSize?: number; mediaAttachments?: ReadonlyArray; + isPreview?: boolean; }; const EmbedAudio: FC = observer( @@ -63,6 +64,7 @@ const EmbedAudio: FC = observer( contentHash, onDelete, fileSize, + isPreview, }) => { const {t} = useLingui(); const effectiveSrc = buildMediaProxyURL(src); @@ -88,7 +90,7 @@ const EmbedAudio: FC = observer( const handleContextMenu = useCallback( (e: React.MouseEvent) => { - if (!message) return; + if (!message || isPreview) return; e.preventDefault(); e.stopPropagation(); @@ -106,7 +108,7 @@ const EmbedAudio: FC = observer( /> )); }, - [message, src, contentHash, attachmentId, defaultName, onDelete], + [message, src, contentHash, attachmentId, defaultName, onDelete, isPreview], ); useEffect(() => { @@ -189,7 +191,12 @@ const EmbedAudio: FC = observer( maxWidth: '400px', }; - const canDelete = canDeleteAttachmentUtil(message) && !isMobile; + const {showDeleteButton, showDownloadButton} = getMediaButtonVisibility( + canFavorite, + isPreview ? undefined : message, + attachmentId, + {disableDelete: !!isPreview}, + ); if (isMobile) { return ( @@ -223,7 +230,7 @@ const EmbedAudio: FC = observer( return (
- {canDelete && ( + {showDeleteButton && (
diff --git a/fluxer_app/src/components/channel/embeds/media/EmbedGifv.tsx b/fluxer_app/src/components/channel/embeds/media/EmbedGifv.tsx index 74ee5183..ed6051b0 100644 --- a/fluxer_app/src/components/channel/embeds/media/EmbedGifv.tsx +++ b/fluxer_app/src/components/channel/embeds/media/EmbedGifv.tsx @@ -255,6 +255,7 @@ export const EmbedGifv: FC< videoProxyURL: string; videoURL: string; videoConfig?: VideoConfig; + isPreview?: boolean; } > = observer( ({ @@ -272,6 +273,7 @@ export const EmbedGifv: FC< message, contentHash, onDelete, + isPreview, }) => { const {t} = useLingui(); const {loaded, error, thumbHashURL} = useMediaLoading( @@ -329,7 +331,7 @@ export const EmbedGifv: FC< const handleContextMenu = useCallback( (e: React.MouseEvent) => { - if (!message) return; + if (!message || isPreview) return; e.preventDefault(); e.stopPropagation(); @@ -348,7 +350,7 @@ export const EmbedGifv: FC< /> )); }, - [message, embedURL, videoProxyURL, contentHash, attachmentId, defaultName, onDelete], + [message, embedURL, videoProxyURL, contentHash, attachmentId, defaultName, onDelete, isPreview], ); useEffect(() => { @@ -449,7 +451,9 @@ export const EmbedGifv: FC< showFavoriteButton, showDownloadButton: _showDownloadButton, showDeleteButton, - } = getMediaButtonVisibility(canFavorite, message, attachmentId); + } = getMediaButtonVisibility(canFavorite, isPreview ? undefined : message, attachmentId, { + disableDelete: !!isPreview, + }); const showDownloadButton = false; const showGifIndicator = AccessibilityStore.showGifIndicator && shouldShowOverlays(dimensions.width, dimensions.height); @@ -515,7 +519,7 @@ export const EmbedGifv: FC< }, ); -export const EmbedGif: FC = observer( +export const EmbedGif: FC = observer( ({ embedURL, proxyURL, @@ -530,6 +534,7 @@ export const EmbedGif: FC { const {t} = useLingui(); const {dimensions} = mediaCalculator.calculate({width: naturalWidth, height: naturalHeight}, {forceScale: true}); @@ -601,7 +606,7 @@ export const EmbedGif: FC { - if (!message) return; + if (!message || isPreview) return; e.preventDefault(); e.stopPropagation(); @@ -620,7 +625,7 @@ export const EmbedGif: FC )); }, - [message, embedURL, proxyURL, contentHash, attachmentId, defaultName, onDelete], + [message, embedURL, proxyURL, contentHash, attachmentId, defaultName, onDelete, isPreview], ); useEffect(() => { @@ -697,8 +702,9 @@ export const EmbedGif: FC & handlePress?: (event: React.MouseEvent | React.KeyboardEvent) => void; alt?: string; mediaAttachments?: ReadonlyArray; + isPreview?: boolean; }; const ImagePreviewHandler: FC = observer( @@ -216,6 +217,7 @@ export const EmbedImage: FC = observer( contentHash, onDelete, mediaAttachments = [], + isPreview, }) => { const {t} = useLingui(); const {loaded, error, thumbHashURL} = useMediaLoading(src, placeholder); @@ -271,7 +273,7 @@ export const EmbedImage: FC = observer( const handleContextMenu = useCallback( (e: React.MouseEvent) => { - if (!message) return; + if (!message || isPreview) return; e.preventDefault(); e.stopPropagation(); @@ -292,7 +294,7 @@ export const EmbedImage: FC = observer( /> )); }, - [message, src, originalSrc, contentHash, attachmentId, embedIndex, alt, defaultName, onDelete], + [message, src, originalSrc, contentHash, attachmentId, embedIndex, alt, defaultName, onDelete, isPreview], ); if (shouldBlur) { @@ -324,8 +326,9 @@ export const EmbedImage: FC = observer( const {showFavoriteButton, showDownloadButton, showDeleteButton} = getMediaButtonVisibility( canFavorite, - message, + isPreview ? undefined : message, attachmentId, + {disableDelete: !!isPreview}, ); return ( diff --git a/fluxer_app/src/components/channel/embeds/media/EmbedVideo.tsx b/fluxer_app/src/components/channel/embeds/media/EmbedVideo.tsx index e2f158aa..35a54c1a 100644 --- a/fluxer_app/src/components/channel/embeds/media/EmbedVideo.tsx +++ b/fluxer_app/src/components/channel/embeds/media/EmbedVideo.tsx @@ -65,6 +65,7 @@ type EmbedVideoProps = BaseMediaProps & { embedUrl?: string; fillContainer?: boolean; mediaAttachments?: ReadonlyArray; + isPreview?: boolean; }; const MobileVideoOverlay: FC<{ @@ -125,6 +126,7 @@ const EmbedVideo: FC = observer( onDelete, fillContainer = false, mediaAttachments = [], + isPreview, }) => { const {enabled: isMobile} = MobileLayoutStore; const effectiveSrc = buildMediaProxyURL(src); @@ -162,7 +164,7 @@ const EmbedVideo: FC = observer( const handleContextMenu = useCallback( (e: React.MouseEvent) => { - if (!message) return; + if (!message || isPreview) return; e.preventDefault(); e.stopPropagation(); @@ -180,7 +182,7 @@ const EmbedVideo: FC = observer( /> )); }, - [message, src, contentHash, attachmentId, defaultName, onDelete], + [message, src, contentHash, attachmentId, defaultName, onDelete, isPreview], ); const thumbHashUrl = placeholder @@ -268,8 +270,9 @@ const EmbedVideo: FC = observer( const {showFavoriteButton, showDownloadButton, showDeleteButton} = getMediaButtonVisibility( canFavorite, - message, + isPreview ? undefined : message, attachmentId, + {disableDelete: !!isPreview}, ); if (isMobile) { diff --git a/fluxer_app/src/components/channel/embeds/media/MediaButtonUtils.tsx b/fluxer_app/src/components/channel/embeds/media/MediaButtonUtils.tsx index 0b63944e..285c62a3 100644 --- a/fluxer_app/src/components/channel/embeds/media/MediaButtonUtils.tsx +++ b/fluxer_app/src/components/channel/embeds/media/MediaButtonUtils.tsx @@ -21,6 +21,10 @@ import {canDeleteAttachmentUtil} from '~/components/channel/messageActionUtils'; import type {MessageRecord} from '~/records/MessageRecord'; import AccessibilityStore from '~/stores/AccessibilityStore'; +export interface MediaButtonVisibilityOptions { + disableDelete?: boolean; +} + export interface MediaButtonVisibility { showFavoriteButton: boolean; showDownloadButton: boolean; @@ -31,14 +35,17 @@ export function getMediaButtonVisibility( canFavorite: boolean, message?: MessageRecord, attachmentId?: string, + options?: MediaButtonVisibilityOptions, ): MediaButtonVisibility { const showMediaFavoriteButton = AccessibilityStore.showMediaFavoriteButton; const showMediaDownloadButton = AccessibilityStore.showMediaDownloadButton; const showMediaDeleteButton = AccessibilityStore.showMediaDeleteButton; + const disableDelete = options?.disableDelete ?? false; return { showFavoriteButton: showMediaFavoriteButton && canFavorite, showDownloadButton: showMediaDownloadButton, - showDeleteButton: showMediaDeleteButton && !!(message && attachmentId && canDeleteAttachmentUtil(message)), + showDeleteButton: + showMediaDeleteButton && !disableDelete && !!(message && attachmentId && canDeleteAttachmentUtil(message)), }; }