Message.tsx: Show expiring metadata when rendering generic attachments

This commit is contained in:
Scott Nonnenberg 2025-07-11 03:29:48 +10:00 committed by GitHub
parent 470cd1624d
commit cf03754d2f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 241 additions and 3 deletions

View file

@ -1408,6 +1408,9 @@ export class Message extends React.PureComponent<Props, State> {
);
};
const willShowMetadata =
expirationLength || expirationTimestamp || !shouldHideMetadata;
// Note: this has to be interactive for the case where text comes along with the
// attachment. But we don't want the user to tab here unless that text exists.
const tabIndex = text ? 0 : -1;
@ -1485,7 +1488,7 @@ export class Message extends React.PureComponent<Props, State> {
{formatFileSize(size)}
</div>
)}
{text || shouldHideMetadata ? undefined : (
{text || !willShowMetadata ? undefined : (
<div className="module-message__simple-attachment__metadata-container">
<MessageMetadata
deletedForEveryone={false}
@ -3266,8 +3269,8 @@ export class Message extends React.PureComponent<Props, State> {
) {
return (
attachments?.length &&
(!isImage(attachments) || imageBroken) &&
(!isVideo(attachments) || imageBroken) &&
(!isImage(attachments) || !canDisplayImage(attachments) || imageBroken) &&
(!isVideo(attachments) || !canDisplayImage(attachments) || imageBroken) &&
!isAudio(attachments)
);
}

View file

@ -1390,6 +1390,226 @@ export function Image(): JSX.Element {
);
}
export function BrokenImage(): JSX.Element {
const darkImageProps = createProps({
attachments: [
fakeAttachment({
url: 'nonexistent.jpg',
fileName: 'tina-rolf-269345-unsplash.jpg',
contentType: IMAGE_JPEG,
width: 128,
height: 128,
}),
],
status: 'sent',
});
const lightImageProps = createProps({
attachments: [
fakeAttachment({
url: 'nonexistent.jpg',
fileName: 'the-sax.png',
contentType: IMAGE_PNG,
height: 240,
width: 320,
}),
],
status: 'sent',
});
return (
<>
{renderBothDirections(darkImageProps)}
{renderBothDirections(lightImageProps)}
</>
);
}
export function BrokenImageWithExpirationTimer(): JSX.Element {
const darkImageProps = createProps({
attachments: [
fakeAttachment({
url: 'nonexistent.jpg',
fileName: 'tina-rolf-269345-unsplash.jpg',
contentType: IMAGE_JPEG,
width: 128,
height: 128,
}),
],
expirationLength: 30 * 1000,
expirationTimestamp: Date.now() + 30 * 1000,
status: 'sent',
});
const lightImageProps = createProps({
attachments: [
fakeAttachment({
url: 'nonexistent.jpg',
fileName: 'the-sax.png',
contentType: IMAGE_PNG,
height: 240,
width: 320,
}),
],
expirationLength: 30 * 1000,
expirationTimestamp: Date.now() + 30 * 1000,
status: 'sent',
});
return (
<>
{renderBothDirections(darkImageProps)}
{renderBothDirections(lightImageProps)}
</>
);
}
export function Video(): JSX.Element {
const darkImageProps = createProps({
attachments: [
fakeAttachment({
url: 'nonexistent.mp4',
screenshot: {
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
size: 100000,
width: 3000,
height: 1680,
contentType: IMAGE_JPEG,
},
fileName: 'tina-rolf-269345-unsplash.jpg',
contentType: VIDEO_MP4,
width: 128,
height: 128,
}),
],
status: 'sent',
});
const lightImageProps = createProps({
attachments: [
fakeAttachment({
url: 'nonexistent.mp4',
screenshot: {
url: pngUrl,
width: 800,
height: 1200,
size: 100000,
contentType: IMAGE_PNG,
},
fileName: 'the-sax.png',
contentType: VIDEO_MP4,
height: 240,
width: 320,
}),
],
status: 'sent',
});
return (
<>
{renderBothDirections(darkImageProps)}
{renderBothDirections(lightImageProps)}
</>
);
}
export function BrokenVideo(): JSX.Element {
const darkImageProps = createProps({
attachments: [
fakeAttachment({
url: 'nonexistent.mp4',
screenshot: {
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
size: 100000,
width: 7680,
height: 3200,
contentType: IMAGE_JPEG,
},
fileName: 'tina-rolf-269345-unsplash.jpg',
contentType: VIDEO_MP4,
height: 3200,
width: 7680,
}),
],
status: 'sent',
});
const lightImageProps = createProps({
attachments: [
fakeAttachment({
url: 'nonexistent.mp4',
screenshot: {
url: pngUrl,
width: 7680,
height: 3200,
size: 100000,
contentType: IMAGE_PNG,
},
fileName: 'the-sax.png',
contentType: VIDEO_MP4,
height: 3200,
width: 7680,
}),
],
status: 'sent',
});
return (
<>
{renderBothDirections(darkImageProps)}
{renderBothDirections(lightImageProps)}
</>
);
}
export function BrokenVideoWithExpirationTimer(): JSX.Element {
const darkImageProps = createProps({
attachments: [
fakeAttachment({
url: 'nonexistent.mp4',
screenshot: {
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
size: 100000,
width: 7680,
height: 3200,
contentType: IMAGE_JPEG,
},
fileName: 'tina-rolf-269345-unsplash.jpg',
contentType: VIDEO_MP4,
height: 3200,
width: 7680,
}),
],
expirationLength: 30 * 1000,
expirationTimestamp: Date.now() + 30 * 1000,
status: 'sent',
});
const lightImageProps = createProps({
attachments: [
fakeAttachment({
url: 'nonexistent.mp4',
screenshot: {
url: pngUrl,
width: 7680,
height: 3200,
size: 100000,
contentType: IMAGE_PNG,
},
fileName: 'the-sax.png',
contentType: VIDEO_MP4,
height: 3200,
width: 7680,
}),
],
expirationLength: 30 * 1000,
expirationTimestamp: Date.now() + 30 * 1000,
status: 'sent',
});
return (
<>
{renderBothDirections(darkImageProps)}
{renderBothDirections(lightImageProps)}
</>
);
}
export const MultipleImages2 = Template.bind({});
MultipleImages2.args = {
attachments: [
@ -1788,6 +2008,21 @@ OtherFileType.args = {
status: 'sent',
};
export const OtherFileTypeWithExpirationTimer = Template.bind({});
OtherFileTypeWithExpirationTimer.args = {
attachments: [
fakeAttachment({
contentType: stringToMIMEType('text/plain'),
fileName: 'things.zip',
url: 'things.zip',
size: 10200000,
}),
],
expirationLength: 30 * 1000,
expirationTimestamp: Date.now() + 30 * 1000,
status: 'sent',
};
export const OtherFileTypeFourChar = Template.bind({});
OtherFileTypeFourChar.args = {
attachments: [