diff --git a/src/Notifier.ts b/src/Notifier.ts index 7e1f9eb0a4..42909a2632 100644 --- a/src/Notifier.ts +++ b/src/Notifier.ts @@ -50,7 +50,8 @@ import { localNotificationsAreSilenced, createLocalNotificationSettingsIfNeeded import { getIncomingCallToastKey, IncomingCallToast } from "./toasts/IncomingCallToast"; import ToastStore from "./stores/ToastStore"; import { ElementCall } from "./models/Call"; -import { VoiceBroadcastChunkEventType } from "./voice-broadcast"; +import { VoiceBroadcastChunkEventType, VoiceBroadcastInfoEventType } from "./voice-broadcast"; +import { getSenderName } from "./utils/event/getSenderName"; /* * Dispatches: @@ -80,9 +81,16 @@ const msgTypeHandlers = { }, [MsgType.Audio]: (event: MatrixEvent): string | null => { if (event.getContent()?.[VoiceBroadcastChunkEventType]) { - // mute broadcast chunks + if (event.getContent()?.[VoiceBroadcastChunkEventType]?.sequence === 1) { + // Show a notification for the first broadcast chunk. + // At this point a user received something to listen to. + return _t("%(senderName)s started a voice broadcast", { senderName: getSenderName(event) }); + } + + // Mute other broadcast chunks return null; } + return TextForEvent.textForEvent(event); }, }; @@ -448,6 +456,9 @@ export const Notifier = { }, _evaluateEvent: function (ev: MatrixEvent) { + // Mute notifications for broadcast info events + if (ev.getType() === VoiceBroadcastInfoEventType) return; + let roomId = ev.getRoomId(); if (LegacyCallHandler.instance.getSupportsVirtualRooms()) { // Attempt to translate a virtual room to a native one diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 5f59272f19..c3f7e3613c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -112,6 +112,7 @@ "Empty room (was %(oldName)s)": "Empty room (was %(oldName)s)", "Default Device": "Default Device", "%(name)s is requesting verification": "%(name)s is requesting verification", + "%(senderName)s started a voice broadcast": "%(senderName)s started a voice broadcast", "%(brand)s does not have permission to send you notifications - please check your browser settings": "%(brand)s does not have permission to send you notifications - please check your browser settings", "%(brand)s was not given permission to send notifications - please try again": "%(brand)s was not given permission to send notifications - please try again", "Unable to enable Notifications": "Unable to enable Notifications", diff --git a/test/Notifier-test.ts b/test/Notifier-test.ts index a3b1f9b2db..20b2c2e361 100644 --- a/test/Notifier-test.ts +++ b/test/Notifier-test.ts @@ -40,7 +40,8 @@ import { mkThread } from "./test-utils/threads"; import dis from "../src/dispatcher/dispatcher"; import { ThreadPayload } from "../src/dispatcher/payloads/ThreadPayload"; import { Action } from "../src/dispatcher/actions"; -import { VoiceBroadcastChunkEventType } from "../src/voice-broadcast"; +import { VoiceBroadcastChunkEventType, VoiceBroadcastInfoState } from "../src/voice-broadcast"; +import { mkVoiceBroadcastInfoStateEvent } from "./voice-broadcast/utils/test-utils"; jest.mock("../src/utils/notifications", () => ({ // @ts-ignore @@ -75,8 +76,8 @@ describe("Notifier", () => { }); }; - const mkAudioEvent = (broadcastChunk = false): MatrixEvent => { - const chunkContent = broadcastChunk ? { [VoiceBroadcastChunkEventType]: {} } : {}; + const mkAudioEvent = (broadcastChunkContent?: object): MatrixEvent => { + const chunkContent = broadcastChunkContent ? { [VoiceBroadcastChunkEventType]: broadcastChunkContent } : {}; return mkEvent({ event: true, @@ -289,8 +290,20 @@ describe("Notifier", () => { ); }); - it("should not display a notification for a broadcast chunk", () => { - const audioEvent = mkAudioEvent(true); + it("should display the expected notification for a broadcast chunk with sequence = 1", () => { + const audioEvent = mkAudioEvent({ sequence: 1 }); + Notifier._displayPopupNotification(audioEvent, testRoom); + expect(MockPlatform.displayNotification).toHaveBeenCalledWith( + "@user:example.com (!room1:server)", + "@user:example.com started a voice broadcast", + "data:image/png;base64,00", + testRoom, + audioEvent, + ); + }); + + it("should display the expected notification for a broadcast chunk with sequence = 1", () => { + const audioEvent = mkAudioEvent({ sequence: 2 }); Notifier._displayPopupNotification(audioEvent, testRoom); expect(MockPlatform.displayNotification).not.toHaveBeenCalled(); }); @@ -499,6 +512,24 @@ describe("Notifier", () => { Notifier._evaluateEvent(mkAudioEvent()); expect(Notifier._displayPopupNotification).toHaveBeenCalledTimes(1); }); + + it("should not show a notification for broadcast info events in any case", () => { + // Let client decide to show a notification + mockClient.getPushActionsForEvent.mockReturnValue({ + notify: true, + tweaks: {}, + }); + + const broadcastStartedEvent = mkVoiceBroadcastInfoStateEvent( + "!other:example.org", + VoiceBroadcastInfoState.Started, + "@user:example.com", + "ABC123", + ); + + Notifier._evaluateEvent(broadcastStartedEvent); + expect(Notifier._displayPopupNotification).not.toHaveBeenCalled(); + }); }); describe("setPromptHidden", () => {