Add support for spoilers on images (MSC4193) (#2212)

* Add support for MSC4193: Spoilers on Media

* Clarify variable names and wording

* Restore list atom

* Improve spoilered image UX with autoload off

* Use `aria-pressed` to indicate attachment spoiler state

* Improve spoiler button tooltip wording, keep reveal button from conflicting with load errors
This commit is contained in:
Ginger 2025-02-22 03:55:13 -05:00 committed by GitHub
parent 7c6ab366af
commit dd4c1a94e6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 158 additions and 19 deletions

View file

@ -167,10 +167,24 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
const encryptFiles = fulfilledPromiseSettledResult(
await Promise.allSettled(safeFiles.map((f) => encryptFile(f)))
);
encryptFiles.forEach((ef) => fileItems.push(ef));
encryptFiles.forEach((ef) =>
fileItems.push({
...ef,
metadata: {
markedAsSpoiler: false,
},
})
);
} else {
safeFiles.forEach((f) =>
fileItems.push({ file: f, originalFile: f, encInfo: undefined })
fileItems.push({
file: f,
originalFile: f,
encInfo: undefined,
metadata: {
markedAsSpoiler: false,
},
})
);
}
setSelectedFiles({
@ -420,7 +434,14 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
// eslint-disable-next-line react/no-array-index-key
key={index}
isEncrypted={!!fileItem.encInfo}
uploadAtom={roomUploadAtomFamily(fileItem.file)}
fileItem={fileItem}
setMetadata={(metadata) =>
setSelectedFiles({
type: 'REPLACE',
item: fileItem,
replacement: { ...fileItem, metadata },
})
}
onRemove={handleRemoveUpload}
/>
))}

View file

@ -1,6 +1,10 @@
import { IContent, MatrixClient, MsgType } from 'matrix-js-sdk';
import to from 'await-to-js';
import { IThumbnailContent, MATRIX_BLUR_HASH_PROPERTY_NAME } from '../../../types/matrix/common';
import {
IThumbnailContent,
MATRIX_BLUR_HASH_PROPERTY_NAME,
MATRIX_SPOILER_PROPERTY_NAME,
} from '../../../types/matrix/common';
import {
getImageFileUrl,
getThumbnail,
@ -42,9 +46,9 @@ const generateThumbnailContent = async (
export const getImageMsgContent = async (
mx: MatrixClient,
item: TUploadItem,
mxc: string,
mxc: string
): Promise<IContent> => {
const { file, originalFile, encInfo } = item;
const { file, originalFile, encInfo, metadata } = item;
const [imgError, imgEl] = await to(loadImageElement(getImageFileUrl(originalFile)));
if (imgError) console.warn(imgError);
@ -52,6 +56,7 @@ export const getImageMsgContent = async (
msgtype: MsgType.Image,
filename: file.name,
body: file.name,
[MATRIX_SPOILER_PROPERTY_NAME]: metadata.markedAsSpoiler,
};
if (imgEl) {
const blurHash = encodeBlurHash(imgEl, 512, scaleYDimension(imgEl.width, 512, imgEl.height));
@ -75,7 +80,7 @@ export const getImageMsgContent = async (
export const getVideoMsgContent = async (
mx: MatrixClient,
item: TUploadItem,
mxc: string,
mxc: string
): Promise<IContent> => {
const { file, originalFile, encInfo } = item;