import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { View, Text, ViewPropTypes, Image as ImageRN, TouchableWithoutFeedback } from 'react-native'; import Icon from 'react-native-vector-icons/MaterialIcons'; import moment from 'moment'; import { KeyboardUtils } from 'react-native-keyboard-input'; import { State, RectButton, LongPressGestureHandler, BorderlessButton } from 'react-native-gesture-handler'; import Image from './Image'; import User from './User'; import Avatar from '../Avatar'; import Audio from './Audio'; import Video from './Video'; import Markdown from './Markdown'; import Url from './Url'; import Reply from './Reply'; import ReactionsModal from './ReactionsModal'; import Emoji from './Emoji'; import styles from './styles'; import I18n from '../../i18n'; import messagesStatus from '../../constants/messagesStatus'; const SYSTEM_MESSAGES = [ 'r', 'au', 'ru', 'ul', 'uj', 'rm', 'user-muted', 'user-unmuted', 'message_pinned', 'subscription-role-added', 'subscription-role-removed', 'room_changed_description', 'room_changed_announcement', 'room_changed_topic', 'room_changed_privacy', 'message_snippeted' ]; const getInfoMessage = ({ type, role, msg, author }) => { const { username } = author; if (type === 'rm') { return I18n.t('Message_removed'); } else if (type === 'uj') { return I18n.t('Has_joined_the_channel'); } else if (type === 'r') { return I18n.t('Room_name_changed', { name: msg, userBy: username }); } else if (type === 'message_pinned') { return I18n.t('Message_pinned'); } else if (type === 'ul') { return I18n.t('Has_left_the_channel'); } else if (type === 'ru') { return I18n.t('User_removed_by', { userRemoved: msg, userBy: username }); } else if (type === 'au') { return I18n.t('User_added_by', { userAdded: msg, userBy: username }); } else if (type === 'user-muted') { return I18n.t('User_muted_by', { userMuted: msg, userBy: username }); } else if (type === 'user-unmuted') { return I18n.t('User_unmuted_by', { userUnmuted: msg, userBy: username }); } else if (type === 'subscription-role-added') { return `${ msg } was set ${ role } by ${ username }`; } else if (type === 'subscription-role-removed') { return `${ msg } is no longer ${ role } by ${ username }`; } else if (type === 'room_changed_description') { return I18n.t('Room_changed_description', { description: msg, userBy: username }); } else if (type === 'room_changed_announcement') { return I18n.t('Room_changed_announcement', { announcement: msg, userBy: username }); } else if (type === 'room_changed_topic') { return I18n.t('Room_changed_topic', { topic: msg, userBy: username }); } else if (type === 'room_changed_privacy') { return I18n.t('Room_changed_privacy', { type: msg, userBy: username }); } else if (type === 'message_snippeted') { return I18n.t('Created_snippet'); } return ''; }; export default class Message extends PureComponent { static propTypes = { baseUrl: PropTypes.string.isRequired, customEmojis: PropTypes.object.isRequired, timeFormat: PropTypes.string.isRequired, msg: PropTypes.string, user: PropTypes.shape({ id: PropTypes.string.isRequired, username: PropTypes.string.isRequired, token: PropTypes.string.isRequired }), author: PropTypes.shape({ _id: PropTypes.string.isRequired, username: PropTypes.string.isRequired, name: PropTypes.string }), status: PropTypes.any, reactions: PropTypes.any, editing: PropTypes.bool, style: ViewPropTypes.style, archived: PropTypes.bool, broadcast: PropTypes.bool, reactionsModal: PropTypes.bool, type: PropTypes.string, header: PropTypes.bool, avatar: PropTypes.string, alias: PropTypes.string, ts: PropTypes.oneOfType([ PropTypes.instanceOf(Date), PropTypes.string ]), edited: PropTypes.bool, attachments: PropTypes.oneOfType([ PropTypes.array, PropTypes.object ]), urls: PropTypes.oneOfType([ PropTypes.array, PropTypes.object ]), useRealName: PropTypes.bool, // methods closeReactions: PropTypes.func, onErrorPress: PropTypes.func, onLongPress: PropTypes.func, onReactionLongPress: PropTypes.func, onReactionPress: PropTypes.func, replyBroadcast: PropTypes.func, toggleReactionPicker: PropTypes.func } static defaultProps = { archived: false, broadcast: false, attachments: [], urls: [], reactions: [], onLongPress: () => {} } onPress = () => { KeyboardUtils.dismiss(); } isInfoMessage = () => { const { type } = this.props; return SYSTEM_MESSAGES.includes(type); } isOwn = () => { const { author, user } = this.props; return author._id === user.id; } isDeleted() { const { type } = this.props; return type === 'rm'; } isTemp() { const { status } = this.props; return status === messagesStatus.TEMP || status === messagesStatus.ERROR; } hasError() { const { status } = this.props; return status === messagesStatus.ERROR; } renderAvatar = () => { const { header, avatar, author, baseUrl, user } = this.props; if (header) { return ( ); } return null; } renderUsername = () => { const { header, timeFormat, author, alias, ts, useRealName } = this.props; if (header) { return ( ); } return null; } renderContent() { if (this.isInfoMessage()) { return {getInfoMessage({ ...this.props })}; } const { customEmojis, msg, baseUrl, user, edited } = this.props; return ; } renderAttachment() { const { attachments, timeFormat } = this.props; if (attachments.length === 0) { return null; } return attachments.map((file, index) => { const { user, baseUrl, customEmojis } = this.props; if (file.image_url) { return ; } if (file.audio_url) { return