// tslint:disable:react-this-binding-issue import React, { useState } from 'react'; import classNames from 'classnames'; import * as MIME from '../../../ts/types/MIME'; import * as GoogleChrome from '../../../ts/util/GoogleChrome'; import { MessageBody } from './MessageBody'; import { ColorType, LocalizerType } from '../../types/Util'; import { ContactName } from './ContactName'; import { PubKey } from '../../session/types'; import { ConversationTypeEnum } from '../../models/conversation'; import { useEncryptedFileFetch } from '../../hooks/useEncryptedFileFetch'; interface QuoteProps { attachment?: QuotedAttachmentType; authorPhoneNumber: string; authorProfileName?: string; authorName?: string; i18n: LocalizerType; isFromMe: boolean; isIncoming: boolean; conversationType: ConversationTypeEnum; convoId: string; isPublic?: boolean; withContentAbove: boolean; onClick?: (e: any) => void; text: string; referencedMessageNotFound: boolean; } export interface QuotedAttachmentType { contentType: MIME.MIMEType; fileName: string; /** Not included in protobuf */ isVoiceMessage: boolean; thumbnail?: Attachment; } interface Attachment { contentType: MIME.MIMEType; /** Not included in protobuf, and is loaded asynchronously */ objectUrl?: string; } function validateQuote(quote: QuoteProps): boolean { if (quote.text) { return true; } if (quote.attachment) { return true; } return false; } function getObjectUrl(thumbnail: Attachment | undefined): string | undefined { if (thumbnail && thumbnail.objectUrl) { return thumbnail.objectUrl; } return; } function getTypeLabel({ i18n, contentType, isVoiceMessage, }: { i18n: LocalizerType; contentType: MIME.MIMEType; isVoiceMessage: boolean; }): string | undefined { if (GoogleChrome.isVideoTypeSupported(contentType)) { return i18n('video'); } if (GoogleChrome.isImageTypeSupported(contentType)) { return i18n('photo'); } if (MIME.isAudio(contentType) && isVoiceMessage) { return i18n('voiceMessage'); } if (MIME.isAudio(contentType)) { return i18n('audio'); } return; } export const QuoteIcon = (props: any) => { const { icon } = props; return (
); }; export const QuoteImage = (props: any) => { const { url, i18n, icon, contentType, handleImageErrorBound } = props; const { loading, urlToLoad } = useEncryptedFileFetch(url, contentType); const srcData = !loading ? urlToLoad : ''; const iconElement = icon ? (
) : null; return (
{i18n('quoteThumbnailAlt')} {iconElement}
); }; export const QuoteGenericFile = (props: any) => { const { attachment, isIncoming } = props; if (!attachment) { return <>; } const { fileName, contentType } = attachment; const isGenericFile = !GoogleChrome.isVideoTypeSupported(contentType) && !GoogleChrome.isImageTypeSupported(contentType) && !MIME.isAudio(contentType); if (!isGenericFile) { return <>; } return (
{fileName}
); }; export const QuoteIconContainer = (props: any) => { const { attachment, i18n, imageBroken, handleImageErrorBound } = props; if (!attachment) { return null; } const { contentType, thumbnail } = attachment; const objectUrl = getObjectUrl(thumbnail); if (GoogleChrome.isVideoTypeSupported(contentType)) { return objectUrl && !imageBroken ? ( ) : ( ); } if (GoogleChrome.isImageTypeSupported(contentType)) { return objectUrl && !imageBroken ? ( ) : ( ); } if (MIME.isAudio(contentType)) { return ; } return null; }; export const QuoteText = (props: any) => { const { i18n, text, attachment, isIncoming, conversationType, convoId } = props; const isGroup = conversationType === ConversationTypeEnum.GROUP; if (text) { return (
); } if (!attachment) { return null; } const { contentType, isVoiceMessage } = attachment; const typeLabel = getTypeLabel({ i18n, contentType, isVoiceMessage }); if (typeLabel) { return (
{typeLabel}
); } return null; }; export const QuoteAuthor = (props: any) => { const { authorProfileName, authorPhoneNumber, authorName, i18n, isFromMe, isIncoming, isPublic, } = props; return (
{isFromMe ? ( i18n('you') ) : ( )}
); }; export const QuoteReferenceWarning = (props: any) => { const { i18n, isIncoming, referencedMessageNotFound } = props; if (!referencedMessageNotFound) { return null; } return (
{i18n('originalMessageNotFound')}
); }; export const Quote = (props: QuoteProps) => { const [imageBroken, setImageBroken] = useState(false); const handleImageErrorBound = null; const handleImageError = () => { // tslint:disable-next-line no-console console.log('Message: Image failed to load; failing over to placeholder'); setImageBroken(true); }; const { isIncoming, onClick, referencedMessageNotFound, withContentAbove } = props; if (!validateQuote(props)) { return null; } return ( <>
); };