mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
feat(app): delete attachments from the media viewer (#2039)
This commit is contained in:
1 parent
88d85919f1
commit
509562e6da
11 files changed
+92
-11
No files matched your search
+2
-1
@@ -208,9 +208,10 @@ export const AttachmentGridItem: FC<AttachmentGridItemProps> = observer(
|
|||||||
messageId: message?.id,
|
messageId: message?.id,
|
||||||
message,
|
message,
|
||||||
sourceChannel: messageViewContext?.channel,
|
sourceChannel: messageViewContext?.channel,
|
||||||
|
allowAttachmentDelete: !isPreview && snapshotIndex === undefined,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[attachment, message, messageViewContext?.channel, mediaAttachments, shouldBlur],
|
[attachment, message, messageViewContext?.channel, mediaAttachments, shouldBlur, isPreview, snapshotIndex],
|
||||||
);
|
);
|
||||||
const openInBrowser = useOpenInBrowserOnMiddleClick(attachment.url ?? attachment.proxy_url ?? '', !shouldBlur);
|
const openInBrowser = useOpenInBrowserOnMiddleClick(attachment.url ?? attachment.proxy_url ?? '', !shouldBlur);
|
||||||
const handleFavoriteClick = useCallback(
|
const handleFavoriteClick = useCallback(
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ const useImagePreview = ({
|
|||||||
message,
|
message,
|
||||||
sourceChannel,
|
sourceChannel,
|
||||||
providerName,
|
providerName,
|
||||||
|
allowAttachmentDelete = false,
|
||||||
}: {
|
}: {
|
||||||
proxyUrl: string;
|
proxyUrl: string;
|
||||||
embedUrl: string;
|
embedUrl: string;
|
||||||
@@ -195,6 +196,7 @@ const useImagePreview = ({
|
|||||||
message?: Message;
|
message?: Message;
|
||||||
sourceChannel?: Channel | null;
|
sourceChannel?: Channel | null;
|
||||||
providerName?: string;
|
providerName?: string;
|
||||||
|
allowAttachmentDelete?: boolean;
|
||||||
}): {viewerItem: MediaViewerItem; openPreview: (event: React.MouseEvent | React.KeyboardEvent) => void} => {
|
}): {viewerItem: MediaViewerItem; openPreview: (event: React.MouseEvent | React.KeyboardEvent) => void} => {
|
||||||
const viewerItem = useMemo<MediaViewerItem>(
|
const viewerItem = useMemo<MediaViewerItem>(
|
||||||
() => ({
|
() => ({
|
||||||
@@ -223,9 +225,10 @@ const useImagePreview = ({
|
|||||||
messageId,
|
messageId,
|
||||||
message,
|
message,
|
||||||
sourceChannel,
|
sourceChannel,
|
||||||
|
allowAttachmentDelete,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[viewerItem, channelId, messageId, message, sourceChannel],
|
[viewerItem, channelId, messageId, message, sourceChannel, allowAttachmentDelete],
|
||||||
);
|
);
|
||||||
return {viewerItem, openPreview};
|
return {viewerItem, openPreview};
|
||||||
};
|
};
|
||||||
@@ -461,6 +464,7 @@ export const EmbedGifv: FC<
|
|||||||
message,
|
message,
|
||||||
sourceChannel: messageViewContext?.channel,
|
sourceChannel: messageViewContext?.channel,
|
||||||
providerName,
|
providerName,
|
||||||
|
allowAttachmentDelete: !isPreview && snapshotIndex === undefined,
|
||||||
});
|
});
|
||||||
const handleDeleteClick = useDeleteAttachment(message, attachmentId);
|
const handleDeleteClick = useDeleteAttachment(message, attachmentId);
|
||||||
const handleDownloadClick = useCallback(
|
const handleDownloadClick = useCallback(
|
||||||
@@ -795,6 +799,7 @@ export const EmbedGif: FC<
|
|||||||
contentHash,
|
contentHash,
|
||||||
message,
|
message,
|
||||||
sourceChannel: messageViewContext?.channel,
|
sourceChannel: messageViewContext?.channel,
|
||||||
|
allowAttachmentDelete: !isPreview && snapshotIndex === undefined,
|
||||||
});
|
});
|
||||||
const {scheduleViewerWarm, cancelViewerWarm} = useMediaViewerHoverWarm(viewerItem, {
|
const {scheduleViewerWarm, cancelViewerWarm} = useMediaViewerHoverWarm(viewerItem, {
|
||||||
allowAnimated: gifAutoPlay,
|
allowAnimated: gifAutoPlay,
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ interface ImagePreviewHandlerProps {
|
|||||||
message?: Message;
|
message?: Message;
|
||||||
animated?: boolean;
|
animated?: boolean;
|
||||||
mediaAttachments?: ReadonlyArray<MessageAttachment>;
|
mediaAttachments?: ReadonlyArray<MessageAttachment>;
|
||||||
|
allowAttachmentDelete?: boolean;
|
||||||
onViewerWarmEnter?: () => void;
|
onViewerWarmEnter?: () => void;
|
||||||
onViewerWarmLeave?: () => void;
|
onViewerWarmLeave?: () => void;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@@ -143,6 +144,7 @@ const ImagePreviewHandler: FC<ImagePreviewHandlerProps> = observer(
|
|||||||
message,
|
message,
|
||||||
animated,
|
animated,
|
||||||
mediaAttachments = NO_MEDIA_ATTACHMENTS,
|
mediaAttachments = NO_MEDIA_ATTACHMENTS,
|
||||||
|
allowAttachmentDelete = false,
|
||||||
onViewerWarmEnter,
|
onViewerWarmEnter,
|
||||||
onViewerWarmLeave,
|
onViewerWarmLeave,
|
||||||
children,
|
children,
|
||||||
@@ -176,6 +178,7 @@ const ImagePreviewHandler: FC<ImagePreviewHandlerProps> = observer(
|
|||||||
messageId,
|
messageId,
|
||||||
message,
|
message,
|
||||||
sourceChannel: messageViewContext?.channel,
|
sourceChannel: messageViewContext?.channel,
|
||||||
|
allowAttachmentDelete,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
MediaViewerCommands.openMediaViewer(
|
MediaViewerCommands.openMediaViewer(
|
||||||
@@ -187,6 +190,7 @@ const ImagePreviewHandler: FC<ImagePreviewHandlerProps> = observer(
|
|||||||
naturalHeight,
|
naturalHeight,
|
||||||
type: 'image' as const,
|
type: 'image' as const,
|
||||||
contentHash,
|
contentHash,
|
||||||
|
attachmentId,
|
||||||
embedIndex,
|
embedIndex,
|
||||||
expiresAt: undefined,
|
expiresAt: undefined,
|
||||||
expired: undefined,
|
expired: undefined,
|
||||||
@@ -199,6 +203,7 @@ const ImagePreviewHandler: FC<ImagePreviewHandlerProps> = observer(
|
|||||||
messageId,
|
messageId,
|
||||||
message,
|
message,
|
||||||
sourceChannel: messageViewContext?.channel,
|
sourceChannel: messageViewContext?.channel,
|
||||||
|
allowAttachmentDelete,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -217,6 +222,7 @@ const ImagePreviewHandler: FC<ImagePreviewHandlerProps> = observer(
|
|||||||
message,
|
message,
|
||||||
messageViewContext?.channel,
|
messageViewContext?.channel,
|
||||||
mediaAttachments,
|
mediaAttachments,
|
||||||
|
allowAttachmentDelete,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
const openInBrowser = useOpenInBrowserOnMiddleClick(originalSrc || src);
|
const openInBrowser = useOpenInBrowserOnMiddleClick(originalSrc || src);
|
||||||
@@ -381,6 +387,7 @@ export const EmbedImage: FC<EmbedImageProps> = observer(
|
|||||||
[originalSrc, src],
|
[originalSrc, src],
|
||||||
);
|
);
|
||||||
const handleDeleteClick = useDeleteAttachment(message, attachmentId);
|
const handleDeleteClick = useDeleteAttachment(message, attachmentId);
|
||||||
|
const allowAttachmentDelete = !isPreview && snapshotIndex === undefined;
|
||||||
const [mediaSheetOpen, setMediaSheetOpen] = useState(false);
|
const [mediaSheetOpen, setMediaSheetOpen] = useState(false);
|
||||||
const handleContextMenu = useCallback(
|
const handleContextMenu = useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
@@ -524,6 +531,7 @@ export const EmbedImage: FC<EmbedImageProps> = observer(
|
|||||||
attachmentId={attachmentId}
|
attachmentId={attachmentId}
|
||||||
message={message}
|
message={message}
|
||||||
mediaAttachments={mediaAttachments}
|
mediaAttachments={mediaAttachments}
|
||||||
|
allowAttachmentDelete={allowAttachmentDelete}
|
||||||
animated={animated}
|
animated={animated}
|
||||||
onViewerWarmEnter={scheduleViewerWarm}
|
onViewerWarmEnter={scheduleViewerWarm}
|
||||||
onViewerWarmLeave={cancelViewerWarm}
|
onViewerWarmLeave={cancelViewerWarm}
|
||||||
|
|||||||
@@ -272,6 +272,7 @@ const EmbedVideo: FC<EmbedVideoProps> = observer(
|
|||||||
[src],
|
[src],
|
||||||
);
|
);
|
||||||
const handleDeleteClick = useDeleteAttachment(message, attachmentId);
|
const handleDeleteClick = useDeleteAttachment(message, attachmentId);
|
||||||
|
const allowAttachmentDelete = !isPreview && snapshotIndex === undefined;
|
||||||
const handleContextMenu = useCallback(
|
const handleContextMenu = useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
if (!message) return;
|
if (!message) return;
|
||||||
@@ -396,6 +397,7 @@ const EmbedVideo: FC<EmbedVideoProps> = observer(
|
|||||||
messageId,
|
messageId,
|
||||||
message,
|
message,
|
||||||
sourceChannel: messageViewContext?.channel,
|
sourceChannel: messageViewContext?.channel,
|
||||||
|
allowAttachmentDelete,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
MediaViewerCommands.openMediaViewer(
|
MediaViewerCommands.openMediaViewer(
|
||||||
@@ -407,12 +409,13 @@ const EmbedVideo: FC<EmbedVideoProps> = observer(
|
|||||||
naturalHeight: viewerVideoDimensions.height,
|
naturalHeight: viewerVideoDimensions.height,
|
||||||
type: 'video' as const,
|
type: 'video' as const,
|
||||||
contentHash,
|
contentHash,
|
||||||
|
attachmentId,
|
||||||
embedIndex,
|
embedIndex,
|
||||||
duration,
|
duration,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
{channelId, messageId, message, sourceChannel: messageViewContext?.channel},
|
{channelId, messageId, message, sourceChannel: messageViewContext?.channel, allowAttachmentDelete},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
@@ -420,6 +423,7 @@ const EmbedVideo: FC<EmbedVideoProps> = observer(
|
|||||||
messageId,
|
messageId,
|
||||||
message,
|
message,
|
||||||
messageViewContext?.channel,
|
messageViewContext?.channel,
|
||||||
|
allowAttachmentDelete,
|
||||||
mediaAttachments,
|
mediaAttachments,
|
||||||
attachmentId,
|
attachmentId,
|
||||||
effectiveSrc,
|
effectiveSrc,
|
||||||
@@ -451,6 +455,7 @@ const EmbedVideo: FC<EmbedVideoProps> = observer(
|
|||||||
messageId,
|
messageId,
|
||||||
message,
|
message,
|
||||||
sourceChannel: messageViewContext?.channel,
|
sourceChannel: messageViewContext?.channel,
|
||||||
|
allowAttachmentDelete,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
MediaViewerCommands.openMediaViewer(
|
MediaViewerCommands.openMediaViewer(
|
||||||
@@ -462,13 +467,14 @@ const EmbedVideo: FC<EmbedVideoProps> = observer(
|
|||||||
naturalHeight: viewerVideoDimensions.height,
|
naturalHeight: viewerVideoDimensions.height,
|
||||||
type: 'video' as const,
|
type: 'video' as const,
|
||||||
contentHash,
|
contentHash,
|
||||||
|
attachmentId,
|
||||||
embedIndex,
|
embedIndex,
|
||||||
duration,
|
duration,
|
||||||
initialTime: currentTime,
|
initialTime: currentTime,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
{channelId, messageId, message, sourceChannel: messageViewContext?.channel},
|
{channelId, messageId, message, sourceChannel: messageViewContext?.channel, allowAttachmentDelete},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
setIsPlayingInline(false);
|
setIsPlayingInline(false);
|
||||||
@@ -477,6 +483,7 @@ const EmbedVideo: FC<EmbedVideoProps> = observer(
|
|||||||
messageId,
|
messageId,
|
||||||
message,
|
message,
|
||||||
messageViewContext?.channel,
|
messageViewContext?.channel,
|
||||||
|
allowAttachmentDelete,
|
||||||
mediaAttachments,
|
mediaAttachments,
|
||||||
attachmentId,
|
attachmentId,
|
||||||
effectiveSrc,
|
effectiveSrc,
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ export const MediaModal: FC<MediaModalProps> = observer(
|
|||||||
onOpenInBrowser,
|
onOpenInBrowser,
|
||||||
onCopyLink,
|
onCopyLink,
|
||||||
onCopyMedia,
|
onCopyMedia,
|
||||||
|
onDeleteAttachment,
|
||||||
onReply,
|
onReply,
|
||||||
onForward,
|
onForward,
|
||||||
children,
|
children,
|
||||||
@@ -636,6 +637,7 @@ export const MediaModal: FC<MediaModalProps> = observer(
|
|||||||
onOpenInBrowser={onOpenInBrowser}
|
onOpenInBrowser={onOpenInBrowser}
|
||||||
onCopyLink={onCopyLink}
|
onCopyLink={onCopyLink}
|
||||||
onCopyMedia={onCopyMedia}
|
onCopyMedia={onCopyMedia}
|
||||||
|
onDeleteAttachment={onDeleteAttachment}
|
||||||
onReset={handleResetMedia}
|
onReset={handleResetMedia}
|
||||||
onZoomIn={handleZoomIn}
|
onZoomIn={handleZoomIn}
|
||||||
onZoomOut={handleZoomOut}
|
onZoomOut={handleZoomOut}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
import Accessibility from '@app/features/accessibility/state/Accessibility';
|
||||||
import {useBottomSheetBackHandler} from '@app/features/app/hooks/useBottomSheetBackHandler';
|
import {useBottomSheetBackHandler} from '@app/features/app/hooks/useBottomSheetBackHandler';
|
||||||
import {deriveDefaultNameFromMessage} from '@app/features/channel/components/embeds/EmbedUtils';
|
import {deriveDefaultNameFromMessage} from '@app/features/channel/components/embeds/EmbedUtils';
|
||||||
import {useMessageActionMenuData} from '@app/features/channel/components/MessageActionMenu';
|
import {useMessageActionMenuData} from '@app/features/channel/components/MessageActionMenu';
|
||||||
@@ -14,6 +15,7 @@ import type {ForwardModalSuccess} from '@app/features/messaging/components/modal
|
|||||||
import {MediaModal} from '@app/features/messaging/components/modals/MediaModal';
|
import {MediaModal} from '@app/features/messaging/components/modals/MediaModal';
|
||||||
import styles from '@app/features/messaging/components/modals/MediaViewerModal.module.css';
|
import styles from '@app/features/messaging/components/modals/MediaViewerModal.module.css';
|
||||||
import {getMediaViewerPortalRoot} from '@app/features/messaging/components/modals/MediaViewerPortal';
|
import {getMediaViewerPortalRoot} from '@app/features/messaging/components/modals/MediaViewerPortal';
|
||||||
|
import {useDeleteAttachment} from '@app/features/messaging/hooks/useDeleteAttachment';
|
||||||
import {useMediaFavorite} from '@app/features/messaging/hooks/useMediaFavorite';
|
import {useMediaFavorite} from '@app/features/messaging/hooks/useMediaFavorite';
|
||||||
import type {Message} from '@app/features/messaging/models/MessagingMessage';
|
import type {Message} from '@app/features/messaging/models/MessagingMessage';
|
||||||
import {formatAttachmentDate} from '@app/features/messaging/utils/AttachmentExpiryUtils';
|
import {formatAttachmentDate} from '@app/features/messaging/utils/AttachmentExpiryUtils';
|
||||||
@@ -273,7 +275,8 @@ const MobileMediaOptionsSheet: FC<MobileMediaOptionsSheetProps> = observer(funct
|
|||||||
});
|
});
|
||||||
const MediaViewerModalComponent: FC = observer(() => {
|
const MediaViewerModalComponent: FC = observer(() => {
|
||||||
const {i18n} = useLingui();
|
const {i18n} = useLingui();
|
||||||
const {isOpen, items, currentIndex, channelId, messageId, message, sourceChannel} = MediaViewer;
|
const {isOpen, items, currentIndex, channelId, messageId, message, sourceChannel, allowAttachmentDelete} =
|
||||||
|
MediaViewer;
|
||||||
const {enabled: isMobile} = MobileLayout;
|
const {enabled: isMobile} = MobileLayout;
|
||||||
const [isMediaMenuOpen, setIsMediaMenuOpen] = useState(false);
|
const [isMediaMenuOpen, setIsMediaMenuOpen] = useState(false);
|
||||||
const currentItem = items[currentIndex];
|
const currentItem = items[currentIndex];
|
||||||
@@ -438,6 +441,22 @@ const MediaViewerModalComponent: FC = observer(() => {
|
|||||||
() => (message ? untracked(() => getMessagePermissions(message, sourceChannel)) : null),
|
() => (message ? untracked(() => getMessagePermissions(message, sourceChannel)) : null),
|
||||||
[message, sourceChannel],
|
[message, sourceChannel],
|
||||||
);
|
);
|
||||||
|
const deletableAttachmentId =
|
||||||
|
Accessibility.showMediaDeleteButton &&
|
||||||
|
allowAttachmentDelete &&
|
||||||
|
permissions?.canDeleteAttachment &&
|
||||||
|
currentItem?.attachmentId &&
|
||||||
|
message?.attachments.some((attachment) => attachment.id === currentItem.attachmentId)
|
||||||
|
? currentItem.attachmentId
|
||||||
|
: undefined;
|
||||||
|
const handleAttachmentDeleted = useCallback(() => {
|
||||||
|
if (MediaViewer.isOpen && MediaViewer.items === items) {
|
||||||
|
MediaViewerCommands.closeMediaViewer();
|
||||||
|
}
|
||||||
|
}, [items]);
|
||||||
|
const handleDeleteAttachment = useDeleteAttachment(message, deletableAttachmentId, {
|
||||||
|
onDeleted: handleAttachmentDeleted,
|
||||||
|
});
|
||||||
const forwardMediaSelection = useMemo<MessageCommands.ForwardMediaSelection | undefined>(() => {
|
const forwardMediaSelection = useMemo<MessageCommands.ForwardMediaSelection | undefined>(() => {
|
||||||
if (!currentItem) return undefined;
|
if (!currentItem) return undefined;
|
||||||
if (currentItem.attachmentId) {
|
if (currentItem.attachmentId) {
|
||||||
@@ -672,6 +691,7 @@ const MediaViewerModalComponent: FC = observer(() => {
|
|||||||
onOpenInBrowser={handleOpenInBrowser}
|
onOpenInBrowser={handleOpenInBrowser}
|
||||||
onCopyLink={handleCopyLink}
|
onCopyLink={handleCopyLink}
|
||||||
onCopyMedia={handleCopyMedia}
|
onCopyMedia={handleCopyMedia}
|
||||||
|
onDeleteAttachment={deletableAttachmentId ? handleDeleteAttachment : undefined}
|
||||||
onReply={permissions?.canSendMessages ? handleReply : undefined}
|
onReply={permissions?.canSendMessages ? handleReply : undefined}
|
||||||
onForward={canForwardCurrentMedia ? handleForward : undefined}
|
onForward={canForwardCurrentMedia ? handleForward : undefined}
|
||||||
enablePanZoom={currentItem.type === 'image' || currentItem.type === 'gif' || currentItem.type === 'gifv'}
|
enablePanZoom={currentItem.type === 'image' || currentItem.type === 'gif' || currentItem.type === 'gifv'}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import {
|
import {
|
||||||
ADD_TO_FAVORITES_DESCRIPTOR,
|
ADD_TO_FAVORITES_DESCRIPTOR,
|
||||||
COPY_LINK_DESCRIPTOR,
|
COPY_LINK_DESCRIPTOR,
|
||||||
|
DELETE_ATTACHMENT_DESCRIPTOR,
|
||||||
REMOVE_FROM_FAVORITES_DESCRIPTOR,
|
REMOVE_FROM_FAVORITES_DESCRIPTOR,
|
||||||
ZOOM_IN_DESCRIPTOR,
|
ZOOM_IN_DESCRIPTOR,
|
||||||
ZOOM_OUT_DESCRIPTOR,
|
ZOOM_OUT_DESCRIPTOR,
|
||||||
@@ -36,16 +37,17 @@ import {
|
|||||||
MagnifyingGlassMinusIcon,
|
MagnifyingGlassMinusIcon,
|
||||||
MagnifyingGlassPlusIcon,
|
MagnifyingGlassPlusIcon,
|
||||||
StarIcon,
|
StarIcon,
|
||||||
|
TrashIcon,
|
||||||
XIcon,
|
XIcon,
|
||||||
} from '@phosphor-icons/react';
|
} from '@phosphor-icons/react';
|
||||||
import {clsx} from 'clsx';
|
import {clsx} from 'clsx';
|
||||||
import {observer} from 'mobx-react-lite';
|
import {observer} from 'mobx-react-lite';
|
||||||
import {type FC, forwardRef, type ReactNode, type Ref} from 'react';
|
import {type FC, forwardRef, type MouseEventHandler, type ReactNode, type Ref} from 'react';
|
||||||
|
|
||||||
interface ControlButtonProps {
|
interface ControlButtonProps {
|
||||||
icon: ReactNode;
|
icon: ReactNode;
|
||||||
label: string;
|
label: string;
|
||||||
onClick: () => void;
|
onClick: MouseEventHandler<HTMLButtonElement>;
|
||||||
variant?: 'default' | 'primary' | 'danger';
|
variant?: 'default' | 'primary' | 'danger';
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -119,6 +121,7 @@ interface MediaOverlayActionsProps {
|
|||||||
onOpenInBrowser?: () => void;
|
onOpenInBrowser?: () => void;
|
||||||
onCopyLink?: () => void;
|
onCopyLink?: () => void;
|
||||||
onCopyMedia?: () => void;
|
onCopyMedia?: () => void;
|
||||||
|
onDeleteAttachment?: MouseEventHandler<HTMLButtonElement>;
|
||||||
onReset?: () => void;
|
onReset?: () => void;
|
||||||
onZoomIn?: () => void;
|
onZoomIn?: () => void;
|
||||||
onZoomOut?: () => void;
|
onZoomOut?: () => void;
|
||||||
@@ -144,6 +147,7 @@ export const MediaOverlayActions: FC<MediaOverlayActionsProps> = observer(
|
|||||||
onOpenInBrowser,
|
onOpenInBrowser,
|
||||||
onCopyLink,
|
onCopyLink,
|
||||||
onCopyMedia,
|
onCopyMedia,
|
||||||
|
onDeleteAttachment,
|
||||||
onReset,
|
onReset,
|
||||||
onZoomIn,
|
onZoomIn,
|
||||||
onZoomOut,
|
onZoomOut,
|
||||||
@@ -250,6 +254,21 @@ export const MediaOverlayActions: FC<MediaOverlayActionsProps> = observer(
|
|||||||
data-flx="messaging.media-modal.media-controls.media-overlay-actions.overlay-tooltip-button.download"
|
data-flx="messaging.media-modal.media-controls.media-overlay-actions.overlay-tooltip-button.download"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{onDeleteAttachment && (
|
||||||
|
<OverlayTooltipButton
|
||||||
|
icon={
|
||||||
|
<TrashIcon
|
||||||
|
size={20}
|
||||||
|
weight="bold"
|
||||||
|
data-flx="messaging.media-modal.media-overlay-actions.delete-attachment-icon"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={i18n._(DELETE_ATTACHMENT_DESCRIPTOR)}
|
||||||
|
onClick={onDeleteAttachment}
|
||||||
|
variant="danger"
|
||||||
|
data-flx="messaging.media-modal.media-controls.media-overlay-actions.overlay-tooltip-button.delete-attachment"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
className={styles.overlayActionGap}
|
className={styles.overlayActionGap}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import {msg} from '@lingui/core/macro';
|
import {msg} from '@lingui/core/macro';
|
||||||
import type {ReactNode} from 'react';
|
import type {MouseEventHandler, ReactNode} from 'react';
|
||||||
|
|
||||||
export type ZoomState = 'fit' | 'zoomed';
|
export type ZoomState = 'fit' | 'zoomed';
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@ export interface MediaModalProps {
|
|||||||
onOpenInBrowser?: () => void;
|
onOpenInBrowser?: () => void;
|
||||||
onCopyLink?: () => void;
|
onCopyLink?: () => void;
|
||||||
onCopyMedia?: () => void;
|
onCopyMedia?: () => void;
|
||||||
|
onDeleteAttachment?: MouseEventHandler<HTMLButtonElement>;
|
||||||
onReply?: () => void;
|
onReply?: () => void;
|
||||||
onForward?: () => void;
|
onForward?: () => void;
|
||||||
onInfo?: () => void;
|
onInfo?: () => void;
|
||||||
|
|||||||
@@ -9,14 +9,26 @@ import {modal} from '@app/features/ui/commands/ModalCommands';
|
|||||||
import {Trans, useLingui} from '@lingui/react/macro';
|
import {Trans, useLingui} from '@lingui/react/macro';
|
||||||
import {useCallback} from 'react';
|
import {useCallback} from 'react';
|
||||||
|
|
||||||
export function useDeleteAttachment(message: Message | null | undefined, attachmentId: string | null | undefined) {
|
interface DeleteAttachmentOptions {
|
||||||
|
onDeleted?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDeleteAttachment(
|
||||||
|
message: Message | null | undefined,
|
||||||
|
attachmentId: string | null | undefined,
|
||||||
|
options?: DeleteAttachmentOptions,
|
||||||
|
) {
|
||||||
const {i18n} = useLingui();
|
const {i18n} = useLingui();
|
||||||
|
const onDeleted = options?.onDeleted;
|
||||||
return useCallback(
|
return useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (!message || !attachmentId) return;
|
if (!message || !attachmentId) return;
|
||||||
const deleteAttachment = () => MessageCommands.deleteAttachment(message.channelId, message.id, attachmentId);
|
const deleteAttachment = async () => {
|
||||||
|
await MessageCommands.deleteAttachment(message.channelId, message.id, attachmentId);
|
||||||
|
onDeleted?.();
|
||||||
|
};
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
void deleteAttachment();
|
void deleteAttachment();
|
||||||
return;
|
return;
|
||||||
@@ -39,6 +51,6 @@ export function useDeleteAttachment(message: Message | null | undefined, attachm
|
|||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[message, attachmentId, i18n],
|
[message, attachmentId, i18n, onDeleted],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@ interface MediaViewerOpenOptions {
|
|||||||
messageId?: string;
|
messageId?: string;
|
||||||
message?: Message;
|
message?: Message;
|
||||||
sourceChannel?: Channel | null;
|
sourceChannel?: Channel | null;
|
||||||
|
allowAttachmentDelete?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type MediaViewerIntent =
|
type MediaViewerIntent =
|
||||||
@@ -26,6 +27,7 @@ function dispatchMediaViewerIntent(intent: MediaViewerIntent): void {
|
|||||||
intent.options?.messageId,
|
intent.options?.messageId,
|
||||||
intent.options?.message,
|
intent.options?.message,
|
||||||
intent.options?.sourceChannel,
|
intent.options?.sourceChannel,
|
||||||
|
intent.options?.allowAttachmentDelete,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
case 'close':
|
case 'close':
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class MediaViewer {
|
|||||||
messageId?: string = undefined;
|
messageId?: string = undefined;
|
||||||
message?: Message = undefined;
|
message?: Message = undefined;
|
||||||
sourceChannel?: Channel = undefined;
|
sourceChannel?: Channel = undefined;
|
||||||
|
allowAttachmentDelete: boolean = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable(
|
makeAutoObservable(
|
||||||
@@ -56,6 +57,7 @@ class MediaViewer {
|
|||||||
messageId?: string,
|
messageId?: string,
|
||||||
message?: Message,
|
message?: Message,
|
||||||
sourceChannel?: Channel | null,
|
sourceChannel?: Channel | null,
|
||||||
|
allowAttachmentDelete: boolean = false,
|
||||||
): void {
|
): void {
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
this.items = copyMediaViewerItems(items);
|
this.items = copyMediaViewerItems(items);
|
||||||
@@ -64,6 +66,7 @@ class MediaViewer {
|
|||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.sourceChannel = sourceChannel ?? undefined;
|
this.sourceChannel = sourceChannel ?? undefined;
|
||||||
|
this.allowAttachmentDelete = allowAttachmentDelete;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(): void {
|
close(): void {
|
||||||
@@ -74,6 +77,7 @@ class MediaViewer {
|
|||||||
this.messageId = undefined;
|
this.messageId = undefined;
|
||||||
this.message = undefined;
|
this.message = undefined;
|
||||||
this.sourceChannel = undefined;
|
this.sourceChannel = undefined;
|
||||||
|
this.allowAttachmentDelete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate(index: number): void {
|
navigate(index: number): void {
|
||||||
|
|||||||
Reference in new issue
Block a user