signal-desktop/ts/components/conversation/ImageGrid.tsx

442 lines
13 KiB
TypeScript
Raw Normal View History

2020-10-30 20:34:04 +00:00
// Copyright 2018-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import classNames from 'classnames';
import type { AttachmentType } from '../../types/Attachment';
import {
2019-01-14 21:49:58 +00:00
areAllAttachmentsVisual,
getAlt,
getImageDimensions,
getThumbnailUrl,
getUrl,
isVideoAttachment,
} from '../../types/Attachment';
import { Image, CurveType } from './Image';
2019-01-14 21:49:58 +00:00
import type { LocalizerType, ThemeType } from '../../types/Util';
export type DirectionType = 'incoming' | 'outgoing';
export type Props = {
attachments: Array<AttachmentType>;
bottomOverlay?: boolean;
direction: DirectionType;
isSticker?: boolean;
shouldCollapseAbove?: boolean;
shouldCollapseBelow?: boolean;
stickerSize?: number;
2019-11-07 21:36:16 +00:00
tabIndex?: number;
withContentAbove?: boolean;
withContentBelow?: boolean;
2019-01-14 21:49:58 +00:00
i18n: LocalizerType;
theme?: ThemeType;
onError: () => void;
onClick?: (attachment: AttachmentType) => void;
};
2021-06-24 21:00:11 +00:00
const GAP = 1;
function getCurves({
direction,
shouldCollapseAbove,
shouldCollapseBelow,
withContentAbove,
withContentBelow,
}: {
direction: DirectionType;
shouldCollapseAbove?: boolean;
shouldCollapseBelow?: boolean;
withContentAbove?: boolean;
withContentBelow?: boolean;
}): {
curveTopLeft: CurveType;
curveTopRight: CurveType;
curveBottomLeft: CurveType;
curveBottomRight: CurveType;
} {
let curveTopLeft = CurveType.None;
let curveTopRight = CurveType.None;
let curveBottomLeft = CurveType.None;
let curveBottomRight = CurveType.None;
if (shouldCollapseAbove && direction === 'incoming') {
curveTopLeft = CurveType.Tiny;
curveTopRight = CurveType.Normal;
} else if (shouldCollapseAbove && direction === 'outgoing') {
curveTopLeft = CurveType.Normal;
curveTopRight = CurveType.Tiny;
} else if (!withContentAbove) {
curveTopLeft = CurveType.Normal;
curveTopRight = CurveType.Normal;
}
if (shouldCollapseBelow && direction === 'incoming') {
curveBottomLeft = CurveType.Tiny;
curveBottomRight = CurveType.None;
} else if (shouldCollapseBelow && direction === 'outgoing') {
curveBottomLeft = CurveType.None;
curveBottomRight = CurveType.Tiny;
} else if (!withContentBelow) {
curveBottomLeft = CurveType.Normal;
curveBottomRight = CurveType.Normal;
}
return {
curveTopLeft,
curveTopRight,
curveBottomLeft,
curveBottomRight,
};
}
2020-09-14 19:51:27 +00:00
export const ImageGrid = ({
attachments,
bottomOverlay,
direction,
2020-09-14 19:51:27 +00:00
i18n,
isSticker,
stickerSize,
onError,
onClick,
shouldCollapseAbove,
shouldCollapseBelow,
2020-09-14 19:51:27 +00:00
tabIndex,
theme,
2020-09-14 19:51:27 +00:00
withContentAbove,
withContentBelow,
}: Props): JSX.Element | null => {
const { curveTopLeft, curveTopRight, curveBottomLeft, curveBottomRight } =
getCurves({
direction,
shouldCollapseAbove,
shouldCollapseBelow,
withContentAbove,
withContentBelow,
});
const withBottomOverlay = Boolean(bottomOverlay && !withContentBelow);
2020-09-14 19:51:27 +00:00
if (!attachments || !attachments.length) {
return null;
}
2019-01-14 21:49:58 +00:00
2020-09-14 19:51:27 +00:00
if (attachments.length === 1 || !areAllAttachmentsVisual(attachments)) {
const { height, width } = getImageDimensions(
attachments[0],
isSticker ? stickerSize : undefined
);
2020-09-14 19:51:27 +00:00
return (
<div
className={classNames(
'module-image-grid',
'module-image-grid--one-image',
isSticker ? 'module-image-grid--with-sticker' : null
)}
>
<Image
alt={getAlt(attachments[0], i18n)}
i18n={i18n}
theme={theme}
2020-09-14 19:51:27 +00:00
blurHash={attachments[0].blurHash}
bottomOverlay={withBottomOverlay}
noBorder={isSticker}
noBackground={isSticker}
curveTopLeft={curveTopLeft}
curveTopRight={curveTopRight}
curveBottomLeft={curveBottomLeft}
curveBottomRight={curveBottomRight}
attachment={attachments[0]}
playIconOverlay={isVideoAttachment(attachments[0])}
height={height}
width={width}
url={getUrl(attachments[0])}
tabIndex={tabIndex}
onClick={onClick}
onError={onError}
/>
</div>
);
}
2020-09-14 19:51:27 +00:00
if (attachments.length === 2) {
return (
<div className="module-image-grid">
<Image
alt={getAlt(attachments[0], i18n)}
i18n={i18n}
theme={theme}
2020-09-14 19:51:27 +00:00
attachment={attachments[0]}
blurHash={attachments[0].blurHash}
bottomOverlay={withBottomOverlay}
noBorder={false}
curveTopLeft={curveTopLeft}
curveBottomLeft={curveBottomLeft}
playIconOverlay={isVideoAttachment(attachments[0])}
2021-06-24 21:00:11 +00:00
height={150}
width={150}
cropWidth={GAP}
2020-09-14 19:51:27 +00:00
url={getThumbnailUrl(attachments[0])}
onClick={onClick}
onError={onError}
/>
<Image
alt={getAlt(attachments[1], i18n)}
i18n={i18n}
theme={theme}
2020-09-14 19:51:27 +00:00
blurHash={attachments[1].blurHash}
bottomOverlay={withBottomOverlay}
noBorder={false}
curveTopRight={curveTopRight}
curveBottomRight={curveBottomRight}
playIconOverlay={isVideoAttachment(attachments[1])}
2021-06-24 21:00:11 +00:00
height={150}
width={150}
2020-09-14 19:51:27 +00:00
attachment={attachments[1]}
url={getThumbnailUrl(attachments[1])}
onClick={onClick}
onError={onError}
/>
</div>
);
}
2020-09-14 19:51:27 +00:00
if (attachments.length === 3) {
return (
<div className="module-image-grid">
<Image
alt={getAlt(attachments[0], i18n)}
i18n={i18n}
theme={theme}
2020-09-14 19:51:27 +00:00
blurHash={attachments[0].blurHash}
bottomOverlay={withBottomOverlay}
noBorder={false}
curveTopLeft={curveTopLeft}
curveBottomLeft={curveBottomLeft}
attachment={attachments[0]}
playIconOverlay={isVideoAttachment(attachments[0])}
height={200}
2021-06-24 21:00:11 +00:00
width={200}
cropWidth={GAP}
2020-09-14 19:51:27 +00:00
url={getUrl(attachments[0])}
onClick={onClick}
onError={onError}
/>
<div className="module-image-grid__column">
<Image
alt={getAlt(attachments[1], i18n)}
i18n={i18n}
theme={theme}
2020-05-27 21:37:06 +00:00
blurHash={attachments[1].blurHash}
curveTopRight={curveTopRight}
2021-06-24 21:00:11 +00:00
height={100}
width={100}
cropHeight={GAP}
attachment={attachments[1]}
2020-09-14 19:51:27 +00:00
playIconOverlay={isVideoAttachment(attachments[1])}
url={getThumbnailUrl(attachments[1])}
onClick={onClick}
onError={onError}
/>
<Image
2020-09-14 19:51:27 +00:00
alt={getAlt(attachments[2], i18n)}
i18n={i18n}
theme={theme}
2020-09-14 19:51:27 +00:00
blurHash={attachments[2].blurHash}
2019-01-14 21:49:58 +00:00
bottomOverlay={withBottomOverlay}
2019-11-07 21:36:16 +00:00
noBorder={false}
2020-09-14 19:51:27 +00:00
curveBottomRight={curveBottomRight}
2021-06-24 21:00:11 +00:00
height={100}
width={100}
2020-09-14 19:51:27 +00:00
attachment={attachments[2]}
playIconOverlay={isVideoAttachment(attachments[2])}
url={getThumbnailUrl(attachments[2])}
onClick={onClick}
onError={onError}
/>
</div>
2020-09-14 19:51:27 +00:00
</div>
);
}
2019-01-14 21:49:58 +00:00
2020-09-14 19:51:27 +00:00
if (attachments.length === 4) {
return (
<div className="module-image-grid">
<div className="module-image-grid__column">
<div className="module-image-grid__row">
<Image
alt={getAlt(attachments[0], i18n)}
i18n={i18n}
theme={theme}
2020-05-27 21:37:06 +00:00
blurHash={attachments[0].blurHash}
curveTopLeft={curveTopLeft}
2020-09-14 19:51:27 +00:00
noBorder={false}
attachment={attachments[0]}
playIconOverlay={isVideoAttachment(attachments[0])}
2021-06-24 21:00:11 +00:00
height={150}
width={150}
cropHeight={GAP}
cropWidth={GAP}
url={getThumbnailUrl(attachments[0])}
onClick={onClick}
onError={onError}
/>
<Image
alt={getAlt(attachments[1], i18n)}
i18n={i18n}
theme={theme}
2020-05-27 21:37:06 +00:00
blurHash={attachments[1].blurHash}
curveTopRight={curveTopRight}
playIconOverlay={isVideoAttachment(attachments[1])}
2020-09-14 19:51:27 +00:00
noBorder={false}
2021-06-24 21:00:11 +00:00
height={150}
width={150}
cropHeight={GAP}
attachment={attachments[1]}
url={getThumbnailUrl(attachments[1])}
onClick={onClick}
onError={onError}
/>
</div>
<div className="module-image-grid__row">
<Image
alt={getAlt(attachments[2], i18n)}
i18n={i18n}
theme={theme}
2020-05-27 21:37:06 +00:00
blurHash={attachments[2].blurHash}
2019-01-14 21:49:58 +00:00
bottomOverlay={withBottomOverlay}
2020-09-14 19:51:27 +00:00
noBorder={false}
curveBottomLeft={curveBottomLeft}
playIconOverlay={isVideoAttachment(attachments[2])}
2021-06-24 21:00:11 +00:00
height={150}
width={150}
cropWidth={GAP}
attachment={attachments[2]}
url={getThumbnailUrl(attachments[2])}
onClick={onClick}
onError={onError}
/>
<Image
alt={getAlt(attachments[3], i18n)}
i18n={i18n}
theme={theme}
2020-05-27 21:37:06 +00:00
blurHash={attachments[3].blurHash}
2019-01-14 21:49:58 +00:00
bottomOverlay={withBottomOverlay}
2020-09-14 19:51:27 +00:00
noBorder={false}
curveBottomRight={curveBottomRight}
playIconOverlay={isVideoAttachment(attachments[3])}
2021-06-24 21:00:11 +00:00
height={150}
width={150}
attachment={attachments[3]}
url={getThumbnailUrl(attachments[3])}
onClick={onClick}
onError={onError}
/>
</div>
</div>
</div>
);
}
2020-09-14 19:51:27 +00:00
const moreMessagesOverlay = attachments.length > 5;
const moreMessagesOverlayText = moreMessagesOverlay
? `+${attachments.length - 5}`
: undefined;
return (
<div className="module-image-grid">
<div className="module-image-grid__column">
<div className="module-image-grid__row">
<Image
alt={getAlt(attachments[0], i18n)}
i18n={i18n}
theme={theme}
2020-09-14 19:51:27 +00:00
blurHash={attachments[0].blurHash}
curveTopLeft={curveTopLeft}
attachment={attachments[0]}
playIconOverlay={isVideoAttachment(attachments[0])}
2021-06-24 21:00:11 +00:00
height={150}
width={150}
cropWidth={GAP}
2020-09-14 19:51:27 +00:00
url={getThumbnailUrl(attachments[0])}
onClick={onClick}
onError={onError}
/>
<Image
alt={getAlt(attachments[1], i18n)}
i18n={i18n}
theme={theme}
2020-09-14 19:51:27 +00:00
blurHash={attachments[1].blurHash}
curveTopRight={curveTopRight}
playIconOverlay={isVideoAttachment(attachments[1])}
2021-06-24 21:00:11 +00:00
height={150}
width={150}
2020-09-14 19:51:27 +00:00
attachment={attachments[1]}
url={getThumbnailUrl(attachments[1])}
onClick={onClick}
onError={onError}
/>
</div>
<div className="module-image-grid__row">
<Image
alt={getAlt(attachments[2], i18n)}
i18n={i18n}
theme={theme}
2020-09-14 19:51:27 +00:00
blurHash={attachments[2].blurHash}
bottomOverlay={withBottomOverlay}
noBorder={isSticker}
curveBottomLeft={curveBottomLeft}
playIconOverlay={isVideoAttachment(attachments[2])}
2021-06-24 21:00:11 +00:00
height={100}
width={100}
cropWidth={GAP}
2020-09-14 19:51:27 +00:00
attachment={attachments[2]}
url={getThumbnailUrl(attachments[2])}
onClick={onClick}
onError={onError}
/>
<Image
alt={getAlt(attachments[3], i18n)}
i18n={i18n}
theme={theme}
2020-09-14 19:51:27 +00:00
blurHash={attachments[3].blurHash}
bottomOverlay={withBottomOverlay}
noBorder={isSticker}
playIconOverlay={isVideoAttachment(attachments[3])}
2021-06-24 21:00:11 +00:00
height={100}
width={100}
cropWidth={GAP}
2020-09-14 19:51:27 +00:00
attachment={attachments[3]}
url={getThumbnailUrl(attachments[3])}
onClick={onClick}
onError={onError}
/>
<Image
alt={getAlt(attachments[4], i18n)}
i18n={i18n}
theme={theme}
2020-09-14 19:51:27 +00:00
blurHash={attachments[4].blurHash}
bottomOverlay={withBottomOverlay}
noBorder={isSticker}
curveBottomRight={curveBottomRight}
playIconOverlay={isVideoAttachment(attachments[4])}
2021-06-24 21:00:11 +00:00
height={100}
width={100}
2020-09-14 19:51:27 +00:00
darkOverlay={moreMessagesOverlay}
overlayText={moreMessagesOverlayText}
attachment={attachments[4]}
url={getThumbnailUrl(attachments[4])}
onClick={onClick}
onError={onError}
/>
</div>
</div>
</div>
);
};