message list image context menu

This commit is contained in:
Michael Peters 2021-12-25 19:21:15 -06:00
parent 54536c1b03
commit 916c3b2f24
4 changed files with 37 additions and 20 deletions

View File

@ -1,7 +1,8 @@
import moment from 'moment';
import React, { FC, useCallback, useMemo } from 'react';
import React, { FC, MouseEvent, useCallback, useMemo, useState } from 'react';
import { Member, Message } from '../../../data-types';
import CombinedGuild from '../../../guild-combined';
import ImageContextMenu from '../../context-menus/context-menu-image';
import ImageOverlay from '../../overlays/overlay-image';
import ElementsUtil from '../../require/elements-util';
import GuildSubscriptions from '../../require/guild-subscriptions';
@ -50,16 +51,38 @@ interface PreviewImageElementProps {
const PreviewImageElement: FC<PreviewImageElementProps> = (props: PreviewImageElementProps) => {
const { guild, previewWidth, previewHeight, resourcePreviewId, resourceId, resourceName } = props;
const [ imgSrc ] = GuildSubscriptions.useSoftImageSrcResourceSubscription(guild, resourcePreviewId);
// TODO: Handle resourceError
const [ previewImgSrc, previewResource, previewResourceError ] = GuildSubscriptions.useSoftImageSrcResourceSubscription(guild, resourcePreviewId);
const [ relativeToPos, setRelativeToPos ] = useState<{ x: number, y: number }>({ x: 0, y: 0 });
const [ contextMenu, toggleContextMenu ] = ReactHelper.useContextMenu((close: () => void) => {
if (!previewResource) return null;
return (
<ImageContextMenu
relativeToPos={relativeToPos} close={close}
resourceName={resourceName} resourceBuff={previewResource.data} isPreview={true}
/>
)
}, [ previewResource, relativeToPos, resourceName ]);
const openImageOverlay = useCallback(() => {
// Note: document here isn't 100% guaranteed (I think) but we should be getting rid of this eventually anyway
ElementsUtil.presentReactOverlay(document, <ImageOverlay guild={guild} resourceId={resourceId} resourceName={resourceName} />);
}, [ guild, resourceId, resourceName ]);
const onContextMenu = useCallback((event: MouseEvent<HTMLImageElement>) => {
setRelativeToPos({ x: event.clientX, y: event.clientY });
toggleContextMenu();
}, [ toggleContextMenu ]);
return (
<div className="content image" style={{ width: previewWidth, height: previewHeight }} onClick={openImageOverlay}>
<img src={imgSrc} alt={resourceName}/>
<div className="content image" style={{ width: previewWidth, height: previewHeight }}>
<img
src={previewImgSrc} alt={resourceName}
onClick={openImageOverlay} onContextMenu={onContextMenu}
/>
{contextMenu}
</div>
);
}

View File

@ -24,13 +24,7 @@ const ImageOverlay: FC<ImageOverlayProps> = (props: ImageOverlayProps) => {
// TODO: Handle errors
const rootRef = useRef<HTMLDivElement>(null);
const [ resource, resourceError ] = GuildSubscriptions.useResourceSubscription(guild, resourceId);
// Note: We want this customization here since we need the resource buffer.
const [ resourceImgSrc ] = ReactHelper.useOneTimeAsyncAction(
async () => await ElementsUtil.getImageSrcFromBufferFailSoftly(resource?.data ?? null),
'./img/loading.svg',
[ guild, resource ]
);
const [ imgSrc, resource, resourceError ] = GuildSubscriptions.useSoftImageSrcResourceSubscription(guild, resourceId);
const [ relativeToPos, setRelativeToPos ] = useState<{ x: number, y: number }>({ x: 0, y: 0 });
@ -54,7 +48,7 @@ const ImageOverlay: FC<ImageOverlayProps> = (props: ImageOverlayProps) => {
return (
<Overlay childRootRef={rootRef}>
<div ref={rootRef} className="content popup-image">
<img src={resourceImgSrc} alt={resourceName} title={resourceName} onContextMenu={onContextMenu}></img>
<img src={imgSrc} alt={resourceName} title={resourceName} onContextMenu={onContextMenu}></img>
<div className="download">
<div className="info">
<div className="name">{resourceName}</div>

View File

@ -574,20 +574,20 @@ export default class GuildSubscriptions {
}, fetchResourceFunc);
}
static useSoftImageSrcResourceSubscription(guild: CombinedGuild, resourceId: string | null): [ imgSrc: string ] {
const [ value, fetchError ] = GuildSubscriptions.useResourceSubscription(guild, resourceId);
static useSoftImageSrcResourceSubscription(guild: CombinedGuild, resourceId: string | null): [ imgSrc: string, resource: Resource | null, fetchError: unknown | null ] {
const [ resource, fetchError ] = GuildSubscriptions.useResourceSubscription(guild, resourceId);
const [ imgSrc ] = ReactHelper.useOneTimeAsyncAction(
async () => {
if (fetchError) return './img/error.png';
if (!value) return './img/loading.svg';
return await ElementsUtil.getImageSrcFromBufferFailSoftly(value.data);
if (!resource) return './img/loading.svg';
return await ElementsUtil.getImageSrcFromBufferFailSoftly(resource.data);
},
'./img/loading.svg',
[ value, fetchError ]
[ resource, fetchError ]
);
return [ imgSrc ];
return [ imgSrc, resource, fetchError ];
}
static useChannelsSubscription(guild: CombinedGuild) {

View File

@ -413,7 +413,7 @@ export default class ReactHelper {
}, []);
const contextMenu = useMemo(() => {
return createContextMenu(close);
}, createContextMenuDeps);
}, [ close, ...createContextMenuDeps ]);
const toggle = useCallback(() => {
setIsOpen(oldIsOpen => !!contextMenu && !oldIsOpen);
@ -421,7 +421,7 @@ export default class ReactHelper {
const open = useCallback(() => {
setIsOpen(!!contextMenu);
}, [ contextMenu ]);
return [ isOpen ? contextMenu : null, toggle, close, open, isOpen ];
}
}