import React from 'react'; import { Text, View } from 'react-native'; import { Avatar } from '../../../base/avatar'; import { translate } from '../../../base/i18n'; import { Linkify } from '../../../base/react'; import { connect } from '../../../base/redux'; import { isGifMessage } from '../../../gifs/functions'; import { MESSAGE_TYPE_ERROR, MESSAGE_TYPE_LOCAL } from '../../constants'; import { replaceNonUnicodeEmojis } from '../../functions'; import AbstractChatMessage, { type Props } from '../AbstractChatMessage'; import GifMessage from './GifMessage'; import PrivateMessageButton from './PrivateMessageButton'; import styles from './styles'; /** * Renders a single chat message. */ class ChatMessage extends AbstractChatMessage { /** * Implements {@code Component#render}. * * @inheritdoc */ render() { const { message, knocking } = this.props; const localMessage = message.messageType === MESSAGE_TYPE_LOCAL; const { privateMessage, lobbyChat } = message; // Style arrays that need to be updated in various scenarios, such as // error messages or others. const detailsWrapperStyle = [ styles.detailsWrapper ]; const messageBubbleStyle = [ styles.messageBubble ]; if (localMessage) { // This is a message sent by the local participant. // The wrapper needs to be aligned to the right. detailsWrapperStyle.push(styles.ownMessageDetailsWrapper); // The bubble needs some additional styling messageBubbleStyle.push(styles.localMessageBubble); } else if (message.messageType === MESSAGE_TYPE_ERROR) { // This is a system message. // The bubble needs some additional styling messageBubbleStyle.push(styles.systemMessageBubble); } else { // This is a remote message sent by a remote participant. // The bubble needs some additional styling messageBubbleStyle.push(styles.remoteMessageBubble); } if (privateMessage) { messageBubbleStyle.push(styles.privateMessageBubble); } if (lobbyChat && !knocking) { messageBubbleStyle.push(styles.lobbyMessageBubble); } const messageText = replaceNonUnicodeEmojis(this._getMessageText()); return ( { this._renderAvatar() } { this._renderDisplayName() } { isGifMessage(messageText) ? : ( { messageText } )} { this._renderPrivateNotice() } { this._renderPrivateReplyButton() } { this._renderTimestamp() } ); } _getFormattedTimestamp: () => string; _getMessageText: () => string; _getPrivateNoticeMessage: () => string; /** * Renders the avatar of the sender. * * @returns {React$Element<*>} */ _renderAvatar() { const { message } = this.props; return ( { this.props.showAvatar && } ); } /** * Renders the display name of the sender if necessary. * * @returns {React$Element<*> | null} */ _renderDisplayName() { const { message, showDisplayName } = this.props; if (!showDisplayName) { return null; } return ( { message.displayName } ); } /** * Renders the message privacy notice, if necessary. * * @returns {React$Element<*> | null} */ _renderPrivateNotice() { const { message, knocking } = this.props; if (!(message.privateMessage || (message.lobbyChat && !knocking))) { return null; } return ( { this._getPrivateNoticeMessage() } ); } /** * Renders the private reply button, if necessary. * * @returns {React$Element<*> | null} */ _renderPrivateReplyButton() { const { message, knocking } = this.props; const { messageType, privateMessage, lobbyChat } = message; if (!(privateMessage || lobbyChat) || messageType === MESSAGE_TYPE_LOCAL || knocking) { return null; } return ( ); } /** * Renders the time at which the message was sent, if necessary. * * @returns {React$Element<*> | null} */ _renderTimestamp() { if (!this.props.showTimestamp) { return null; } return ( { this._getFormattedTimestamp() } ); } } /** * Maps part of the redux state to the props of this component. * * @param {Object} state - The Redux state. * @returns {Props} */ function _mapStateToProps(state) { return { knocking: state['features/lobby'].knocking }; } export default translate(connect(_mapStateToProps)(ChatMessage));