Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

ChatMessage.tsx 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import React from 'react';
  2. import { Text, View, ViewStyle } from 'react-native';
  3. import { connect } from 'react-redux';
  4. import { IReduxState } from '../../../app/types';
  5. import Avatar from '../../../base/avatar/components/Avatar';
  6. import { translate } from '../../../base/i18n/functions';
  7. import Linkify from '../../../base/react/components/native/Linkify';
  8. import { isGifMessage } from '../../../gifs/functions.native';
  9. import { MESSAGE_TYPE_ERROR, MESSAGE_TYPE_LOCAL } from '../../constants';
  10. import { replaceNonUnicodeEmojis } from '../../functions';
  11. import AbstractChatMessage, { IProps } from '../AbstractChatMessage';
  12. import GifMessage from './GifMessage';
  13. import PrivateMessageButton from './PrivateMessageButton';
  14. import styles from './styles';
  15. /**
  16. * Renders a single chat message.
  17. */
  18. class ChatMessage extends AbstractChatMessage<IProps> {
  19. /**
  20. * Implements {@code Component#render}.
  21. *
  22. * @inheritdoc
  23. */
  24. render() {
  25. const { message, knocking } = this.props;
  26. const localMessage = message.messageType === MESSAGE_TYPE_LOCAL;
  27. const { privateMessage, lobbyChat } = message;
  28. // Style arrays that need to be updated in various scenarios, such as
  29. // error messages or others.
  30. const detailsWrapperStyle: ViewStyle[] = [
  31. styles.detailsWrapper as ViewStyle
  32. ];
  33. const messageBubbleStyle: ViewStyle[] = [
  34. styles.messageBubble as ViewStyle
  35. ];
  36. if (localMessage) {
  37. // This is a message sent by the local participant.
  38. // The wrapper needs to be aligned to the right.
  39. detailsWrapperStyle.push(styles.ownMessageDetailsWrapper as ViewStyle);
  40. // The bubble needs some additional styling
  41. messageBubbleStyle.push(styles.localMessageBubble);
  42. } else if (message.messageType === MESSAGE_TYPE_ERROR) {
  43. // This is a system message.
  44. // The bubble needs some additional styling
  45. messageBubbleStyle.push(styles.systemMessageBubble);
  46. } else {
  47. // This is a remote message sent by a remote participant.
  48. // The bubble needs some additional styling
  49. messageBubbleStyle.push(styles.remoteMessageBubble);
  50. }
  51. if (privateMessage) {
  52. messageBubbleStyle.push(styles.privateMessageBubble);
  53. }
  54. if (lobbyChat && !knocking) {
  55. messageBubbleStyle.push(styles.lobbyMessageBubble);
  56. }
  57. const messageText = replaceNonUnicodeEmojis(this._getMessageText());
  58. return (
  59. <View style = { styles.messageWrapper as ViewStyle } >
  60. { this._renderAvatar() }
  61. <View style = { detailsWrapperStyle }>
  62. <View style = { messageBubbleStyle }>
  63. <View style = { styles.textWrapper as ViewStyle } >
  64. { this._renderDisplayName() }
  65. { isGifMessage(messageText)
  66. ? <GifMessage message = { messageText } />
  67. : (
  68. <Linkify
  69. linkStyle = { styles.chatLink }
  70. style = { styles.chatMessage }>
  71. { messageText }
  72. </Linkify>
  73. )}
  74. { this._renderPrivateNotice() }
  75. </View>
  76. { this._renderPrivateReplyButton() }
  77. </View>
  78. { this._renderTimestamp() }
  79. </View>
  80. </View>
  81. );
  82. }
  83. /**
  84. * Renders the avatar of the sender.
  85. *
  86. * @returns {React$Element<*>}
  87. */
  88. _renderAvatar() {
  89. const { message } = this.props;
  90. return (
  91. <View style = { styles.avatarWrapper }>
  92. { this.props.showAvatar && <Avatar
  93. displayName = { message.displayName }
  94. participantId = { message.id }
  95. size = { styles.avatarWrapper.width } />
  96. }
  97. </View>
  98. );
  99. }
  100. /**
  101. * Renders the display name of the sender if necessary.
  102. *
  103. * @returns {React$Element<*> | null}
  104. */
  105. _renderDisplayName() {
  106. const { message, showDisplayName } = this.props;
  107. if (!showDisplayName) {
  108. return null;
  109. }
  110. return (
  111. <Text style = { styles.senderDisplayName }>
  112. { message.displayName }
  113. </Text>
  114. );
  115. }
  116. /**
  117. * Renders the message privacy notice, if necessary.
  118. *
  119. * @returns {React$Element<*> | null}
  120. */
  121. _renderPrivateNotice() {
  122. const { message, knocking } = this.props;
  123. if (!(message.privateMessage || (message.lobbyChat && !knocking))) {
  124. return null;
  125. }
  126. return (
  127. <Text style = { message.lobbyChat ? styles.lobbyMsgNotice : styles.privateNotice }>
  128. { this._getPrivateNoticeMessage() }
  129. </Text>
  130. );
  131. }
  132. /**
  133. * Renders the private reply button, if necessary.
  134. *
  135. * @returns {React$Element<*> | null}
  136. */
  137. _renderPrivateReplyButton() {
  138. const { message, knocking } = this.props;
  139. const { messageType, privateMessage, lobbyChat } = message;
  140. if (!(privateMessage || lobbyChat) || messageType === MESSAGE_TYPE_LOCAL || knocking) {
  141. return null;
  142. }
  143. return (
  144. <View style = { styles.replyContainer as ViewStyle }>
  145. <PrivateMessageButton
  146. isLobbyMessage = { lobbyChat }
  147. participantID = { message.id }
  148. reply = { true }
  149. showLabel = { false }
  150. toggledStyles = { styles.replyStyles } />
  151. </View>
  152. );
  153. }
  154. /**
  155. * Renders the time at which the message was sent, if necessary.
  156. *
  157. * @returns {React$Element<*> | null}
  158. */
  159. _renderTimestamp() {
  160. if (!this.props.showTimestamp) {
  161. return null;
  162. }
  163. return (
  164. <Text style = { styles.timeText }>
  165. { this._getFormattedTimestamp() }
  166. </Text>
  167. );
  168. }
  169. }
  170. /**
  171. * Maps part of the redux state to the props of this component.
  172. *
  173. * @param {Object} state - The Redux state.
  174. * @returns {IProps}
  175. */
  176. function _mapStateToProps(state: IReduxState) {
  177. return {
  178. knocking: state['features/lobby'].knocking
  179. };
  180. }
  181. export default translate(connect(_mapStateToProps)(ChatMessage));