You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/ts/components/conversation/right-panel/overlay/message-info/components/AttachmentCarousel.tsx

142 lines
4.1 KiB
TypeScript

import { isEmpty } from 'lodash';
import { useCallback, useState } from 'react';
import styled, { CSSProperties } from 'styled-components';
import { PropsForAttachment } from '../../../../../../state/ducks/conversations';
import { getAlt, getThumbnailUrl, isVideoAttachment } from '../../../../../../types/Attachment';
import { Flex } from '../../../../../basic/Flex';
import { SessionIconButton } from '../../../../../icon';
import { Image } from '../../../../Image';
import {
StyledSubtitleDotMenu,
SubtitleDotMenu,
} from '../../../../header/ConversationHeaderSubtitle';
import { showLightboxFromAttachmentProps } from '../../../../message/message-content/MessageAttachment';
const CarouselButton = (props: { visible: boolean; rotation: number; onClick: () => void }) => {
return (
<SessionIconButton
iconSize={'huge'}
iconType={'chevron'}
iconRotation={props.rotation}
onClick={props.onClick}
iconPadding={'var(--margins-xs)'}
style={{
visibility: props.visible ? 'visible' : 'hidden',
}}
/>
);
};
const StyledFullscreenButton = styled.div``;
const FullscreenButton = (props: { onClick: () => void; style?: CSSProperties }) => {
return (
<StyledFullscreenButton style={props.style}>
<SessionIconButton
iconSize={'large'}
iconColor={'var(--button-icon-stroke-hover-color)'}
iconType={'fullscreen'}
onClick={props.onClick}
iconPadding={'6px'}
/>
</StyledFullscreenButton>
);
};
const ImageContainer = styled.div`
position: relative;
${StyledSubtitleDotMenu} {
position: absolute;
bottom: 8px;
left: 0;
right: 0;
margin: 0 auto;
z-index: 2;
}
${StyledFullscreenButton} {
position: absolute;
bottom: 8px;
right: 8px;
z-index: 2;
}
`;
type Props = {
messageId: string;
attachments: Array<PropsForAttachment>;
visibleIndex: number;
nextAction: () => void;
previousAction: () => void;
};
export const AttachmentCarousel = (props: Props) => {
const { messageId, attachments, visibleIndex, nextAction, previousAction } = props;
const [imageBroken, setImageBroken] = useState(false);
const handleImageError = useCallback(() => {
setImageBroken(true);
}, [setImageBroken]);
if (isEmpty(attachments)) {
window.log.debug('No attachments to render in carousel');
return null;
}
const isVideo = isVideoAttachment(attachments[visibleIndex]);
const showLightbox = () => {
void showLightboxFromAttachmentProps(messageId, attachments[visibleIndex]);
};
if (imageBroken) {
return null;
}
return (
<Flex container={true} flexDirection={'row'} justifyContent={'center'} alignItems={'center'}>
<CarouselButton visible={visibleIndex > 0} onClick={previousAction} rotation={90} />
<ImageContainer>
<Image
alt={getAlt(attachments[visibleIndex])}
attachment={attachments[visibleIndex]}
playIconOverlay={isVideo}
height={'var(--right-panel-attachment-height)'}
width={'var(--right-panel-attachment-width)'}
url={getThumbnailUrl(attachments[visibleIndex])}
attachmentIndex={visibleIndex}
softCorners={true}
onClick={isVideo ? showLightbox : undefined}
onError={handleImageError}
/>
<SubtitleDotMenu
id={'attachment-carousel-subtitle-dots'}
selectedOptionIndex={visibleIndex}
optionsCount={attachments.length}
style={{
display: attachments.length < 2 ? 'none' : 'undefined',
padding: '6px',
backgroundColor: 'var(--modal-background-color)',
borderRadius: '50px',
width: 'fit-content',
}}
/>
<FullscreenButton
onClick={showLightbox}
style={{
backgroundColor: 'var(--modal-background-color)',
borderRadius: '50px',
}}
/>
</ImageContainer>
<CarouselButton
visible={visibleIndex < attachments.length - 1}
onClick={nextAction}
rotation={270}
/>
</Flex>
);
};