diff --git a/ts/components/MiniPlayer.tsx b/ts/components/MiniPlayer.tsx index 49ad6c0423..c31cbf42a2 100644 --- a/ts/components/MiniPlayer.tsx +++ b/ts/components/MiniPlayer.tsx @@ -8,6 +8,7 @@ import { durationToPlaybackText } from '../util/durationToPlaybackText'; import { PlaybackButton } from './PlaybackButton'; import { PlaybackRateButton } from './PlaybackRateButton'; import { UserText } from './UserText'; +import { shortenFileName } from '../util/attachments'; export enum PlayerState { loading = 'loading', @@ -18,6 +19,7 @@ export enum PlayerState { export type Props = Readonly<{ i18n: LocalizerType; title: string; + fileName: string | undefined currentTime: number; // not available until audio has loaded duration: number | undefined; @@ -34,6 +36,7 @@ export type Props = Readonly<{ export function MiniPlayer({ i18n, title, + fileName, state, currentTime, duration, @@ -100,8 +103,9 @@ export function MiniPlayer({
· + {shortenFileName(fileName, true)} {duration !== undefined && ( - + {durationToPlaybackText( state === PlayerState.loading ? duration : currentTime )} diff --git a/ts/components/conversation/MessageAudio.tsx b/ts/components/conversation/MessageAudio.tsx index 4f6abcb63a..396bf65518 100644 --- a/ts/components/conversation/MessageAudio.tsx +++ b/ts/components/conversation/MessageAudio.tsx @@ -23,6 +23,7 @@ import { WaveformScrubber } from './WaveformScrubber'; import { useComputePeaks } from '../../hooks/useComputePeaks'; import { durationToPlaybackText } from '../../util/durationToPlaybackText'; import { shouldNeverBeCalled } from '../../util/shouldNeverBeCalled'; +import { shortenFileName } from '../../util/attachments'; export type OwnProps = Readonly<{ active: @@ -167,7 +168,7 @@ export function MessageAudio(props: Props): JSX.Element { const [isPlayedDotVisible, setIsPlayedDotVisible] = React.useState(!played); const audioUrl = isDownloaded(attachment) ? attachment.url : undefined; - + const fileName = (attachment.fileName && !attachment.isVoiceMessage) ? shortenFileName(attachment.fileName) : undefined; const { duration, hasPeaks, peaks } = useComputePeaks({ audioUrl, activeDuration: active?.duration, @@ -369,7 +370,6 @@ export function MessageAudio(props: Props): JSX.Element { )}
); - return (
{button} - {waveform} +
+ + {fileName} + + {waveform} +
{metadata}
diff --git a/ts/state/selectors/audioPlayer.ts b/ts/state/selectors/audioPlayer.ts index c4dfe2aa6c..2808750c15 100644 --- a/ts/state/selectors/audioPlayer.ts +++ b/ts/state/selectors/audioPlayer.ts @@ -34,6 +34,7 @@ export type VoiceNoteForPlayback = { id: string; // undefined if download is pending url: string | undefined; + fileName: string | undefined; type: 'incoming' | 'outgoing'; source: string | undefined; sourceServiceId: ServiceIdString | undefined; @@ -96,11 +97,13 @@ export function extractVoiceNoteForPlayback( const voiceNoteUrl = attachment.path ? getAttachmentUrlForPath(attachment.path) : undefined; + const fileName = attachment.fileName; const status = getMessagePropStatus(message, ourConversationId); return { id: message.id, url: voiceNoteUrl, + fileName, type, isPlayed: isPlayed(type, status, message.readStatus), messageIdForLogging: getMessageIdForLogging(message), diff --git a/ts/state/smart/MiniPlayer.tsx b/ts/state/smart/MiniPlayer.tsx index 34a76bbb9d..7dd97f3aa3 100644 --- a/ts/state/smart/MiniPlayer.tsx +++ b/ts/state/smart/MiniPlayer.tsx @@ -41,6 +41,9 @@ export function SmartMiniPlayer({ shouldFlow }: Props): JSX.Element | null { const url = AudioPlayerContent.isVoiceNote(content) ? content.current.url : content.url; + const fileName = AudioPlayerContent.isVoiceNote(content) + ? content.current.fileName + : undefined let state = PlayerState.loading; if (url) { @@ -55,6 +58,7 @@ export function SmartMiniPlayer({ shouldFlow }: Props): JSX.Element | null { ? i18n('icu:you') : getVoiceNoteTitle(content.current) } + fileName={fileName} onPlay={handlePlay} onPause={handlePause} onPlaybackRate={setPlaybackRate} diff --git a/ts/util/attachments.ts b/ts/util/attachments.ts index 4e08af029b..e01a02112e 100644 --- a/ts/util/attachments.ts +++ b/ts/util/attachments.ts @@ -111,3 +111,35 @@ export function copyCdnFields( plaintextHash: uploaded.plaintextHash, }; } +/** + * Shortens a file name based on specified conditions. + * @param fileName - The original file name. + * @param isPlaying - If true, truncate the file name to maxLength characters and add '...' at the end. + * - If false, show the first 15 characters, add '...', and the last 15 characters. + * @param maxLength - The maximum length of the file name (default: 30). + * @returns The shortened file name. + */ +export function shortenFileName( + fileName: string | undefined, + isPlaying: boolean = false, + maxLength: number = 30 +): string { + if (fileName === undefined) return ''; + if (fileName.length <= maxLength) { + return fileName; + } + + if (!isPlaying) { + const fileNameWithoutExtension = fileName.split('.').slice(0, -1).join('.'); + const extension = fileName.split('.').pop(); + const shortenedFileName = `${fileNameWithoutExtension.slice( + 0, + 15 + )}...${fileNameWithoutExtension.slice(-15)}`; + + return `${shortenedFileName}.${extension}`; + } else { + const truncatedFileName = `${fileName.slice(0, maxLength - 3)}...`; + return truncatedFileName; + } +}