diff --git a/ts/components/conversation/media-gallery/DocumentListItem.tsx b/ts/components/conversation/media-gallery/DocumentListItem.tsx index b5d6394038..b8e83bcec9 100644 --- a/ts/components/conversation/media-gallery/DocumentListItem.tsx +++ b/ts/components/conversation/media-gallery/DocumentListItem.tsx @@ -4,7 +4,7 @@ import moment from 'moment'; import formatFileSize from 'filesize'; interface Props { - fileName?: string; + fileName?: string | null; fileSize?: number; i18n: (key: string, values?: Array) => string; onClick?: () => void; diff --git a/ts/test/types/Attachment_test.ts b/ts/test/types/Attachment_test.ts index cdb671eed6..49e1621e3a 100644 --- a/ts/test/types/Attachment_test.ts +++ b/ts/test/types/Attachment_test.ts @@ -6,6 +6,7 @@ import { assert } from 'chai'; import * as Attachment from '../../types/Attachment'; import * as MIME from '../../types/MIME'; +import { signalservice as SignalService } from '../../protobuf/SignalService'; // @ts-ignore import { stringToArrayBuffer } from '../../../js/modules/string_to_array_buffer'; @@ -57,4 +58,34 @@ describe('Attachment', () => { }); }); }); + + describe('isVoiceMessage', () => { + it('should return true for voice message attachment', () => { + const attachment: Attachment.Attachment = { + fileName: 'Voice Message.aac', + flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE, + data: stringToArrayBuffer('voice message'), + contentType: MIME.AUDIO_AAC, + }; + assert.isTrue(Attachment.isVoiceMessage(attachment)); + }); + + it('should return true for legacy Android voice message attachment', () => { + const attachment: Attachment.Attachment = { + fileName: null, + data: stringToArrayBuffer('voice message'), + contentType: MIME.AUDIO_MP3, + }; + assert.isTrue(Attachment.isVoiceMessage(attachment)); + }); + + it('should return false for other attachments', () => { + const attachment: Attachment.Attachment = { + fileName: 'foo.gif', + data: stringToArrayBuffer('foo'), + contentType: MIME.IMAGE_GIF, + }; + assert.isFalse(Attachment.isVoiceMessage(attachment)); + }); + }); }); diff --git a/ts/types/Attachment.ts b/ts/types/Attachment.ts index fccc9962d4..6ed7f54234 100644 --- a/ts/types/Attachment.ts +++ b/ts/types/Attachment.ts @@ -5,9 +5,11 @@ import * as GoogleChrome from '../util/GoogleChrome'; import { saveURLAsFile } from '../util/saveURLAsFile'; import { arrayBufferToObjectURL } from '../util/arrayBufferToObjectURL'; import * as MIME from './MIME'; +import { signalservice as SignalService } from '../protobuf/SignalService'; export type Attachment = { - fileName?: string; + fileName?: string | null; + flags?: SignalService.AttachmentPointer.Flags; contentType?: MIME.MIMEType; size?: number; data: ArrayBuffer; @@ -20,7 +22,6 @@ export type Attachment = { // thumbnail?: ArrayBuffer; // key?: ArrayBuffer; // digest?: ArrayBuffer; - // flags?: number; } & Partial; interface AttachmentSchemaVersion3 { @@ -39,6 +40,26 @@ export const isVisualMedia = (attachment: Attachment): boolean => { return isSupportedImageType || isSupportedVideoType; }; +export const isVoiceMessage = (attachment: Attachment): boolean => { + const flag = SignalService.AttachmentPointer.Flags.VOICE_MESSAGE; + const hasFlag = + // tslint:disable-next-line no-bitwise + !is.undefined(attachment.flags) && (attachment.flags & flag) === flag; + if (hasFlag) { + return true; + } + + const isLegacyAndroidVoiceMessage = + !is.undefined(attachment.contentType) && + MIME.isAudio(attachment.contentType) && + attachment.fileName === null; + if (isLegacyAndroidVoiceMessage) { + return true; + } + + return false; +}; + export const save = ({ attachment, document, diff --git a/ts/types/MIME.ts b/ts/types/MIME.ts index 60dd011558..c2cc66ac58 100644 --- a/ts/types/MIME.ts +++ b/ts/types/MIME.ts @@ -1,6 +1,8 @@ export type MIMEType = string & { _mimeTypeBrand: any }; export const APPLICATION_OCTET_STREAM = 'application/octet-stream' as MIMEType; +export const AUDIO_AAC = 'audio/aac' as MIMEType; +export const AUDIO_MP3 = 'audio/mp3' as MIMEType; export const IMAGE_GIF = 'image/gif' as MIMEType; export const IMAGE_JPEG = 'image/jpeg' as MIMEType; export const VIDEO_QUICKTIME = 'video/quicktime' as MIMEType; @@ -9,4 +11,3 @@ export const isJPEG = (value: MIMEType): boolean => value === 'image/jpeg'; export const isImage = (value: MIMEType): boolean => value.startsWith('image/'); export const isVideo = (value: MIMEType): boolean => value.startsWith('video/'); export const isAudio = (value: MIMEType): boolean => value.startsWith('audio/'); -