From d25ec282c5cfa5d4db9ddf539cfe07b7bec07ac5 Mon Sep 17 00:00:00 2001 From: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com> Date: Mon, 1 Dec 2025 11:48:36 -0800 Subject: [PATCH] Disable consecutive audio playback in Media Gallery --- ts/components/EditHistoryMessagesModal.dom.tsx | 2 +- ts/components/conversation/Message.dom.tsx | 5 +++-- ts/state/ducks/audioPlayer.preload.ts | 13 +++++++++++-- ts/state/smart/MessageAudio.preload.tsx | 3 ++- .../state/selectors/audioPlayer_test.preload.ts | 2 +- .../state/ducks/audioPlayer_test.preload.ts | 8 ++++---- ts/types/RenderingContext.d.ts | 10 ++++++++++ 7 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 ts/types/RenderingContext.d.ts diff --git a/ts/components/EditHistoryMessagesModal.dom.tsx b/ts/components/EditHistoryMessagesModal.dom.tsx index e3696a5b5a..0a307c5f72 100644 --- a/ts/components/EditHistoryMessagesModal.dom.tsx +++ b/ts/components/EditHistoryMessagesModal.dom.tsx @@ -62,7 +62,7 @@ const MESSAGE_DEFAULT_PROPS = { endPoll: shouldNeverBeCalled, pushPanelForConversation: shouldNeverBeCalled, renderAudioAttachment: () =>
, - renderingContext: 'EditHistoryMessagesModal', + renderingContext: 'EditHistoryMessagesModal' as const, saveAttachment: shouldNeverBeCalled, saveAttachments: shouldNeverBeCalled, scrollToQuotedMessage: shouldNeverBeCalled, diff --git a/ts/components/conversation/Message.dom.tsx b/ts/components/conversation/Message.dom.tsx index 4fa81457e9..4bc82d7fec 100644 --- a/ts/components/conversation/Message.dom.tsx +++ b/ts/components/conversation/Message.dom.tsx @@ -46,6 +46,7 @@ import type { } from './ReactionViewer.dom.js'; import { ReactionViewer } from './ReactionViewer.dom.js'; import { LinkPreviewDate } from './LinkPreviewDate.dom.js'; +import type { RenderingContextType } from '../../types/RenderingContext.d.ts'; import type { LinkPreviewForUIType } from '../../types/message/LinkPreviews.std.js'; import type { MessageStatusType } from '../../types/message/MessageStatus.std.js'; import { shouldUseFullSizeLinkPreviewImage } from '../../linkPreviews/shouldUseFullSizeLinkPreviewImage.std.js'; @@ -178,7 +179,7 @@ export enum MessageInteractivity { } export type AudioAttachmentProps = { - renderingContext: string; + renderingContext: RenderingContextType; i18n: LocalizerType; buttonRef: React.RefObject; theme: ThemeType | undefined; @@ -239,7 +240,7 @@ function ReactionEmoji(props: { emojiVariantValue: string }) { export type PropsData = { id: string; - renderingContext: string; + renderingContext: RenderingContextType; contactNameColor?: ContactNameColorType; conversationColor: ConversationColorType; conversationTitle: string; diff --git a/ts/state/ducks/audioPlayer.preload.ts b/ts/state/ducks/audioPlayer.preload.ts index 324bbc7301..28765086e9 100644 --- a/ts/state/ducks/audioPlayer.preload.ts +++ b/ts/state/ducks/audioPlayer.preload.ts @@ -27,6 +27,7 @@ import { isAudio } from '../../util/Attachment.std.js'; import { getLocalAttachmentUrl } from '../../util/getLocalAttachmentUrl.std.js'; import { assertDev } from '../../util/assert.std.js'; import { drop } from '../../util/drop.std.js'; +import type { RenderingContextType } from '../../types/RenderingContext.d.ts'; import { Sound, SoundType } from '../../util/Sound.std.js'; import { DataReader } from '../../sql/Client.preload.js'; @@ -47,7 +48,7 @@ type AudioPlayerContentDraft = ReadonlyDeep<{ /** A voice note consecutive playback */ export type AudioPlayerContentVoiceNote = ReadonlyDeep<{ conversationId: string; - context: string; + context: RenderingContextType; current: VoiceNoteForPlayback; // playing because it followed a message // false on the first of a consecutive group @@ -214,6 +215,14 @@ function messageAudioEnded(): ThunkAction< return; } + // No consecutive playback in All Media view + if (content.context === 'AllMedia') { + dispatch({ + type: 'audioPlayer/MESSAGE_AUDIO_ENDED', + }); + return; + } + const { conversationId, context, current } = content; const next = await getNextVoiceNote({ @@ -314,7 +323,7 @@ function loadVoiceNoteAudio({ }: { voiceNoteData: VoiceNoteAndConsecutiveForPlayback; position: number; - context: string; + context: RenderingContextType; playbackRate: number; }): SetMessageAudioAction { const { conversationId, voiceNote } = voiceNoteData; diff --git a/ts/state/smart/MessageAudio.preload.tsx b/ts/state/smart/MessageAudio.preload.tsx index d5d3c5faa0..cd02f37a71 100644 --- a/ts/state/smart/MessageAudio.preload.tsx +++ b/ts/state/smart/MessageAudio.preload.tsx @@ -3,6 +3,7 @@ import React, { memo, useCallback } from 'react'; import { useSelector } from 'react-redux'; +import type { RenderingContextType } from '../../types/RenderingContext.d.ts'; import { MessageAudio } from '../../components/conversation/MessageAudio.dom.js'; import type { OwnProps as MessageAudioOwnProps } from '../../components/conversation/MessageAudio.dom.js'; import type { ActiveAudioPlayerStateType } from '../ducks/audioPlayer.preload.js'; @@ -24,7 +25,7 @@ import { const log = createLogger('MessageAudio'); export type Props = Omit & { - renderingContext: string; + renderingContext: RenderingContextType; }; export const SmartMessageAudio = memo(function SmartMessageAudio({ diff --git a/ts/test-electron/state/selectors/audioPlayer_test.preload.ts b/ts/test-electron/state/selectors/audioPlayer_test.preload.ts index d507ad9e85..334b4d8362 100644 --- a/ts/test-electron/state/selectors/audioPlayer_test.preload.ts +++ b/ts/test-electron/state/selectors/audioPlayer_test.preload.ts @@ -48,7 +48,7 @@ describe('state/selectors/audioPlayer', () => { actions.loadVoiceNoteAudio({ voiceNoteData: voiceNoteDataForMessage('id'), position: 0, - context: 'context', + context: 'AllMedia', playbackRate: 1, }) ); diff --git a/ts/test-node/state/ducks/audioPlayer_test.preload.ts b/ts/test-node/state/ducks/audioPlayer_test.preload.ts index 109b80823f..35e06963c8 100644 --- a/ts/test-node/state/ducks/audioPlayer_test.preload.ts +++ b/ts/test-node/state/ducks/audioPlayer_test.preload.ts @@ -54,7 +54,7 @@ describe('both/state/ducks/audioPlayer', () => { actions.loadVoiceNoteAudio({ voiceNoteData: voiceNoteDataForMessage(MESSAGE_ID), position: 0, - context: 'context', + context: 'AllMedia', playbackRate: 1, }) ); @@ -65,7 +65,7 @@ describe('both/state/ducks/audioPlayer', () => { if (content && AudioPlayerContent.isVoiceNote(content)) { assert.strictEqual(content.current.id, MESSAGE_ID); - assert.strictEqual(content.context, 'context'); + assert.strictEqual(content.context, 'AllMedia'); } return updated; @@ -81,7 +81,7 @@ describe('both/state/ducks/audioPlayer', () => { actions.loadVoiceNoteAudio({ voiceNoteData: voiceNoteDataForMessage('test'), position: 0, - context: 'context', + context: 'AllMedia', playbackRate: 1, }) ); @@ -91,7 +91,7 @@ describe('both/state/ducks/audioPlayer', () => { if (content && AudioPlayerContent.isVoiceNote(content)) { assert.strictEqual(content.current.id, 'test'); - assert.strictEqual(content.context, 'context'); + assert.strictEqual(content.context, 'AllMedia'); } }); }); diff --git a/ts/types/RenderingContext.d.ts b/ts/types/RenderingContext.d.ts new file mode 100644 index 0000000000..50df593b92 --- /dev/null +++ b/ts/types/RenderingContext.d.ts @@ -0,0 +1,10 @@ +// Copyright 2025 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +export type RenderingContextType = + | 'EditHistoryMessagesModal' + | 'StoryViewsNRepliesModal' + | 'conversation/MessageDetail' + | 'conversation/TimelineItem' + | 'AllMedia' + | 'storybook';