From 6d03cb35b74d35f04d13fdcff073608673f588bc Mon Sep 17 00:00:00 2001 From: grimhilt <107760093+grimhilt@users.noreply.github.com> Date: Mon, 5 Sep 2022 10:04:37 +0000 Subject: [PATCH] Fix voice messages with multiple composers (#9208) * Allow having multiple voice messages in composers Co-authored-by: grimhilt Co-authored-by: Janne Mareike Koschinski --- .../views/rooms/MessageComposer.tsx | 6 ++- .../views/rooms/VoiceRecordComposerTile.tsx | 16 ++++---- src/stores/VoiceRecordingStore.ts | 41 ++++++++++++------- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 4e33fd3022..239969cb82 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -308,7 +308,8 @@ export default class MessageComposer extends React.Component { }; private updateRecordingState() { - this.voiceRecording = VoiceRecordingStore.instance.getActiveRecording(this.props.room.roomId); + const voiceRecordingId = VoiceRecordingStore.getVoiceRecordingId(this.props.room, this.props.relation); + this.voiceRecording = VoiceRecordingStore.instance.getActiveRecording(voiceRecordingId); if (this.voiceRecording) { // If the recording has already started, it's probably a cached one. if (this.voiceRecording.hasRecording && !this.voiceRecording.isRecording) { @@ -323,7 +324,8 @@ export default class MessageComposer extends React.Component { private onRecordingStarted = () => { // update the recording instance, just in case - this.voiceRecording = VoiceRecordingStore.instance.getActiveRecording(this.props.room.roomId); + const voiceRecordingId = VoiceRecordingStore.getVoiceRecordingId(this.props.room, this.props.relation); + this.voiceRecording = VoiceRecordingStore.instance.getActiveRecording(voiceRecordingId); this.setState({ haveRecording: !!this.voiceRecording, }); diff --git a/src/components/views/rooms/VoiceRecordComposerTile.tsx b/src/components/views/rooms/VoiceRecordComposerTile.tsx index 338995c3b9..b25d87a0ce 100644 --- a/src/components/views/rooms/VoiceRecordComposerTile.tsx +++ b/src/components/views/rooms/VoiceRecordComposerTile.tsx @@ -64,6 +64,7 @@ interface IState { export default class VoiceRecordComposerTile extends React.PureComponent { static contextType = RoomContext; public context!: React.ContextType; + private voiceRecordingId: string; public constructor(props: IProps) { super(props); @@ -71,10 +72,12 @@ export default class VoiceRecordComposerTile extends React.PureComponent; + [voiceRecordingId: string]: Optional; } export class VoiceRecordingStore extends AsyncStoreWithClient { @@ -45,48 +50,54 @@ export class VoiceRecordingStore extends AsyncStoreWithClient { return; } + public static getVoiceRecordingId(room: Room, relation?: IEventRelation): string { + if (relation?.rel_type === "io.element.thread" || relation?.rel_type === RelationType.Thread) { + return room.roomId + SEPARATOR + relation.event_id; + } else { + return room.roomId; + } + } + /** * Gets the active recording instance, if any. - * @param {string} roomId The room ID to get the recording in. + * @param {string} voiceRecordingId The room ID (with optionally the thread ID if in one) to get the recording in. * @returns {Optional} The recording, if any. */ - public getActiveRecording(roomId: string): Optional { - return this.state[roomId]; + public getActiveRecording(voiceRecordingId: string): Optional { + return this.state[voiceRecordingId]; } /** * Starts a new recording if one isn't already in progress. Note that this simply * creates a recording instance - whether or not recording is actively in progress * can be seen via the VoiceRecording class. - * @param {string} roomId The room ID to start recording in. + * @param {string} voiceRecordingId The room ID (with optionally the thread ID if in one) to start recording in. * @returns {VoiceRecording} The recording. */ - public startRecording(roomId: string): VoiceRecording { + public startRecording(voiceRecordingId: string): VoiceRecording { if (!this.matrixClient) throw new Error("Cannot start a recording without a MatrixClient"); - if (!roomId) throw new Error("Recording must be associated with a room"); - if (this.state[roomId]) throw new Error("A recording is already in progress"); + if (!voiceRecordingId) throw new Error("Recording must be associated with a room"); + if (this.state[voiceRecordingId]) throw new Error("A recording is already in progress"); const recording = new VoiceRecording(this.matrixClient); // noinspection JSIgnoredPromiseFromCall - we can safely run this async - this.updateState({ ...this.state, [roomId]: recording }); + this.updateState({ ...this.state, [voiceRecordingId]: recording }); return recording; } /** * Disposes of the current recording, no matter the state of it. - * @param {string} roomId The room ID to dispose of the recording in. + * @param {string} voiceRecordingId The room ID (with optionally the thread ID if in one) to dispose of the recording in. * @returns {Promise} Resolves when complete. */ - public disposeRecording(roomId: string): Promise { - if (this.state[roomId]) { - this.state[roomId].destroy(); // stops internally - } + public disposeRecording(voiceRecordingId: string): Promise { + this.state[voiceRecordingId]?.destroy(); // stops internally const { // eslint-disable-next-line @typescript-eslint/no-unused-vars - [roomId]: _toDelete, + [voiceRecordingId]: _toDelete, ...newState } = this.state; // unexpectedly AsyncStore.updateState merges state