mirror of
https://github.com/element-hq/element-web
synced 2024-11-29 21:08:58 +03:00
Voice Broadcast live state / extract RelationsHelper
(#9432)
* Extract RelationsHelper * Make RelationsHelper.relations optional
This commit is contained in:
parent
e38c9e036c
commit
1b74782854
6 changed files with 328 additions and 42 deletions
98
src/events/RelationsHelper.ts
Normal file
98
src/events/RelationsHelper.ts
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { MatrixClient, MatrixEvent, MatrixEventEvent, RelationType } from "matrix-js-sdk/src/matrix";
|
||||||
|
import { Relations, RelationsEvent } from "matrix-js-sdk/src/models/relations";
|
||||||
|
import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter";
|
||||||
|
|
||||||
|
import { IDestroyable } from "../utils/IDestroyable";
|
||||||
|
|
||||||
|
export enum RelationsHelperEvent {
|
||||||
|
Add = "add",
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EventMap {
|
||||||
|
[RelationsHelperEvent.Add]: (event: MatrixEvent) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class that manages a specific event type relation for an event.
|
||||||
|
* Just create an instance and listen for new events for that relation.
|
||||||
|
* Optionally receive the current events by calling emitCurrent().
|
||||||
|
* Clean up everything by calling destroy().
|
||||||
|
*/
|
||||||
|
export class RelationsHelper
|
||||||
|
extends TypedEventEmitter<RelationsHelperEvent, EventMap>
|
||||||
|
implements IDestroyable {
|
||||||
|
private relations?: Relations;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
private event: MatrixEvent,
|
||||||
|
private relationType: RelationType,
|
||||||
|
private relationEventType: string,
|
||||||
|
private client: MatrixClient,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this.setUpRelations();
|
||||||
|
}
|
||||||
|
|
||||||
|
private setUpRelations = (): void => {
|
||||||
|
this.setRelations();
|
||||||
|
|
||||||
|
if (this.relations) {
|
||||||
|
this.relations.on(RelationsEvent.Add, this.onRelationsAdd);
|
||||||
|
} else {
|
||||||
|
this.event.once(MatrixEventEvent.RelationsCreated, this.onRelationsCreated);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private onRelationsCreated = (): void => {
|
||||||
|
this.setRelations();
|
||||||
|
|
||||||
|
if (this.relations) {
|
||||||
|
this.relations.on(RelationsEvent.Add, this.onRelationsAdd);
|
||||||
|
this.emitCurrent();
|
||||||
|
} else {
|
||||||
|
this.event.once(MatrixEventEvent.RelationsCreated, this.onRelationsCreated);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private setRelations(): void {
|
||||||
|
const room = this.client.getRoom(this.event.getRoomId());
|
||||||
|
this.relations = room?.getUnfilteredTimelineSet()?.relations?.getChildEventsForEvent(
|
||||||
|
this.event.getId(),
|
||||||
|
this.relationType,
|
||||||
|
this.relationEventType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onRelationsAdd = (event: MatrixEvent): void => {
|
||||||
|
this.emit(RelationsHelperEvent.Add, event);
|
||||||
|
};
|
||||||
|
|
||||||
|
public emitCurrent(): void {
|
||||||
|
this.relations?.getRelations()?.forEach(e => this.emit(RelationsHelperEvent.Add, e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy(): void {
|
||||||
|
this.removeAllListeners();
|
||||||
|
this.event.off(MatrixEventEvent.RelationsCreated, this.onRelationsCreated);
|
||||||
|
|
||||||
|
if (this.relations) {
|
||||||
|
this.relations.off(RelationsEvent.Add, this.onRelationsAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ export const VoiceBroadcastPlaybackBody: React.FC<VoiceBroadcastPlaybackBodyProp
|
||||||
playback,
|
playback,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
|
live,
|
||||||
room,
|
room,
|
||||||
sender,
|
sender,
|
||||||
toggle,
|
toggle,
|
||||||
|
@ -40,7 +41,7 @@ export const VoiceBroadcastPlaybackBody: React.FC<VoiceBroadcastPlaybackBodyProp
|
||||||
return (
|
return (
|
||||||
<div className="mx_VoiceBroadcastPlaybackBody">
|
<div className="mx_VoiceBroadcastPlaybackBody">
|
||||||
<VoiceBroadcastHeader
|
<VoiceBroadcastHeader
|
||||||
live={false}
|
live={live}
|
||||||
sender={sender}
|
sender={sender}
|
||||||
room={room}
|
room={room}
|
||||||
showBroadcast={true}
|
showBroadcast={true}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { useState } from "react";
|
||||||
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
||||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||||
import {
|
import {
|
||||||
|
VoiceBroadcastInfoState,
|
||||||
VoiceBroadcastPlayback,
|
VoiceBroadcastPlayback,
|
||||||
VoiceBroadcastPlaybackEvent,
|
VoiceBroadcastPlaybackEvent,
|
||||||
VoiceBroadcastPlaybackState,
|
VoiceBroadcastPlaybackState,
|
||||||
|
@ -40,7 +41,17 @@ export const useVoiceBroadcastPlayback = (playback: VoiceBroadcastPlayback) => {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [playbackInfoState, setPlaybackInfoState] = useState(playback.getInfoState());
|
||||||
|
useTypedEventEmitter(
|
||||||
|
playback,
|
||||||
|
VoiceBroadcastPlaybackEvent.InfoStateChanged,
|
||||||
|
(state: VoiceBroadcastInfoState) => {
|
||||||
|
setPlaybackInfoState(state);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
live: playbackInfoState !== VoiceBroadcastInfoState.Stopped,
|
||||||
room: room,
|
room: room,
|
||||||
sender: playback.infoEvent.sender,
|
sender: playback.infoEvent.sender,
|
||||||
toggle: playbackToggle,
|
toggle: playbackToggle,
|
||||||
|
|
|
@ -18,20 +18,19 @@ import {
|
||||||
EventType,
|
EventType,
|
||||||
MatrixClient,
|
MatrixClient,
|
||||||
MatrixEvent,
|
MatrixEvent,
|
||||||
MatrixEventEvent,
|
|
||||||
MsgType,
|
MsgType,
|
||||||
RelationType,
|
RelationType,
|
||||||
} from "matrix-js-sdk/src/matrix";
|
} from "matrix-js-sdk/src/matrix";
|
||||||
import { Relations, RelationsEvent } from "matrix-js-sdk/src/models/relations";
|
|
||||||
import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter";
|
import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter";
|
||||||
|
|
||||||
import { Playback, PlaybackState } from "../../audio/Playback";
|
import { Playback, PlaybackState } from "../../audio/Playback";
|
||||||
import { PlaybackManager } from "../../audio/PlaybackManager";
|
import { PlaybackManager } from "../../audio/PlaybackManager";
|
||||||
import { getReferenceRelationsForEvent } from "../../events";
|
|
||||||
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
||||||
import { MediaEventHelper } from "../../utils/MediaEventHelper";
|
import { MediaEventHelper } from "../../utils/MediaEventHelper";
|
||||||
import { IDestroyable } from "../../utils/IDestroyable";
|
import { IDestroyable } from "../../utils/IDestroyable";
|
||||||
import { VoiceBroadcastChunkEventType } from "..";
|
import { VoiceBroadcastChunkEventType, VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "..";
|
||||||
|
import { RelationsHelper, RelationsHelperEvent } from "../../events/RelationsHelper";
|
||||||
|
import { getReferenceRelationsForEvent } from "../../events";
|
||||||
|
|
||||||
export enum VoiceBroadcastPlaybackState {
|
export enum VoiceBroadcastPlaybackState {
|
||||||
Paused,
|
Paused,
|
||||||
|
@ -42,29 +41,55 @@ export enum VoiceBroadcastPlaybackState {
|
||||||
export enum VoiceBroadcastPlaybackEvent {
|
export enum VoiceBroadcastPlaybackEvent {
|
||||||
LengthChanged = "length_changed",
|
LengthChanged = "length_changed",
|
||||||
StateChanged = "state_changed",
|
StateChanged = "state_changed",
|
||||||
|
InfoStateChanged = "info_state_changed",
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EventMap {
|
interface EventMap {
|
||||||
[VoiceBroadcastPlaybackEvent.LengthChanged]: (length: number) => void;
|
[VoiceBroadcastPlaybackEvent.LengthChanged]: (length: number) => void;
|
||||||
[VoiceBroadcastPlaybackEvent.StateChanged]: (state: VoiceBroadcastPlaybackState) => void;
|
[VoiceBroadcastPlaybackEvent.StateChanged]: (state: VoiceBroadcastPlaybackState) => void;
|
||||||
|
[VoiceBroadcastPlaybackEvent.InfoStateChanged]: (state: VoiceBroadcastInfoState) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class VoiceBroadcastPlayback
|
export class VoiceBroadcastPlayback
|
||||||
extends TypedEventEmitter<VoiceBroadcastPlaybackEvent, EventMap>
|
extends TypedEventEmitter<VoiceBroadcastPlaybackEvent, EventMap>
|
||||||
implements IDestroyable {
|
implements IDestroyable {
|
||||||
private state = VoiceBroadcastPlaybackState.Stopped;
|
private state = VoiceBroadcastPlaybackState.Stopped;
|
||||||
|
private infoState: VoiceBroadcastInfoState;
|
||||||
private chunkEvents = new Map<string, MatrixEvent>();
|
private chunkEvents = new Map<string, MatrixEvent>();
|
||||||
/** Holds the playback qeue with a 1-based index (sequence number) */
|
/** Holds the playback queue with a 1-based index (sequence number) */
|
||||||
private queue: Playback[] = [];
|
private queue: Playback[] = [];
|
||||||
private currentlyPlaying: Playback;
|
private currentlyPlaying: Playback;
|
||||||
private relations: Relations;
|
private lastInfoEvent: MatrixEvent;
|
||||||
|
private chunkRelationHelper: RelationsHelper;
|
||||||
|
private infoRelationHelper: RelationsHelper;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
public readonly infoEvent: MatrixEvent,
|
public readonly infoEvent: MatrixEvent,
|
||||||
private client: MatrixClient,
|
private client: MatrixClient,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.setUpRelations();
|
this.addInfoEvent(this.infoEvent);
|
||||||
|
this.setUpRelationsHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
private setUpRelationsHelper(): void {
|
||||||
|
this.infoRelationHelper = new RelationsHelper(
|
||||||
|
this.infoEvent,
|
||||||
|
RelationType.Reference,
|
||||||
|
VoiceBroadcastInfoEventType,
|
||||||
|
this.client,
|
||||||
|
);
|
||||||
|
this.infoRelationHelper.on(RelationsHelperEvent.Add, this.addInfoEvent);
|
||||||
|
this.infoRelationHelper.emitCurrent();
|
||||||
|
|
||||||
|
this.chunkRelationHelper = new RelationsHelper(
|
||||||
|
this.infoEvent,
|
||||||
|
RelationType.Reference,
|
||||||
|
EventType.RoomMessage,
|
||||||
|
this.client,
|
||||||
|
);
|
||||||
|
this.chunkRelationHelper.on(RelationsHelperEvent.Add, this.addChunkEvent);
|
||||||
|
this.chunkRelationHelper.emitCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private addChunkEvent(event: MatrixEvent): boolean {
|
private addChunkEvent(event: MatrixEvent): boolean {
|
||||||
|
@ -81,41 +106,21 @@ export class VoiceBroadcastPlayback
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setUpRelations(): void {
|
private addInfoEvent = (event: MatrixEvent): void => {
|
||||||
const relations = getReferenceRelationsForEvent(this.infoEvent, EventType.RoomMessage, this.client);
|
if (this.lastInfoEvent && this.lastInfoEvent.getTs() >= event.getTs()) {
|
||||||
|
// Only handle newer events
|
||||||
if (!relations) {
|
|
||||||
// No related events, yet. Set up relation watcher.
|
|
||||||
this.infoEvent.on(MatrixEventEvent.RelationsCreated, this.onRelationsCreated);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.relations = relations;
|
const state = event.getContent()?.state;
|
||||||
relations.getRelations()?.forEach(e => this.addChunkEvent(e));
|
|
||||||
relations.on(RelationsEvent.Add, this.onRelationsEventAdd);
|
|
||||||
|
|
||||||
if (this.chunkEvents.size > 0) {
|
if (!Object.values(VoiceBroadcastInfoState).includes(state)) {
|
||||||
this.emitLengthChanged();
|
// Do not handle unknown voice broadcast states
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private onRelationsEventAdd = (event: MatrixEvent) => {
|
|
||||||
if (this.addChunkEvent(event)) {
|
|
||||||
this.emitLengthChanged();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private emitLengthChanged(): void {
|
|
||||||
this.emit(VoiceBroadcastPlaybackEvent.LengthChanged, this.chunkEvents.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
private onRelationsCreated = (relationType: string) => {
|
|
||||||
if (relationType !== RelationType.Reference) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.infoEvent.off(MatrixEventEvent.RelationsCreated, this.onRelationsCreated);
|
this.lastInfoEvent = event;
|
||||||
this.setUpRelations();
|
this.setInfoState(state);
|
||||||
};
|
};
|
||||||
|
|
||||||
private async loadChunks(): Promise<void> {
|
private async loadChunks(): Promise<void> {
|
||||||
|
@ -173,7 +178,7 @@ export class VoiceBroadcastPlayback
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState(VoiceBroadcastPlaybackState.Playing);
|
this.setState(VoiceBroadcastPlaybackState.Playing);
|
||||||
// index of the first schunk is the first sequence number
|
// index of the first chunk is the first sequence number
|
||||||
const first = this.queue[1];
|
const first = this.queue[1];
|
||||||
this.currentlyPlaying = first;
|
this.currentlyPlaying = first;
|
||||||
await first.play();
|
await first.play();
|
||||||
|
@ -238,17 +243,27 @@ export class VoiceBroadcastPlayback
|
||||||
this.emit(VoiceBroadcastPlaybackEvent.StateChanged, state);
|
this.emit(VoiceBroadcastPlaybackEvent.StateChanged, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getInfoState(): VoiceBroadcastInfoState {
|
||||||
|
return this.infoState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private setInfoState(state: VoiceBroadcastInfoState): void {
|
||||||
|
if (this.infoState === state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.infoState = state;
|
||||||
|
this.emit(VoiceBroadcastPlaybackEvent.InfoStateChanged, state);
|
||||||
|
}
|
||||||
|
|
||||||
private destroyQueue(): void {
|
private destroyQueue(): void {
|
||||||
this.queue.forEach(p => p.destroy());
|
this.queue.forEach(p => p.destroy());
|
||||||
this.queue = [];
|
this.queue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
if (this.relations) {
|
this.chunkRelationHelper.destroy();
|
||||||
this.relations.off(RelationsEvent.Add, this.onRelationsEventAdd);
|
this.infoRelationHelper.destroy();
|
||||||
}
|
|
||||||
|
|
||||||
this.infoEvent.off(MatrixEventEvent.RelationsCreated, this.onRelationsCreated);
|
|
||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
this.destroyQueue();
|
this.destroyQueue();
|
||||||
}
|
}
|
||||||
|
|
150
test/events/RelationsHelper-test.ts
Normal file
150
test/events/RelationsHelper-test.ts
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { mocked } from "jest-mock";
|
||||||
|
import {
|
||||||
|
EventTimelineSet,
|
||||||
|
EventType,
|
||||||
|
MatrixClient,
|
||||||
|
MatrixEvent,
|
||||||
|
MatrixEventEvent,
|
||||||
|
RelationType,
|
||||||
|
Room,
|
||||||
|
} from "matrix-js-sdk/src/matrix";
|
||||||
|
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||||
|
import { RelationsContainer } from "matrix-js-sdk/src/models/relations-container";
|
||||||
|
|
||||||
|
import { RelationsHelper, RelationsHelperEvent } from "../../src/events/RelationsHelper";
|
||||||
|
import { mkEvent, mkStubRoom, stubClient } from "../test-utils";
|
||||||
|
|
||||||
|
describe("RelationsHelper", () => {
|
||||||
|
const roomId = "!room:example.com";
|
||||||
|
let event: MatrixEvent;
|
||||||
|
let relatedEvent1: MatrixEvent;
|
||||||
|
let relatedEvent2: MatrixEvent;
|
||||||
|
let room: Room;
|
||||||
|
let client: MatrixClient;
|
||||||
|
let relationsHelper: RelationsHelper;
|
||||||
|
let onAdd: (event: MatrixEvent) => void;
|
||||||
|
let timelineSet: EventTimelineSet;
|
||||||
|
let relationsContainer: RelationsContainer;
|
||||||
|
let relations: Relations;
|
||||||
|
let relationsOnAdd: (event: MatrixEvent) => void;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
client = stubClient();
|
||||||
|
room = mkStubRoom(roomId, "test room", client);
|
||||||
|
mocked(client.getRoom).mockImplementation((getRoomId: string) => {
|
||||||
|
if (getRoomId === roomId) {
|
||||||
|
return room;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
event = mkEvent({
|
||||||
|
event: true,
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
room: roomId,
|
||||||
|
user: client.getUserId(),
|
||||||
|
content: {},
|
||||||
|
});
|
||||||
|
relatedEvent1 = mkEvent({
|
||||||
|
event: true,
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
room: roomId,
|
||||||
|
user: client.getUserId(),
|
||||||
|
content: {},
|
||||||
|
});
|
||||||
|
relatedEvent2 = mkEvent({
|
||||||
|
event: true,
|
||||||
|
type: EventType.RoomMessage,
|
||||||
|
room: roomId,
|
||||||
|
user: client.getUserId(),
|
||||||
|
content: {},
|
||||||
|
});
|
||||||
|
onAdd = jest.fn();
|
||||||
|
// TODO Michael W: create test utils, remove casts
|
||||||
|
relationsContainer = {
|
||||||
|
getChildEventsForEvent: jest.fn(),
|
||||||
|
} as unknown as RelationsContainer;
|
||||||
|
relations = {
|
||||||
|
getRelations: jest.fn(),
|
||||||
|
on: jest.fn().mockImplementation((type, l) => relationsOnAdd = l),
|
||||||
|
} as unknown as Relations;
|
||||||
|
timelineSet = {
|
||||||
|
relations: relationsContainer,
|
||||||
|
} as unknown as EventTimelineSet;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when there is an event without relations", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
relationsHelper = new RelationsHelper(event, RelationType.Reference, EventType.RoomMessage, client);
|
||||||
|
relationsHelper.on(RelationsHelperEvent.Add, onAdd);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("emitCurrent", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
relationsHelper.emitCurrent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not emit any event", () => {
|
||||||
|
expect(onAdd).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("and relations are created and a new event appears", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mocked(room.getUnfilteredTimelineSet).mockReturnValue(timelineSet);
|
||||||
|
mocked(relationsContainer.getChildEventsForEvent).mockReturnValue(relations);
|
||||||
|
mocked(relations.getRelations).mockReturnValue([relatedEvent1]);
|
||||||
|
event.emit(MatrixEventEvent.RelationsCreated, RelationType.Reference, EventType.RoomMessage);
|
||||||
|
relationsOnAdd(relatedEvent2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should emit the new event", () => {
|
||||||
|
expect(onAdd).toHaveBeenCalledWith(relatedEvent2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when there is an event with relations", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mocked(room.getUnfilteredTimelineSet).mockReturnValue(timelineSet);
|
||||||
|
mocked(relationsContainer.getChildEventsForEvent).mockReturnValue(relations);
|
||||||
|
mocked(relations.getRelations).mockReturnValue([relatedEvent1]);
|
||||||
|
relationsHelper = new RelationsHelper(event, RelationType.Reference, EventType.RoomMessage, client);
|
||||||
|
relationsHelper.on(RelationsHelperEvent.Add, onAdd);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("emitCurrent", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
relationsHelper.emitCurrent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should emit the related event", () => {
|
||||||
|
expect(onAdd).toHaveBeenCalledWith(relatedEvent1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("and a new event appears", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
relationsOnAdd(relatedEvent2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should emit the new event", () => {
|
||||||
|
expect(onAdd).toHaveBeenCalledWith(relatedEvent2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -45,6 +45,17 @@ exports[`VoiceBroadcastPlaybackBody when rendering a broadcast should render as
|
||||||
Voice broadcast
|
Voice broadcast
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_LiveBadge"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
aria-hidden="true"
|
||||||
|
class="mx_Icon mx_Icon_16 mx_Icon_live-badge"
|
||||||
|
role="presentation"
|
||||||
|
style="mask-image: url(\\"image-file-stub\\");"
|
||||||
|
/>
|
||||||
|
Live
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="mx_VoiceBroadcastPlaybackBody_controls"
|
class="mx_VoiceBroadcastPlaybackBody_controls"
|
||||||
|
|
Loading…
Reference in a new issue