From fd509c1fcf72b567be8953f0a6686ece6f7b68b0 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 29 Nov 2022 15:39:38 +0000 Subject: [PATCH 01/13] Upgrade matrix-js-sdk to 22.0.0-rc.1 --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index c3ab6219a7..b2234466fe 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "maplibre-gl": "^1.15.2", "matrix-encrypt-attachment": "^1.0.3", "matrix-events-sdk": "0.0.1", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", + "matrix-js-sdk": "22.0.0-rc.1", "matrix-widget-api": "^1.1.1", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", diff --git a/yarn.lock b/yarn.lock index 4cbb91c6ad..13f0be9c65 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7167,9 +7167,10 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": - version "21.2.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/b318a77ecef179a6fd288cdf32d3ff9c5e8ea989" +matrix-js-sdk@22.0.0-rc.1: + version "22.0.0-rc.1" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-22.0.0-rc.1.tgz#e590b204b39179cd1c48ea6d577f3ac96989a5b7" + integrity sha512-6BLXHle0QIpgccpFE7EQq2IhTnsbhomCx0NZJ9URIY08M2aznvVxM2XfTi+LGjRKhv7yu8TueJaW7sGlsqZ79w== dependencies: "@babel/runtime" "^7.12.5" "@types/sdp-transform" "^2.4.5" From de8e8a33de4bfee763b536e462e3facf4221feb3 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 29 Nov 2022 15:41:18 +0000 Subject: [PATCH 02/13] Prepare changelog for v3.62.0-rc.1 --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca24b8e447..d2e2dce388 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +Changes in [3.62.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.62.0-rc.1) (2022-11-29) +=============================================================================================================== + +## ✨ Features + * Further improve replies ([\#6396](https://github.com/matrix-org/matrix-react-sdk/pull/6396)). Fixes vector-im/element-web#19074, vector-im/element-web#18194 vector-im/element-web#18027 and vector-im/element-web#19179. + * Enable users to join group calls from multiple devices ([\#9625](https://github.com/matrix-org/matrix-react-sdk/pull/9625)). + * fix(visual): make cursor a pointer for summaries ([\#9419](https://github.com/matrix-org/matrix-react-sdk/pull/9419)). Contributed by @r00ster91. + * Add placeholder for rich text editor ([\#9613](https://github.com/matrix-org/matrix-react-sdk/pull/9613)). + * Consolidate public room search experience ([\#9605](https://github.com/matrix-org/matrix-react-sdk/pull/9605)). Fixes vector-im/element-web#22846. + * New password reset flow ([\#9581](https://github.com/matrix-org/matrix-react-sdk/pull/9581)). Fixes vector-im/element-web#23131. + * Device manager - add tooltip to device details toggle ([\#9594](https://github.com/matrix-org/matrix-react-sdk/pull/9594)). + * sliding sync: add lazy-loading member support ([\#9530](https://github.com/matrix-org/matrix-react-sdk/pull/9530)). + * Limit formatting bar offset to top of composer ([\#9365](https://github.com/matrix-org/matrix-react-sdk/pull/9365)). Fixes vector-im/element-web#12359. Contributed by @owi92. + +## 🐛 Bug Fixes + * Fix issues around up arrow event edit shortcut ([\#9645](https://github.com/matrix-org/matrix-react-sdk/pull/9645)). Fixes vector-im/element-web#18497 and vector-im/element-web#18964. + * Fix search not being cleared when clicking on a result ([\#9635](https://github.com/matrix-org/matrix-react-sdk/pull/9635)). Fixes vector-im/element-web#23845. + * Fix screensharing in 1:1 calls ([\#9612](https://github.com/matrix-org/matrix-react-sdk/pull/9612)). Fixes vector-im/element-web#23808. + * Fix the background color flashing when joining a call ([\#9640](https://github.com/matrix-org/matrix-react-sdk/pull/9640)). + * Fix the size of the 'Private space' icon ([\#9638](https://github.com/matrix-org/matrix-react-sdk/pull/9638)). + * Fix reply editing in rich text editor (https ([\#9615](https://github.com/matrix-org/matrix-react-sdk/pull/9615)). + * Fix thread list jumping back down while scrolling ([\#9606](https://github.com/matrix-org/matrix-react-sdk/pull/9606)). Fixes vector-im/element-web#23727. + * Fix regression with TimelinePanel props updates not taking effect ([\#9608](https://github.com/matrix-org/matrix-react-sdk/pull/9608)). Fixes vector-im/element-web#23794. + * Fix form tooltip positioning ([\#9598](https://github.com/matrix-org/matrix-react-sdk/pull/9598)). Fixes vector-im/element-web#22861. + * Extract Search handling from RoomView into its own Component ([\#9574](https://github.com/matrix-org/matrix-react-sdk/pull/9574)). Fixes vector-im/element-web#498. + Changes in [3.61.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.61.0) (2022-11-22) ===================================================================================================== From 1216580bafef8665f6bb65e45c747bb4b3407bae Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 29 Nov 2022 15:41:19 +0000 Subject: [PATCH 03/13] v3.62.0-rc.1 --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index b2234466fe..55302f0183 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.61.0", + "version": "3.62.0-rc.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { @@ -23,7 +23,7 @@ "package.json", ".stylelintrc.js" ], - "main": "./src/index.ts", + "main": "./lib/index.ts", "matrix_src_main": "./src/index.ts", "matrix_lib_main": "./lib/index.ts", "matrix_lib_typings": "./lib/index.d.ts", @@ -257,5 +257,6 @@ "outputDirectory": "coverage", "outputName": "jest-sonar-report.xml", "relativePaths": true - } + }, + "typings": "./lib/index.d.ts" } From f4b6719a2825211cf1e337809714884bd440abcd Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Thu, 1 Dec 2022 20:34:45 +0000 Subject: [PATCH 04/13] [Backport staging] Start voice broadcast recording while listening (#9659) Co-authored-by: Michael Weimann --- .../views/rooms/MessageComposer.tsx | 1 + src/components/views/voip/PipView.tsx | 8 +- .../models/VoiceBroadcastPreRecording.ts | 3 + .../utils/setUpVoiceBroadcastPreRecording.ts | 8 +- .../utils/startNewVoiceBroadcastRecording.ts | 7 ++ test/components/views/voip/PipView-test.tsx | 14 ++++ .../VoiceBroadcastPreRecordingPip-test.tsx | 4 + .../models/VoiceBroadcastPreRecording-test.ts | 6 +- .../VoiceBroadcastPreRecordingStore-test.ts | 7 +- .../setUpVoiceBroadcastPreRecording-test.ts | 42 +++++++++-- .../startNewVoiceBroadcastRecording-test.ts | 75 ++++++++++++------- 11 files changed, 135 insertions(+), 40 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 152c592a02..6fe5923a29 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -584,6 +584,7 @@ export class MessageComposer extends React.Component { setUpVoiceBroadcastPreRecording( this.props.room, MatrixClientPeg.get(), + SdkContextClass.instance.voiceBroadcastPlaybacksStore, VoiceBroadcastRecordingsStore.instance(), SdkContextClass.instance.voiceBroadcastPreRecordingStore, ); diff --git a/src/components/views/voip/PipView.tsx b/src/components/views/voip/PipView.tsx index 27f7798f11..40a59710d4 100644 --- a/src/components/views/voip/PipView.tsx +++ b/src/components/views/voip/PipView.tsx @@ -367,14 +367,14 @@ class PipView extends React.Component { const pipMode = true; let pipContent: CreatePipChildren | null = null; - if (this.props.voiceBroadcastPreRecording) { - pipContent = this.createVoiceBroadcastPreRecordingPipContent(this.props.voiceBroadcastPreRecording); - } - if (this.props.voiceBroadcastPlayback) { pipContent = this.createVoiceBroadcastPlaybackPipContent(this.props.voiceBroadcastPlayback); } + if (this.props.voiceBroadcastPreRecording) { + pipContent = this.createVoiceBroadcastPreRecordingPipContent(this.props.voiceBroadcastPreRecording); + } + if (this.props.voiceBroadcastRecording) { pipContent = this.createVoiceBroadcastRecordingPipContent(this.props.voiceBroadcastRecording); } diff --git a/src/voice-broadcast/models/VoiceBroadcastPreRecording.ts b/src/voice-broadcast/models/VoiceBroadcastPreRecording.ts index f1e956c600..10995e5d49 100644 --- a/src/voice-broadcast/models/VoiceBroadcastPreRecording.ts +++ b/src/voice-broadcast/models/VoiceBroadcastPreRecording.ts @@ -18,6 +18,7 @@ import { MatrixClient, Room, RoomMember } from "matrix-js-sdk/src/matrix"; import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter"; import { IDestroyable } from "../../utils/IDestroyable"; +import { VoiceBroadcastPlaybacksStore } from "../stores/VoiceBroadcastPlaybacksStore"; import { VoiceBroadcastRecordingsStore } from "../stores/VoiceBroadcastRecordingsStore"; import { startNewVoiceBroadcastRecording } from "../utils/startNewVoiceBroadcastRecording"; @@ -34,6 +35,7 @@ export class VoiceBroadcastPreRecording public room: Room, public sender: RoomMember, private client: MatrixClient, + private playbacksStore: VoiceBroadcastPlaybacksStore, private recordingsStore: VoiceBroadcastRecordingsStore, ) { super(); @@ -43,6 +45,7 @@ export class VoiceBroadcastPreRecording await startNewVoiceBroadcastRecording( this.room, this.client, + this.playbacksStore, this.recordingsStore, ); this.emit("dismiss", this); diff --git a/src/voice-broadcast/utils/setUpVoiceBroadcastPreRecording.ts b/src/voice-broadcast/utils/setUpVoiceBroadcastPreRecording.ts index 8bd211f612..9d5d410aa2 100644 --- a/src/voice-broadcast/utils/setUpVoiceBroadcastPreRecording.ts +++ b/src/voice-broadcast/utils/setUpVoiceBroadcastPreRecording.ts @@ -18,6 +18,7 @@ import { MatrixClient, Room } from "matrix-js-sdk/src/matrix"; import { checkVoiceBroadcastPreConditions, + VoiceBroadcastPlaybacksStore, VoiceBroadcastPreRecording, VoiceBroadcastPreRecordingStore, VoiceBroadcastRecordingsStore, @@ -26,6 +27,7 @@ import { export const setUpVoiceBroadcastPreRecording = ( room: Room, client: MatrixClient, + playbacksStore: VoiceBroadcastPlaybacksStore, recordingsStore: VoiceBroadcastRecordingsStore, preRecordingStore: VoiceBroadcastPreRecordingStore, ): VoiceBroadcastPreRecording | null => { @@ -39,7 +41,11 @@ export const setUpVoiceBroadcastPreRecording = ( const sender = room.getMember(userId); if (!sender) return null; - const preRecording = new VoiceBroadcastPreRecording(room, sender, client, recordingsStore); + // pause and clear current playback (if any) + playbacksStore.getCurrent()?.pause(); + playbacksStore.clearCurrent(); + + const preRecording = new VoiceBroadcastPreRecording(room, sender, client, playbacksStore, recordingsStore); preRecordingStore.setCurrent(preRecording); return preRecording; }; diff --git a/src/voice-broadcast/utils/startNewVoiceBroadcastRecording.ts b/src/voice-broadcast/utils/startNewVoiceBroadcastRecording.ts index ae4e40c4a3..5306a9d605 100644 --- a/src/voice-broadcast/utils/startNewVoiceBroadcastRecording.ts +++ b/src/voice-broadcast/utils/startNewVoiceBroadcastRecording.ts @@ -24,6 +24,7 @@ import { VoiceBroadcastRecordingsStore, VoiceBroadcastRecording, getChunkLength, + VoiceBroadcastPlaybacksStore, } from ".."; import { checkVoiceBroadcastPreConditions } from "./checkVoiceBroadcastPreConditions"; @@ -80,17 +81,23 @@ const startBroadcast = async ( /** * Starts a new Voice Broadcast Recording, if * - the user has the permissions to do so in the room + * - the user is not already recording a voice broadcast * - there is no other broadcast being recorded in the room, yet * Sends a voice_broadcast_info state event and waits for the event to actually appear in the room state. */ export const startNewVoiceBroadcastRecording = async ( room: Room, client: MatrixClient, + playbacksStore: VoiceBroadcastPlaybacksStore, recordingsStore: VoiceBroadcastRecordingsStore, ): Promise => { if (!checkVoiceBroadcastPreConditions(room, client, recordingsStore)) { return null; } + // pause and clear current playback (if any) + playbacksStore.getCurrent()?.pause(); + playbacksStore.clearCurrent(); + return startBroadcast(room, client, recordingsStore); }; diff --git a/test/components/views/voip/PipView-test.tsx b/test/components/views/voip/PipView-test.tsx index 1dcc617e64..6a9105a413 100644 --- a/test/components/views/voip/PipView-test.tsx +++ b/test/components/views/voip/PipView-test.tsx @@ -184,6 +184,7 @@ describe("PipView", () => { room, alice, client, + voiceBroadcastPlaybacksStore, voiceBroadcastRecordingsStore, ); voiceBroadcastPreRecordingStore.setCurrent(voiceBroadcastPreRecording); @@ -271,6 +272,19 @@ describe("PipView", () => { }); }); + describe("when there is a voice broadcast playback and pre-recording", () => { + beforeEach(() => { + startVoiceBroadcastPlayback(room); + setUpVoiceBroadcastPreRecording(); + renderPip(); + }); + + it("should render the voice broadcast pre-recording PiP", () => { + // check for the „Go live“ button + expect(screen.queryByText("Go live")).toBeInTheDocument(); + }); + }); + describe("when there is a voice broadcast pre-recording", () => { beforeEach(() => { setUpVoiceBroadcastPreRecording(); diff --git a/test/voice-broadcast/components/molecules/VoiceBroadcastPreRecordingPip-test.tsx b/test/voice-broadcast/components/molecules/VoiceBroadcastPreRecordingPip-test.tsx index 91658f26ed..61636ce000 100644 --- a/test/voice-broadcast/components/molecules/VoiceBroadcastPreRecordingPip-test.tsx +++ b/test/voice-broadcast/components/molecules/VoiceBroadcastPreRecordingPip-test.tsx @@ -21,6 +21,7 @@ import { act, render, RenderResult, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { + VoiceBroadcastPlaybacksStore, VoiceBroadcastPreRecording, VoiceBroadcastPreRecordingPip, VoiceBroadcastRecordingsStore, @@ -42,6 +43,7 @@ jest.mock("../../../../src/components/views/avatars/RoomAvatar", () => ({ describe("VoiceBroadcastPreRecordingPip", () => { let renderResult: RenderResult; let preRecording: VoiceBroadcastPreRecording; + let playbacksStore: VoiceBroadcastPlaybacksStore; let recordingsStore: VoiceBroadcastRecordingsStore; let client: MatrixClient; let room: Room; @@ -51,6 +53,7 @@ describe("VoiceBroadcastPreRecordingPip", () => { client = stubClient(); room = new Room("!room@example.com", client, client.getUserId() || ""); sender = new RoomMember(room.roomId, client.getUserId() || ""); + playbacksStore = new VoiceBroadcastPlaybacksStore(); recordingsStore = new VoiceBroadcastRecordingsStore(); mocked(requestMediaPermissions).mockReturnValue(new Promise((r) => { r({ @@ -76,6 +79,7 @@ describe("VoiceBroadcastPreRecordingPip", () => { room, sender, client, + playbacksStore, recordingsStore, ); }); diff --git a/test/voice-broadcast/models/VoiceBroadcastPreRecording-test.ts b/test/voice-broadcast/models/VoiceBroadcastPreRecording-test.ts index 3a9fc11065..2c2db30b38 100644 --- a/test/voice-broadcast/models/VoiceBroadcastPreRecording-test.ts +++ b/test/voice-broadcast/models/VoiceBroadcastPreRecording-test.ts @@ -18,6 +18,7 @@ import { MatrixClient, Room, RoomMember } from "matrix-js-sdk/src/matrix"; import { startNewVoiceBroadcastRecording, + VoiceBroadcastPlaybacksStore, VoiceBroadcastPreRecording, VoiceBroadcastRecordingsStore, } from "../../../src/voice-broadcast"; @@ -30,6 +31,7 @@ describe("VoiceBroadcastPreRecording", () => { let client: MatrixClient; let room: Room; let sender: RoomMember; + let playbacksStore: VoiceBroadcastPlaybacksStore; let recordingsStore: VoiceBroadcastRecordingsStore; let preRecording: VoiceBroadcastPreRecording; let onDismiss: (voiceBroadcastPreRecording: VoiceBroadcastPreRecording) => void; @@ -38,12 +40,13 @@ describe("VoiceBroadcastPreRecording", () => { client = stubClient(); room = new Room(roomId, client, client.getUserId() || ""); sender = new RoomMember(roomId, client.getUserId() || ""); + playbacksStore = new VoiceBroadcastPlaybacksStore(); recordingsStore = new VoiceBroadcastRecordingsStore(); }); beforeEach(() => { onDismiss = jest.fn(); - preRecording = new VoiceBroadcastPreRecording(room, sender, client, recordingsStore); + preRecording = new VoiceBroadcastPreRecording(room, sender, client, playbacksStore, recordingsStore); preRecording.on("dismiss", onDismiss); }); @@ -56,6 +59,7 @@ describe("VoiceBroadcastPreRecording", () => { expect(startNewVoiceBroadcastRecording).toHaveBeenCalledWith( room, client, + playbacksStore, recordingsStore, ); }); diff --git a/test/voice-broadcast/stores/VoiceBroadcastPreRecordingStore-test.ts b/test/voice-broadcast/stores/VoiceBroadcastPreRecordingStore-test.ts index 36983ae601..97e944b564 100644 --- a/test/voice-broadcast/stores/VoiceBroadcastPreRecordingStore-test.ts +++ b/test/voice-broadcast/stores/VoiceBroadcastPreRecordingStore-test.ts @@ -18,6 +18,7 @@ import { mocked } from "jest-mock"; import { MatrixClient, Room, RoomMember } from "matrix-js-sdk/src/matrix"; import { + VoiceBroadcastPlaybacksStore, VoiceBroadcastPreRecording, VoiceBroadcastPreRecordingStore, VoiceBroadcastRecordingsStore, @@ -31,6 +32,7 @@ describe("VoiceBroadcastPreRecordingStore", () => { let client: MatrixClient; let room: Room; let sender: RoomMember; + let playbacksStore: VoiceBroadcastPlaybacksStore; let recordingsStore: VoiceBroadcastRecordingsStore; let store: VoiceBroadcastPreRecordingStore; let preRecording1: VoiceBroadcastPreRecording; @@ -39,6 +41,7 @@ describe("VoiceBroadcastPreRecordingStore", () => { client = stubClient(); room = new Room(roomId, client, client.getUserId() || ""); sender = new RoomMember(roomId, client.getUserId() || ""); + playbacksStore = new VoiceBroadcastPlaybacksStore(); recordingsStore = new VoiceBroadcastRecordingsStore(); }); @@ -46,7 +49,7 @@ describe("VoiceBroadcastPreRecordingStore", () => { store = new VoiceBroadcastPreRecordingStore(); jest.spyOn(store, "emit"); jest.spyOn(store, "removeAllListeners"); - preRecording1 = new VoiceBroadcastPreRecording(room, sender, client, recordingsStore); + preRecording1 = new VoiceBroadcastPreRecording(room, sender, client, playbacksStore, recordingsStore); jest.spyOn(preRecording1, "off"); }); @@ -117,7 +120,7 @@ describe("VoiceBroadcastPreRecordingStore", () => { beforeEach(() => { mocked(store.emit).mockClear(); mocked(preRecording1.off).mockClear(); - preRecording2 = new VoiceBroadcastPreRecording(room, sender, client, recordingsStore); + preRecording2 = new VoiceBroadcastPreRecording(room, sender, client, playbacksStore, recordingsStore); store.setCurrent(preRecording2); }); diff --git a/test/voice-broadcast/utils/setUpVoiceBroadcastPreRecording-test.ts b/test/voice-broadcast/utils/setUpVoiceBroadcastPreRecording-test.ts index 0b05d26912..4779813165 100644 --- a/test/voice-broadcast/utils/setUpVoiceBroadcastPreRecording-test.ts +++ b/test/voice-broadcast/utils/setUpVoiceBroadcastPreRecording-test.ts @@ -15,16 +15,20 @@ limitations under the License. */ import { mocked } from "jest-mock"; -import { MatrixClient, Room } from "matrix-js-sdk/src/matrix"; +import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; import { checkVoiceBroadcastPreConditions, + VoiceBroadcastInfoState, + VoiceBroadcastPlayback, + VoiceBroadcastPlaybacksStore, VoiceBroadcastPreRecording, VoiceBroadcastPreRecordingStore, VoiceBroadcastRecordingsStore, } from "../../../src/voice-broadcast"; import { setUpVoiceBroadcastPreRecording } from "../../../src/voice-broadcast/utils/setUpVoiceBroadcastPreRecording"; import { mkRoomMemberJoinEvent, stubClient } from "../../test-utils"; +import { mkVoiceBroadcastInfoStateEvent } from "./test-utils"; jest.mock("../../../src/voice-broadcast/utils/checkVoiceBroadcastPreConditions"); @@ -34,11 +38,20 @@ describe("setUpVoiceBroadcastPreRecording", () => { let userId: string; let room: Room; let preRecordingStore: VoiceBroadcastPreRecordingStore; + let infoEvent: MatrixEvent; + let playback: VoiceBroadcastPlayback; + let playbacksStore: VoiceBroadcastPlaybacksStore; let recordingsStore: VoiceBroadcastRecordingsStore; const itShouldReturnNull = () => { it("should return null", () => { - expect(setUpVoiceBroadcastPreRecording(room, client, recordingsStore, preRecordingStore)).toBeNull(); + expect(setUpVoiceBroadcastPreRecording( + room, + client, + playbacksStore, + recordingsStore, + preRecordingStore, + )).toBeNull(); expect(checkVoiceBroadcastPreConditions).toHaveBeenCalledWith(room, client, recordingsStore); }); }; @@ -51,7 +64,16 @@ describe("setUpVoiceBroadcastPreRecording", () => { userId = clientUserId; room = new Room(roomId, client, userId); + infoEvent = mkVoiceBroadcastInfoStateEvent( + roomId, + VoiceBroadcastInfoState.Started, + client.getUserId()!, + client.getDeviceId()!, + ); preRecordingStore = new VoiceBroadcastPreRecordingStore(); + playback = new VoiceBroadcastPlayback(infoEvent, client); + jest.spyOn(playback, "pause"); + playbacksStore = new VoiceBroadcastPlaybacksStore(); recordingsStore = new VoiceBroadcastRecordingsStore(); }); @@ -85,15 +107,25 @@ describe("setUpVoiceBroadcastPreRecording", () => { itShouldReturnNull(); }); - describe("and there is a room member", () => { + describe("and there is a room member and listening to another broadcast", () => { beforeEach(() => { + playbacksStore.setCurrent(playback); room.currentState.setStateEvents([ mkRoomMemberJoinEvent(userId, roomId), ]); }); - it("should create a voice broadcast pre-recording", () => { - const result = setUpVoiceBroadcastPreRecording(room, client, recordingsStore, preRecordingStore); + it("should pause the current playback and create a voice broadcast pre-recording", () => { + const result = setUpVoiceBroadcastPreRecording( + room, + client, + playbacksStore, + recordingsStore, + preRecordingStore, + ); + expect(playback.pause).toHaveBeenCalled(); + expect(playbacksStore.getCurrent()).toBeNull(); + expect(checkVoiceBroadcastPreConditions).toHaveBeenCalledWith(room, client, recordingsStore); expect(result).toBeInstanceOf(VoiceBroadcastPreRecording); }); diff --git a/test/voice-broadcast/utils/startNewVoiceBroadcastRecording-test.ts b/test/voice-broadcast/utils/startNewVoiceBroadcastRecording-test.ts index 1873a4b513..448a18a746 100644 --- a/test/voice-broadcast/utils/startNewVoiceBroadcastRecording-test.ts +++ b/test/voice-broadcast/utils/startNewVoiceBroadcastRecording-test.ts @@ -15,7 +15,7 @@ limitations under the License. */ import { mocked } from "jest-mock"; -import { EventType, MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; +import { EventType, ISendEventResponse, MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; import Modal from "../../../src/Modal"; import { @@ -24,6 +24,8 @@ import { VoiceBroadcastInfoState, VoiceBroadcastRecordingsStore, VoiceBroadcastRecording, + VoiceBroadcastPlaybacksStore, + VoiceBroadcastPlayback, } from "../../../src/voice-broadcast"; import { mkEvent, stubClient } from "../../test-utils"; import { mkVoiceBroadcastInfoStateEvent } from "./test-utils"; @@ -38,6 +40,7 @@ describe("startNewVoiceBroadcastRecording", () => { const roomId = "!room:example.com"; const otherUserId = "@other:example.com"; let client: MatrixClient; + let playbacksStore: VoiceBroadcastPlaybacksStore; let recordingsStore: VoiceBroadcastRecordingsStore; let room: Room; let infoEvent: MatrixEvent; @@ -46,45 +49,50 @@ describe("startNewVoiceBroadcastRecording", () => { beforeEach(() => { client = stubClient(); - room = new Room(roomId, client, client.getUserId()); + room = new Room(roomId, client, client.getUserId()!); jest.spyOn(room.currentState, "maySendStateEvent"); mocked(client.getRoom).mockImplementation((getRoomId: string) => { if (getRoomId === roomId) { return room; } + + return null; }); mocked(client.sendStateEvent).mockImplementation(( sendRoomId: string, eventType: string, - _content: any, - _stateKey: string, - ) => { + content: any, + stateKey: string, + ): Promise => { if (sendRoomId === roomId && eventType === VoiceBroadcastInfoEventType) { - return Promise.resolve({ event_id: infoEvent.getId() }); + return Promise.resolve({ event_id: infoEvent.getId()! }); } - }); - recordingsStore = { - setCurrent: jest.fn(), - getCurrent: jest.fn(), - } as unknown as VoiceBroadcastRecordingsStore; + throw new Error("Unexpected sendStateEvent call"); + }); infoEvent = mkVoiceBroadcastInfoStateEvent( roomId, VoiceBroadcastInfoState.Started, - client.getUserId(), - client.getDeviceId(), + client.getUserId()!, + client.getDeviceId()!, ); otherEvent = mkEvent({ event: true, type: EventType.RoomMember, content: {}, - user: client.getUserId(), + user: client.getUserId()!, room: roomId, skey: "", }); + playbacksStore = new VoiceBroadcastPlaybacksStore(); + recordingsStore = { + setCurrent: jest.fn(), + getCurrent: jest.fn(), + } as unknown as VoiceBroadcastRecordingsStore; + mocked(VoiceBroadcastRecording).mockImplementation(( infoEvent: MatrixEvent, client: MatrixClient, @@ -106,22 +114,35 @@ describe("startNewVoiceBroadcastRecording", () => { mocked(room.currentState.maySendStateEvent).mockReturnValue(true); }); - describe("when there currently is no other broadcast", () => { - it("should create a new Voice Broadcast", async () => { + describe("when currently listening to a broadcast and there is no recording", () => { + let playback: VoiceBroadcastPlayback; + + beforeEach(() => { + playback = new VoiceBroadcastPlayback(infoEvent, client); + jest.spyOn(playback, "pause"); + playbacksStore.setCurrent(playback); + }); + + it("should stop listen to the current broadcast and create a new recording", async () => { mocked(client.sendStateEvent).mockImplementation(async ( _roomId: string, _eventType: string, _content: any, _stateKey = "", - ) => { + ): Promise => { setTimeout(() => { // emit state events after resolving the promise room.currentState.setStateEvents([otherEvent]); room.currentState.setStateEvents([infoEvent]); }, 0); - return { event_id: infoEvent.getId() }; + return { event_id: infoEvent.getId()! }; }); - const recording = await startNewVoiceBroadcastRecording(room, client, recordingsStore); + const recording = await startNewVoiceBroadcastRecording(room, client, playbacksStore, recordingsStore); + expect(recording).not.toBeNull(); + + // expect to stop and clear the current playback + expect(playback.pause).toHaveBeenCalled(); + expect(playbacksStore.getCurrent()).toBeNull(); expect(client.sendStateEvent).toHaveBeenCalledWith( roomId, @@ -133,8 +154,8 @@ describe("startNewVoiceBroadcastRecording", () => { }, client.getUserId(), ); - expect(recording.infoEvent).toBe(infoEvent); - expect(recording.start).toHaveBeenCalled(); + expect(recording!.infoEvent).toBe(infoEvent); + expect(recording!.start).toHaveBeenCalled(); }); }); @@ -144,7 +165,7 @@ describe("startNewVoiceBroadcastRecording", () => { new VoiceBroadcastRecording(infoEvent, client), ); - result = await startNewVoiceBroadcastRecording(room, client, recordingsStore); + result = await startNewVoiceBroadcastRecording(room, client, playbacksStore, recordingsStore); }); it("should not start a voice broadcast", () => { @@ -162,12 +183,12 @@ describe("startNewVoiceBroadcastRecording", () => { mkVoiceBroadcastInfoStateEvent( roomId, VoiceBroadcastInfoState.Resumed, - client.getUserId(), - client.getDeviceId(), + client.getUserId()!, + client.getDeviceId()!, ), ]); - result = await startNewVoiceBroadcastRecording(room, client, recordingsStore); + result = await startNewVoiceBroadcastRecording(room, client, playbacksStore, recordingsStore); }); it("should not start a voice broadcast", () => { @@ -190,7 +211,7 @@ describe("startNewVoiceBroadcastRecording", () => { ), ]); - result = await startNewVoiceBroadcastRecording(room, client, recordingsStore); + result = await startNewVoiceBroadcastRecording(room, client, playbacksStore, recordingsStore); }); it("should not start a voice broadcast", () => { @@ -206,7 +227,7 @@ describe("startNewVoiceBroadcastRecording", () => { describe("when the current user is not allowed to send voice broadcast info state events", () => { beforeEach(async () => { mocked(room.currentState.maySendStateEvent).mockReturnValue(false); - result = await startNewVoiceBroadcastRecording(room, client, recordingsStore); + result = await startNewVoiceBroadcastRecording(room, client, playbacksStore, recordingsStore); }); it("should not start a voice broadcast", () => { From fcc49d09592c7023255bc8d52b8c68f4d489cf62 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Thu, 1 Dec 2022 20:34:57 +0000 Subject: [PATCH 05/13] [Backport staging] Update Voice Broadcast buffering style (#9660) Co-authored-by: Michael Weimann --- .../atoms/_VoiceBroadcastHeader.pcss | 5 +- src/i18n/strings/en_EN.json | 1 + .../components/atoms/VoiceBroadcastHeader.tsx | 41 +++++++----- .../molecules/VoiceBroadcastPlaybackBody.tsx | 61 ++++++++--------- .../hooks/useVoiceBroadcastPlayback.ts | 7 ++ .../atoms/VoiceBroadcastHeader-test.tsx | 17 ++++- .../VoiceBroadcastHeader-test.tsx.snap | 66 +++++++++++++++++++ .../VoiceBroadcastPlaybackBody-test.tsx.snap | 25 ++++--- 8 files changed, 163 insertions(+), 60 deletions(-) diff --git a/res/css/voice-broadcast/atoms/_VoiceBroadcastHeader.pcss b/res/css/voice-broadcast/atoms/_VoiceBroadcastHeader.pcss index 1ff29bd985..90092a35ac 100644 --- a/res/css/voice-broadcast/atoms/_VoiceBroadcastHeader.pcss +++ b/res/css/voice-broadcast/atoms/_VoiceBroadcastHeader.pcss @@ -40,8 +40,9 @@ limitations under the License. display: flex; gap: $spacing-4; - i { - flex-shrink: 0; + .mx_Spinner { + flex: 0 0 14px; + padding: 1px; } span { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 376133905d..9922fa0413 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -657,6 +657,7 @@ "Change input device": "Change input device", "Live": "Live", "Voice broadcast": "Voice broadcast", + "Buffering…": "Buffering…", "Cannot reach homeserver": "Cannot reach homeserver", "Ensure you have a stable internet connection, or get in touch with the server admin": "Ensure you have a stable internet connection, or get in touch with the server admin", "Your %(brand)s is misconfigured": "Your %(brand)s is misconfigured", diff --git a/src/voice-broadcast/components/atoms/VoiceBroadcastHeader.tsx b/src/voice-broadcast/components/atoms/VoiceBroadcastHeader.tsx index be31cd4efe..64640ca793 100644 --- a/src/voice-broadcast/components/atoms/VoiceBroadcastHeader.tsx +++ b/src/voice-broadcast/components/atoms/VoiceBroadcastHeader.tsx @@ -25,6 +25,7 @@ import AccessibleButton from "../../../components/views/elements/AccessibleButto import { Icon as XIcon } from "../../../../res/img/element-icons/cancel-rounded.svg"; import Clock from "../../../components/views/audio_messages/Clock"; import { formatTimeLeft } from "../../../DateUtils"; +import Spinner from "../../../components/views/elements/Spinner"; interface VoiceBroadcastHeaderProps { live?: VoiceBroadcastLiveness; @@ -33,6 +34,7 @@ interface VoiceBroadcastHeaderProps { room: Room; microphoneLabel?: string; showBroadcast?: boolean; + showBuffering?: boolean; timeLeft?: number; showClose?: boolean; } @@ -44,47 +46,55 @@ export const VoiceBroadcastHeader: React.FC = ({ room, microphoneLabel, showBroadcast = false, + showBuffering = false, showClose = false, timeLeft, }) => { - const broadcast = showBroadcast - ?
+ const broadcast = showBroadcast && ( +
{ _t("Voice broadcast") }
- : null; + ); - const liveBadge = live === "not-live" - ? null - : ; + const liveBadge = live !== "not-live" && ( + + ); - const closeButton = showClose - ? + const closeButton = showClose && ( + - : null; + ); - const timeLeftLine = timeLeft - ?
+ const timeLeftLine = timeLeft && ( +
- : null; + ); + + const buffering = showBuffering && ( +
+ + { _t("Buffering…") } +
+ ); const microphoneLineClasses = classNames({ mx_VoiceBroadcastHeader_line: true, ["mx_VoiceBroadcastHeader_mic--clickable"]: onMicrophoneLineClick, }); - const microphoneLine = microphoneLabel - ?
{ microphoneLabel }
- : null; + ); return
@@ -95,6 +105,7 @@ export const VoiceBroadcastHeader: React.FC = ({ { microphoneLine } { timeLeftLine } { broadcast } + { buffering }
{ liveBadge } { closeButton } diff --git a/src/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody.tsx b/src/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody.tsx index 6c16223388..1601fbb363 100644 --- a/src/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody.tsx +++ b/src/voice-broadcast/components/molecules/VoiceBroadcastPlaybackBody.tsx @@ -23,7 +23,6 @@ import { VoiceBroadcastPlayback, VoiceBroadcastPlaybackState, } from "../.."; -import Spinner from "../../../components/views/elements/Spinner"; import { useVoiceBroadcastPlayback } from "../../hooks/useVoiceBroadcastPlayback"; import { Icon as PlayIcon } from "../../../../res/img/element-icons/play.svg"; import { Icon as PauseIcon } from "../../../../res/img/element-icons/pause.svg"; @@ -55,40 +54,35 @@ export const VoiceBroadcastPlaybackBody: React.FC>; + let controlLabel: string; + let className = ""; - if (playbackState === VoiceBroadcastPlaybackState.Buffering) { - control = ; - } else { - let controlIcon: React.FC>; - let controlLabel: string; - let className = ""; - - switch (playbackState) { - case VoiceBroadcastPlaybackState.Stopped: - controlIcon = PlayIcon; - className = "mx_VoiceBroadcastControl-play"; - controlLabel = _t("play voice broadcast"); - break; - case VoiceBroadcastPlaybackState.Paused: - controlIcon = PlayIcon; - className = "mx_VoiceBroadcastControl-play"; - controlLabel = _t("resume voice broadcast"); - break; - case VoiceBroadcastPlaybackState.Playing: - controlIcon = PauseIcon; - controlLabel = _t("pause voice broadcast"); - break; - } - - control = ; + switch (playbackState) { + case VoiceBroadcastPlaybackState.Stopped: + controlIcon = PlayIcon; + className = "mx_VoiceBroadcastControl-play"; + controlLabel = _t("play voice broadcast"); + break; + case VoiceBroadcastPlaybackState.Paused: + controlIcon = PlayIcon; + className = "mx_VoiceBroadcastControl-play"; + controlLabel = _t("resume voice broadcast"); + break; + case VoiceBroadcastPlaybackState.Buffering: + case VoiceBroadcastPlaybackState.Playing: + controlIcon = PauseIcon; + controlLabel = _t("pause voice broadcast"); + break; } + const control = ; + let seekBackwardButton: ReactElement | null = null; let seekForwardButton: ReactElement | null = null; @@ -125,7 +119,8 @@ export const VoiceBroadcastPlaybackBody: React.FC
{ seekBackwardButton } diff --git a/src/voice-broadcast/hooks/useVoiceBroadcastPlayback.ts b/src/voice-broadcast/hooks/useVoiceBroadcastPlayback.ts index 1828b31d01..fb27abfab9 100644 --- a/src/voice-broadcast/hooks/useVoiceBroadcastPlayback.ts +++ b/src/voice-broadcast/hooks/useVoiceBroadcastPlayback.ts @@ -27,6 +27,13 @@ import { export const useVoiceBroadcastPlayback = (playback: VoiceBroadcastPlayback) => { const client = MatrixClientPeg.get(); const room = client.getRoom(playback.infoEvent.getRoomId()); + + if (!room) { + throw new Error( + `Voice Broadcast room not found (event ${playback.infoEvent.getId()})`, + ); + } + const playbackToggle = () => { playback.toggle(); }; diff --git a/test/voice-broadcast/components/atoms/VoiceBroadcastHeader-test.tsx b/test/voice-broadcast/components/atoms/VoiceBroadcastHeader-test.tsx index f056137813..e090841c82 100644 --- a/test/voice-broadcast/components/atoms/VoiceBroadcastHeader-test.tsx +++ b/test/voice-broadcast/components/atoms/VoiceBroadcastHeader-test.tsx @@ -35,12 +35,17 @@ describe("VoiceBroadcastHeader", () => { const sender = new RoomMember(roomId, userId); let container: Container; - const renderHeader = (live: VoiceBroadcastLiveness, showBroadcast: boolean = undefined): RenderResult => { + const renderHeader = ( + live: VoiceBroadcastLiveness, + showBroadcast?: boolean, + buffering?: boolean, + ): RenderResult => { return render(); }; @@ -51,6 +56,16 @@ describe("VoiceBroadcastHeader", () => { }); describe("when rendering a live broadcast header with broadcast info", () => { + beforeEach(() => { + container = renderHeader("live", true, true).container; + }); + + it("should render the header with a red live badge", () => { + expect(container).toMatchSnapshot(); + }); + }); + + describe("when rendering a buffering live broadcast header with broadcast info", () => { beforeEach(() => { container = renderHeader("live", true).container; }); diff --git a/test/voice-broadcast/components/atoms/__snapshots__/VoiceBroadcastHeader-test.tsx.snap b/test/voice-broadcast/components/atoms/__snapshots__/VoiceBroadcastHeader-test.tsx.snap index 1f4b657a22..c00d81e37d 100644 --- a/test/voice-broadcast/components/atoms/__snapshots__/VoiceBroadcastHeader-test.tsx.snap +++ b/test/voice-broadcast/components/atoms/__snapshots__/VoiceBroadcastHeader-test.tsx.snap @@ -1,5 +1,55 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`VoiceBroadcastHeader when rendering a buffering live broadcast header with broadcast info should render the header with a red live badge 1`] = ` +
+
+
+ room avatar: + !room:example.com +
+
+
+ !room:example.com +
+
+
+ + test user + +
+
+
+ Voice broadcast +
+
+
+
+ Live +
+
+
+`; + exports[`VoiceBroadcastHeader when rendering a live (grey) broadcast header with broadcast info should render the header with a grey live badge 1`] = `
Voice broadcast
+
+
+
+
+ Buffering… +
- Voice broadcast + class="mx_Spinner" + > +
+
+ Buffering…
Date: Fri, 2 Dec 2022 10:35:04 +0000 Subject: [PATCH 06/13] [Backport staging] Fix call splitbrains when switching between rooms (#9701) * Fix call splitbrains when switching between rooms Mounting CallView causes the user's call membership room state to be cleaned up. However, because the GroupCall object always thought the local device was disconnected from the call, it would remove the local device from room state when the clean method is called, causing a splitbrain. This uses GroupCall's new enteredViaAnotherSession field to fix that, and also simplify participant tracking. * Remove clean tests that have been moved to matrix-js-sdk (cherry picked from commit 62a740d318980c98475aa564ef54bfc27e6d3880) Co-authored-by: Robin --- src/models/Call.ts | 27 +---------- test/models/Call-test.ts | 90 ----------------------------------- test/test-utils/test-utils.ts | 1 + 3 files changed, 3 insertions(+), 115 deletions(-) diff --git a/src/models/Call.ts b/src/models/Call.ts index 0e20c331fb..383f3557ac 100644 --- a/src/models/Call.ts +++ b/src/models/Call.ts @@ -647,7 +647,6 @@ export class ElementCall extends Call { client, ); - this.on(CallEvent.ConnectionState, this.onConnectionState); this.on(CallEvent.Participants, this.onParticipants); groupCall.on(GroupCallEvent.ParticipantsChanged, this.onGroupCallParticipants); groupCall.on(GroupCallEvent.GroupCallStateChanged, this.onGroupCallState); @@ -704,6 +703,7 @@ export class ElementCall extends Call { throw new Error(`Failed to join call in room ${this.roomId}: ${e}`); } + this.groupCall.enteredViaAnotherSession = true; this.messaging!.on(`action:${ElementWidgetActions.HangupCall}`, this.onHangup); this.messaging!.on(`action:${ElementWidgetActions.TileLayout}`, this.onTileLayout); this.messaging!.on(`action:${ElementWidgetActions.SpotlightLayout}`, this.onSpotlightLayout); @@ -724,11 +724,11 @@ export class ElementCall extends Call { this.messaging!.off(`action:${ElementWidgetActions.SpotlightLayout}`, this.onSpotlightLayout); this.messaging!.off(`action:${ElementWidgetActions.ScreenshareRequest}`, this.onScreenshareRequest); super.setDisconnected(); + this.groupCall.enteredViaAnotherSession = false; } public destroy() { WidgetStore.instance.removeVirtualWidget(this.widget.id, this.groupCall.room.roomId); - this.off(CallEvent.ConnectionState, this.onConnectionState); this.off(CallEvent.Participants, this.onParticipants); this.groupCall.off(GroupCallEvent.ParticipantsChanged, this.onGroupCallParticipants); this.groupCall.off(GroupCallEvent.GroupCallStateChanged, this.onGroupCallState); @@ -760,20 +760,6 @@ export class ElementCall extends Call { participants.set(member, new Set(deviceMap.keys())); } - // We never enter group calls natively, so the GroupCall will think it's - // disconnected regardless of what our call member state says. Thus we - // have to insert our own device manually when connected via the widget. - if (this.connected) { - const localMember = this.room.getMember(this.client.getUserId()!)!; - let devices = participants.get(localMember); - if (devices === undefined) { - devices = new Set(); - participants.set(localMember, devices); - } - - devices.add(this.client.getDeviceId()!); - } - this.participants = participants; } @@ -782,15 +768,6 @@ export class ElementCall extends Call { && this.room.currentState.mayClientSendStateEvent(ElementCall.CALL_EVENT_TYPE.name, this.client); } - private onConnectionState = (state: ConnectionState, prevState: ConnectionState) => { - if ( - (state === ConnectionState.Connected && !isConnected(prevState)) - || (state === ConnectionState.Disconnected && isConnected(prevState)) - ) { - this.updateParticipants(); // Local echo - } - }; - private onParticipants = async ( participants: Map>, prevParticipants: Map>, diff --git a/test/models/Call-test.ts b/test/models/Call-test.ts index aa22db2718..785b9eea58 100644 --- a/test/models/Call-test.ts +++ b/test/models/Call-test.ts @@ -939,96 +939,6 @@ describe("ElementCall", () => { call.off(CallEvent.Destroy, onDestroy); }); - - describe("clean", () => { - const aliceWeb: IMyDevice = { - device_id: "aliceweb", - last_seen_ts: 0, - }; - const aliceDesktop: IMyDevice = { - device_id: "alicedesktop", - last_seen_ts: 0, - }; - const aliceDesktopOffline: IMyDevice = { - device_id: "alicedesktopoffline", - last_seen_ts: 1000 * 60 * 60 * -2, // 2 hours ago - }; - const aliceDesktopNeverOnline: IMyDevice = { - device_id: "alicedesktopneveronline", - }; - - const mkContent = (devices: IMyDevice[]) => ({ - "m.calls": [{ - "m.call_id": call.groupCall.groupCallId, - "m.devices": devices.map(d => ({ - device_id: d.device_id, session_id: "1", feeds: [], expires_ts: 1000 * 60 * 10, - })), - }], - }); - const expectDevices = (devices: IMyDevice[]) => expect( - room.currentState.getStateEvents(ElementCall.MEMBER_EVENT_TYPE.name, alice.userId)?.getContent(), - ).toEqual({ - "m.calls": [{ - "m.call_id": call.groupCall.groupCallId, - "m.devices": devices.map(d => ({ - device_id: d.device_id, session_id: "1", feeds: [], expires_ts: expect.any(Number), - })), - }], - }); - - beforeEach(() => { - client.getDeviceId.mockReturnValue(aliceWeb.device_id); - client.getDevices.mockResolvedValue({ - devices: [ - aliceWeb, - aliceDesktop, - aliceDesktopOffline, - aliceDesktopNeverOnline, - ], - }); - }); - - it("doesn't clean up valid devices", async () => { - await client.sendStateEvent( - room.roomId, - ElementCall.MEMBER_EVENT_TYPE.name, - mkContent([aliceDesktop]), - alice.userId, - ); - - await call.clean(); - expectDevices([aliceDesktop]); - }); - - it("cleans up our own device if we're disconnected", async () => { - await client.sendStateEvent( - room.roomId, - ElementCall.MEMBER_EVENT_TYPE.name, - mkContent([aliceWeb, aliceDesktop]), - alice.userId, - ); - - await call.clean(); - expectDevices([aliceDesktop]); - }); - - it("cleans up devices that have never been online", async () => { - await client.sendStateEvent( - room.roomId, - ElementCall.MEMBER_EVENT_TYPE.name, - mkContent([aliceDesktop, aliceDesktopNeverOnline]), - alice.userId, - ); - - await call.clean(); - expectDevices([aliceDesktop]); - }); - - it("no-ops if there are no state events", async () => { - await call.clean(); - expect(room.currentState.getStateEvents(JitsiCall.MEMBER_EVENT_TYPE, alice.userId)).toBe(null); - }); - }); }); describe("instance in a video room", () => { diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index e218629547..69b626dfd5 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -91,6 +91,7 @@ export function createTestClient(): MatrixClient { getDeviceId: jest.fn().mockReturnValue("ABCDEFGHI"), deviceId: "ABCDEFGHI", getDevices: jest.fn().mockResolvedValue({ devices: [{ device_id: "ABCDEFGHI" }] }), + getSessionId: jest.fn().mockReturnValue("iaszphgvfku"), credentials: { userId: "@userId:matrix.org" }, store: { From dae04a777e447972c7ef8d0a6a7dba752ce74663 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Fri, 2 Dec 2022 16:30:15 +0000 Subject: [PATCH 07/13] Upgrade matrix-js-sdk to 22.0.0-rc.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 55302f0183..d816663024 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "maplibre-gl": "^1.15.2", "matrix-encrypt-attachment": "^1.0.3", "matrix-events-sdk": "0.0.1", - "matrix-js-sdk": "22.0.0-rc.1", + "matrix-js-sdk": "22.0.0-rc.2", "matrix-widget-api": "^1.1.1", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", diff --git a/yarn.lock b/yarn.lock index 13f0be9c65..e44f797940 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7167,10 +7167,10 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -matrix-js-sdk@22.0.0-rc.1: - version "22.0.0-rc.1" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-22.0.0-rc.1.tgz#e590b204b39179cd1c48ea6d577f3ac96989a5b7" - integrity sha512-6BLXHle0QIpgccpFE7EQq2IhTnsbhomCx0NZJ9URIY08M2aznvVxM2XfTi+LGjRKhv7yu8TueJaW7sGlsqZ79w== +matrix-js-sdk@22.0.0-rc.2: + version "22.0.0-rc.2" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-22.0.0-rc.2.tgz#101a3bf54b67d8c96b17dbc9bfdbed8457e3b673" + integrity sha512-yvfIfrlemxE+fhJHlmZqvwa/NVkV0zH0H+0ktxidd5WiXExMJL07uDZd9WyCOZb3vTkcxBiSDR9UWBfLJvQdjg== dependencies: "@babel/runtime" "^7.12.5" "@types/sdp-transform" "^2.4.5" From cc2e40e5cfe689359da865a1fd9ca539058a7857 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Fri, 2 Dec 2022 16:32:11 +0000 Subject: [PATCH 08/13] Prepare changelog for v3.62.0-rc.2 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2e2dce388..428d1d1024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Changes in [3.62.0-rc.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.62.0-rc.2) (2022-12-02) +=============================================================================================================== + +## 🐛 Bug Fixes + * Fix call splitbrains when switching between rooms ([\#9692](https://github.com/matrix-org/matrix-react-sdk/pull/9692)). + Changes in [3.62.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.62.0-rc.1) (2022-11-29) =============================================================================================================== From cb2e1e92fd47afd3d2d20cdb39ca8aa574c167f6 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Fri, 2 Dec 2022 16:32:12 +0000 Subject: [PATCH 09/13] v3.62.0-rc.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d816663024..9c4972981b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.62.0-rc.1", + "version": "3.62.0-rc.2", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From f3432e99c8ee2ce2428444a09e04cbcf5b6d130b Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Mon, 5 Dec 2022 13:14:58 +0000 Subject: [PATCH 10/13] [Backport staging] Fix replies to emotes not showing as inline (#9708) Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/rooms/_ReplyTile.pcss | 17 +++++++++++++++-- src/components/views/rooms/ReplyTile.tsx | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/res/css/views/rooms/_ReplyTile.pcss b/res/css/views/rooms/_ReplyTile.pcss index fe6235eb1e..616f1b181f 100644 --- a/res/css/views/rooms/_ReplyTile.pcss +++ b/res/css/views/rooms/_ReplyTile.pcss @@ -28,8 +28,11 @@ limitations under the License. } > a { - display: flex; - flex-direction: column; + display: grid; + grid-template: + "sender" auto + "message" auto + / auto; text-decoration: none; color: $secondary-content; transition: color ease 0.15s; @@ -58,6 +61,7 @@ limitations under the License. /* We do reply size limiting with CSS to avoid duplicating the TextualBody component. */ .mx_EventTile_content { + grid-area: message; $reply-lines: 2; $line-height: $font-18px; @@ -102,7 +106,16 @@ limitations under the License. padding-top: 0; } + &.mx_ReplyTile_inline > a { + /* Render replies to emotes inline with the sender avatar */ + grid-template: + "sender message" auto + / max-content auto; + gap: 4px; // increase spacing + } + .mx_ReplyTile_sender { + grid-area: sender; display: flex; align-items: center; gap: 4px; diff --git a/src/components/views/rooms/ReplyTile.tsx b/src/components/views/rooms/ReplyTile.tsx index cdfbce1a88..515c8975e7 100644 --- a/src/components/views/rooms/ReplyTile.tsx +++ b/src/components/views/rooms/ReplyTile.tsx @@ -123,6 +123,7 @@ export default class ReplyTile extends React.PureComponent { } const classes = classNames("mx_ReplyTile", { + mx_ReplyTile_inline: msgType === MsgType.Emote, mx_ReplyTile_info: isInfoMessage && !mxEvent.isRedacted(), mx_ReplyTile_audio: msgType === MsgType.Audio, mx_ReplyTile_video: msgType === MsgType.Video, From 336b96acc3d2e6de3cf509099fef2d9d15e0b145 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 6 Dec 2022 12:40:19 +0000 Subject: [PATCH 11/13] Upgrade matrix-js-sdk to 22.0.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9c4972981b..41d2e02e51 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "maplibre-gl": "^1.15.2", "matrix-encrypt-attachment": "^1.0.3", "matrix-events-sdk": "0.0.1", - "matrix-js-sdk": "22.0.0-rc.2", + "matrix-js-sdk": "22.0.0", "matrix-widget-api": "^1.1.1", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", diff --git a/yarn.lock b/yarn.lock index e44f797940..07017a3b92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7167,10 +7167,10 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -matrix-js-sdk@22.0.0-rc.2: - version "22.0.0-rc.2" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-22.0.0-rc.2.tgz#101a3bf54b67d8c96b17dbc9bfdbed8457e3b673" - integrity sha512-yvfIfrlemxE+fhJHlmZqvwa/NVkV0zH0H+0ktxidd5WiXExMJL07uDZd9WyCOZb3vTkcxBiSDR9UWBfLJvQdjg== +matrix-js-sdk@22.0.0: + version "22.0.0" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-22.0.0.tgz#8e396a1798d6d1515a92cf8f544b0010bd0c9e85" + integrity sha512-mpKqeD3nCobjGiUiATUyEoP44n+AzDW5cSeBTIBY5fPhj0AkzLJhblHt40vzSOJazj8tT0PhsSzhEIR9hGzYGA== dependencies: "@babel/runtime" "^7.12.5" "@types/sdp-transform" "^2.4.5" From 143a3b16b354b201a4e9798c269170f95d7be368 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 6 Dec 2022 12:47:42 +0000 Subject: [PATCH 12/13] Prepare changelog for v3.62.0 --- CHANGELOG.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 428d1d1024..6d46f19fb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,5 @@ -Changes in [3.62.0-rc.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.62.0-rc.2) (2022-12-02) -=============================================================================================================== - -## 🐛 Bug Fixes - * Fix call splitbrains when switching between rooms ([\#9692](https://github.com/matrix-org/matrix-react-sdk/pull/9692)). - -Changes in [3.62.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.62.0-rc.1) (2022-11-29) -=============================================================================================================== +Changes in [3.62.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.62.0) (2022-12-06) +===================================================================================================== ## ✨ Features * Further improve replies ([\#6396](https://github.com/matrix-org/matrix-react-sdk/pull/6396)). Fixes vector-im/element-web#19074, vector-im/element-web#18194 vector-im/element-web#18027 and vector-im/element-web#19179. @@ -29,6 +23,8 @@ Changes in [3.62.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases * Fix regression with TimelinePanel props updates not taking effect ([\#9608](https://github.com/matrix-org/matrix-react-sdk/pull/9608)). Fixes vector-im/element-web#23794. * Fix form tooltip positioning ([\#9598](https://github.com/matrix-org/matrix-react-sdk/pull/9598)). Fixes vector-im/element-web#22861. * Extract Search handling from RoomView into its own Component ([\#9574](https://github.com/matrix-org/matrix-react-sdk/pull/9574)). Fixes vector-im/element-web#498. + * Fix call splitbrains when switching between rooms ([\#9692](https://github.com/matrix-org/matrix-react-sdk/pull/9692)). + * Fix replies to emotes not showing as inline ([\#9707](https://github.com/matrix-org/matrix-react-sdk/pull/9707)). Fixes vector-im/element-web#23903. Changes in [3.61.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.61.0) (2022-11-22) ===================================================================================================== From df0eba7eab8a64de9a715274c902f6f6fc718805 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 6 Dec 2022 12:47:43 +0000 Subject: [PATCH 13/13] v3.62.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 41d2e02e51..738268babf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.62.0-rc.2", + "version": "3.62.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": {