feat(captions): edit image/video captions after sending
Captions could be attached at upload but never changed — canEditEvent only allowed m.text/emote/notice, so a typo in an image caption meant delete + re-upload. Add caption editing for image/video messages. - utils/room.ts: canEditCaption (own image/video RoomMessage, no non-thread relation) + canEditEventOrCaption. canEditEvent unchanged. - Message.tsx: gate the Edit affordance (quick-actions + menu) on canEditEventOrCaption; label it "Edit caption" for media; keep the media rendered above the editor while editing. - MessageEditor.tsx: for a media message, seed the editor from the caption (not the filename), allow an empty caption (removes it), and build the m.replace so m.new_content spreads the original media content (url/info/encrypted file/filename/msgtype) and only sets body + format/formatted_body. Outer content is the full media (not a "* text" fallback) so non-edit-aware clients still render the media. No-op guard when the caption is unchanged. Placeholder "Add a caption…". Rendering + Edit History need no changes: getEditedEvent's m.new_content flows to renderCaption, and the word-diff already diffs body (the caption). Encrypted media keeps its file/key (no re-upload). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -507,6 +507,27 @@ export const canEditEvent = (mx: MatrixClient, mEvent: MatrixEvent) => {
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the current user can edit the *caption* of a media message. Captions
|
||||
* are authored for image/video only (see msgContent.ts): the caption is the
|
||||
* event `body` when it differs from `filename`. Editing only changes the caption
|
||||
* — the media (url/info/file) is preserved.
|
||||
*/
|
||||
export const canEditCaption = (mx: MatrixClient, mEvent: MatrixEvent) => {
|
||||
const content = mEvent.getContent();
|
||||
const relationType = content['m.relates_to']?.rel_type;
|
||||
return (
|
||||
mEvent.getSender() === mx.getUserId() &&
|
||||
(!relationType || relationType === RelationType.Thread) &&
|
||||
mEvent.getType() === MessageEvent.RoomMessage &&
|
||||
(content.msgtype === MsgType.Image || content.msgtype === MsgType.Video)
|
||||
);
|
||||
};
|
||||
|
||||
/** Editable as a text message, or has an editable media caption. */
|
||||
export const canEditEventOrCaption = (mx: MatrixClient, mEvent: MatrixEvent) =>
|
||||
canEditEvent(mx, mEvent) || canEditCaption(mx, mEvent);
|
||||
|
||||
export const getLatestEditableEvt = (
|
||||
timeline: EventTimeline,
|
||||
canEdit: (mEvent: MatrixEvent) => boolean,
|
||||
|
||||
Reference in New Issue
Block a user