Disable consecutive audio playback in Media Gallery

This commit is contained in:
Fedor Indutny
2025-12-01 11:48:36 -08:00
committed by GitHub
parent 7dae047d53
commit d25ec282c5
7 changed files with 32 additions and 11 deletions

View File

@@ -62,7 +62,7 @@ const MESSAGE_DEFAULT_PROPS = {
endPoll: shouldNeverBeCalled, endPoll: shouldNeverBeCalled,
pushPanelForConversation: shouldNeverBeCalled, pushPanelForConversation: shouldNeverBeCalled,
renderAudioAttachment: () => <div />, renderAudioAttachment: () => <div />,
renderingContext: 'EditHistoryMessagesModal', renderingContext: 'EditHistoryMessagesModal' as const,
saveAttachment: shouldNeverBeCalled, saveAttachment: shouldNeverBeCalled,
saveAttachments: shouldNeverBeCalled, saveAttachments: shouldNeverBeCalled,
scrollToQuotedMessage: shouldNeverBeCalled, scrollToQuotedMessage: shouldNeverBeCalled,

View File

@@ -46,6 +46,7 @@ import type {
} from './ReactionViewer.dom.js'; } from './ReactionViewer.dom.js';
import { ReactionViewer } from './ReactionViewer.dom.js'; import { ReactionViewer } from './ReactionViewer.dom.js';
import { LinkPreviewDate } from './LinkPreviewDate.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 { LinkPreviewForUIType } from '../../types/message/LinkPreviews.std.js';
import type { MessageStatusType } from '../../types/message/MessageStatus.std.js'; import type { MessageStatusType } from '../../types/message/MessageStatus.std.js';
import { shouldUseFullSizeLinkPreviewImage } from '../../linkPreviews/shouldUseFullSizeLinkPreviewImage.std.js'; import { shouldUseFullSizeLinkPreviewImage } from '../../linkPreviews/shouldUseFullSizeLinkPreviewImage.std.js';
@@ -178,7 +179,7 @@ export enum MessageInteractivity {
} }
export type AudioAttachmentProps = { export type AudioAttachmentProps = {
renderingContext: string; renderingContext: RenderingContextType;
i18n: LocalizerType; i18n: LocalizerType;
buttonRef: React.RefObject<HTMLButtonElement>; buttonRef: React.RefObject<HTMLButtonElement>;
theme: ThemeType | undefined; theme: ThemeType | undefined;
@@ -239,7 +240,7 @@ function ReactionEmoji(props: { emojiVariantValue: string }) {
export type PropsData = { export type PropsData = {
id: string; id: string;
renderingContext: string; renderingContext: RenderingContextType;
contactNameColor?: ContactNameColorType; contactNameColor?: ContactNameColorType;
conversationColor: ConversationColorType; conversationColor: ConversationColorType;
conversationTitle: string; conversationTitle: string;

View File

@@ -27,6 +27,7 @@ import { isAudio } from '../../util/Attachment.std.js';
import { getLocalAttachmentUrl } from '../../util/getLocalAttachmentUrl.std.js'; import { getLocalAttachmentUrl } from '../../util/getLocalAttachmentUrl.std.js';
import { assertDev } from '../../util/assert.std.js'; import { assertDev } from '../../util/assert.std.js';
import { drop } from '../../util/drop.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 { Sound, SoundType } from '../../util/Sound.std.js';
import { DataReader } from '../../sql/Client.preload.js'; import { DataReader } from '../../sql/Client.preload.js';
@@ -47,7 +48,7 @@ type AudioPlayerContentDraft = ReadonlyDeep<{
/** A voice note consecutive playback */ /** A voice note consecutive playback */
export type AudioPlayerContentVoiceNote = ReadonlyDeep<{ export type AudioPlayerContentVoiceNote = ReadonlyDeep<{
conversationId: string; conversationId: string;
context: string; context: RenderingContextType;
current: VoiceNoteForPlayback; current: VoiceNoteForPlayback;
// playing because it followed a message // playing because it followed a message
// false on the first of a consecutive group // false on the first of a consecutive group
@@ -214,6 +215,14 @@ function messageAudioEnded(): ThunkAction<
return; 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 { conversationId, context, current } = content;
const next = await getNextVoiceNote({ const next = await getNextVoiceNote({
@@ -314,7 +323,7 @@ function loadVoiceNoteAudio({
}: { }: {
voiceNoteData: VoiceNoteAndConsecutiveForPlayback; voiceNoteData: VoiceNoteAndConsecutiveForPlayback;
position: number; position: number;
context: string; context: RenderingContextType;
playbackRate: number; playbackRate: number;
}): SetMessageAudioAction { }): SetMessageAudioAction {
const { conversationId, voiceNote } = voiceNoteData; const { conversationId, voiceNote } = voiceNoteData;

View File

@@ -3,6 +3,7 @@
import React, { memo, useCallback } from 'react'; import React, { memo, useCallback } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import type { RenderingContextType } from '../../types/RenderingContext.d.ts';
import { MessageAudio } from '../../components/conversation/MessageAudio.dom.js'; import { MessageAudio } from '../../components/conversation/MessageAudio.dom.js';
import type { OwnProps as MessageAudioOwnProps } 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'; import type { ActiveAudioPlayerStateType } from '../ducks/audioPlayer.preload.js';
@@ -24,7 +25,7 @@ import {
const log = createLogger('MessageAudio'); const log = createLogger('MessageAudio');
export type Props = Omit<MessageAudioOwnProps, 'active' | 'onPlayMessage'> & { export type Props = Omit<MessageAudioOwnProps, 'active' | 'onPlayMessage'> & {
renderingContext: string; renderingContext: RenderingContextType;
}; };
export const SmartMessageAudio = memo(function SmartMessageAudio({ export const SmartMessageAudio = memo(function SmartMessageAudio({

View File

@@ -48,7 +48,7 @@ describe('state/selectors/audioPlayer', () => {
actions.loadVoiceNoteAudio({ actions.loadVoiceNoteAudio({
voiceNoteData: voiceNoteDataForMessage('id'), voiceNoteData: voiceNoteDataForMessage('id'),
position: 0, position: 0,
context: 'context', context: 'AllMedia',
playbackRate: 1, playbackRate: 1,
}) })
); );

View File

@@ -54,7 +54,7 @@ describe('both/state/ducks/audioPlayer', () => {
actions.loadVoiceNoteAudio({ actions.loadVoiceNoteAudio({
voiceNoteData: voiceNoteDataForMessage(MESSAGE_ID), voiceNoteData: voiceNoteDataForMessage(MESSAGE_ID),
position: 0, position: 0,
context: 'context', context: 'AllMedia',
playbackRate: 1, playbackRate: 1,
}) })
); );
@@ -65,7 +65,7 @@ describe('both/state/ducks/audioPlayer', () => {
if (content && AudioPlayerContent.isVoiceNote(content)) { if (content && AudioPlayerContent.isVoiceNote(content)) {
assert.strictEqual(content.current.id, MESSAGE_ID); assert.strictEqual(content.current.id, MESSAGE_ID);
assert.strictEqual(content.context, 'context'); assert.strictEqual(content.context, 'AllMedia');
} }
return updated; return updated;
@@ -81,7 +81,7 @@ describe('both/state/ducks/audioPlayer', () => {
actions.loadVoiceNoteAudio({ actions.loadVoiceNoteAudio({
voiceNoteData: voiceNoteDataForMessage('test'), voiceNoteData: voiceNoteDataForMessage('test'),
position: 0, position: 0,
context: 'context', context: 'AllMedia',
playbackRate: 1, playbackRate: 1,
}) })
); );
@@ -91,7 +91,7 @@ describe('both/state/ducks/audioPlayer', () => {
if (content && AudioPlayerContent.isVoiceNote(content)) { if (content && AudioPlayerContent.isVoiceNote(content)) {
assert.strictEqual(content.current.id, 'test'); assert.strictEqual(content.current.id, 'test');
assert.strictEqual(content.context, 'context'); assert.strictEqual(content.context, 'AllMedia');
} }
}); });
}); });

10
ts/types/RenderingContext.d.ts vendored Normal file
View File

@@ -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';