diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index b9950e32d61..4338ff0f36b 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -3666,7 +3666,7 @@ exports[`Storyshots Message list message 1`] = ` - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - - + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + - - - diego.mello - - + diego.mello + - + Diego Mello - Diego Mello - - @ - diego.mello - + @ + diego.mello - + - + Diego Mello - Diego Mello - - @ - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - + @ + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - Diego Mello - - + Diego Mello + - - - diego.mello - - + diego.mello + - + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + Array [ + Object { + "backgroundColor": "transparent", + "fontFamily": "System", + "fontSize": 16, + "fontWeight": "500", + "lineHeight": 22, + }, + Object { + "color": "#0d0e12", + }, + ] + } + > + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + Array [ + Object { + "backgroundColor": "transparent", + "fontFamily": "System", + "fontSize": 16, + "fontWeight": "500", + "lineHeight": 22, + }, + Object { + "color": "#0d0e12", + }, + ] + } + > + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - rocket.cat - - + rocket.cat + - - - diego.mello - - + diego.mello + - - - rocket.cat - - + rocket.cat + - - - diego.mello - - + diego.mello + - - - rocket.cat - - + rocket.cat + - - - diego.mello - - + diego.mello + - - - rocket.cat - - + rocket.cat + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + - - - diego.mello - - + diego.mello + { const avatarStyle = { width: size, @@ -36,9 +37,9 @@ const Avatar = React.memo(({ if (onPress) { image = ( - + {image} - + ); } @@ -61,7 +62,6 @@ Avatar.propTypes = { children: PropTypes.object, userId: PropTypes.string, token: PropTypes.string, - theme: PropTypes.string, onPress: PropTypes.func }; diff --git a/app/containers/message/Attachments.js b/app/containers/message/Attachments.js index cf3f6106cb6..3d4ff48b4bf 100644 --- a/app/containers/message/Attachments.js +++ b/app/containers/message/Attachments.js @@ -8,7 +8,7 @@ import Video from './Video'; import Reply from './Reply'; const Attachments = React.memo(({ - attachments, timeFormat, user, baseUrl, showAttachment, getCustomEmoji, theme + attachments, timeFormat, showAttachment, getCustomEmoji, theme }) => { if (!attachments || attachments.length === 0) { return null; @@ -16,25 +16,23 @@ const Attachments = React.memo(({ return attachments.map((file, index) => { if (file.image_url) { - return ; + return ; } if (file.audio_url) { - return ); } + const { onPress, onLongPress } = useContext(MessageContext); return ( @@ -129,9 +132,7 @@ MessageTouchable.propTypes = { hasError: PropTypes.bool, isInfo: PropTypes.bool, isTemp: PropTypes.bool, - archived: PropTypes.bool, - onLongPress: PropTypes.func, - onPress: PropTypes.func + archived: PropTypes.bool }; Message.propTypes = { @@ -143,7 +144,6 @@ Message.propTypes = { hasError: PropTypes.bool, style: PropTypes.any, onLongPress: PropTypes.func, - onPress: PropTypes.func, isReadReceiptEnabled: PropTypes.bool, unread: PropTypes.bool, theme: PropTypes.string diff --git a/app/containers/message/MessageAvatar.js b/app/containers/message/MessageAvatar.js index 190bb43a8fe..0663551e6bd 100644 --- a/app/containers/message/MessageAvatar.js +++ b/app/containers/message/MessageAvatar.js @@ -1,34 +1,31 @@ -import React from 'react'; +import React, { useContext } from 'react'; import PropTypes from 'prop-types'; -import { TouchableOpacity } from 'react-native'; import Avatar from '../Avatar'; import styles from './styles'; +import MessageContext from './Context'; const MessageAvatar = React.memo(({ - isHeader, avatar, author, baseUrl, user, small, navToRoomInfo + isHeader, avatar, author, small, navToRoomInfo }) => { + const { baseUrl, user } = useContext(MessageContext); if (isHeader && author) { const navParam = { t: 'd', rid: author._id }; return ( - navToRoomInfo(navParam)} - disabled={author._id === user.id} - > - - + navToRoomInfo(navParam)} + avatar={avatar} + baseUrl={baseUrl} + userId={user.id} + token={user.token} + /> ); } return null; @@ -38,8 +35,6 @@ MessageAvatar.propTypes = { isHeader: PropTypes.bool, avatar: PropTypes.string, author: PropTypes.obj, - baseUrl: PropTypes.string, - user: PropTypes.obj, small: PropTypes.bool, navToRoomInfo: PropTypes.func }; diff --git a/app/containers/message/MessageError.js b/app/containers/message/MessageError.js index d30e409966b..b3e3969a1b0 100644 --- a/app/containers/message/MessageError.js +++ b/app/containers/message/MessageError.js @@ -1,16 +1,18 @@ -import React from 'react'; -import Touchable from 'react-native-platform-touchable'; +import React, { useContext } from 'react'; import PropTypes from 'prop-types'; +import Touchable from './Touchable'; import { CustomIcon } from '../../lib/Icons'; import styles from './styles'; import { BUTTON_HIT_SLOP } from './utils'; import { themes } from '../../constants/colors'; +import MessageContext from './Context'; -const MessageError = React.memo(({ hasError, onErrorPress, theme }) => { +const MessageError = React.memo(({ hasError, theme }) => { if (!hasError) { return null; } + const { onErrorPress } = useContext(MessageContext); return ( @@ -20,7 +22,6 @@ const MessageError = React.memo(({ hasError, onErrorPress, theme }) => { MessageError.propTypes = { hasError: PropTypes.bool, - onErrorPress: PropTypes.func, theme: PropTypes.string }; MessageError.displayName = 'MessageError'; diff --git a/app/containers/message/Reactions.js b/app/containers/message/Reactions.js index 1614b1b7a1f..6ff654221d9 100644 --- a/app/containers/message/Reactions.js +++ b/app/containers/message/Reactions.js @@ -1,33 +1,40 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { View, Text } from 'react-native'; -import Touchable from 'react-native-platform-touchable'; import PropTypes from 'prop-types'; +import Touchable from './Touchable'; import { CustomIcon } from '../../lib/Icons'; import styles from './styles'; import Emoji from './Emoji'; import { BUTTON_HIT_SLOP } from './utils'; import { themes } from '../../constants/colors'; import { withTheme } from '../../theme'; +import MessageContext from './Context'; -const AddReaction = React.memo(({ reactionInit, theme }) => ( - - - - - -)); +const AddReaction = React.memo(({ theme }) => { + const { reactionInit } = useContext(MessageContext); + return ( + + + + + + ); +}); const Reaction = React.memo(({ - reaction, user, onReactionLongPress, onReactionPress, baseUrl, getCustomEmoji, theme + reaction, getCustomEmoji, theme }) => { + const { + onReactionPress, onReactionLongPress, baseUrl, user + } = useContext(MessageContext); const reacted = reaction.usernames.findIndex(item => item === user.username) !== -1; return ( { if (!Array.isArray(reactions) || reactions.length === 0) { return null; @@ -65,25 +72,17 @@ const Reactions = React.memo(({ ))} - + ); }); Reaction.propTypes = { reaction: PropTypes.object, - user: PropTypes.object, - baseUrl: PropTypes.string, - onReactionPress: PropTypes.func, - onReactionLongPress: PropTypes.func, getCustomEmoji: PropTypes.func, theme: PropTypes.string }; @@ -91,18 +90,12 @@ Reaction.displayName = 'MessageReaction'; Reactions.propTypes = { reactions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]), - user: PropTypes.object, - baseUrl: PropTypes.string, - onReactionPress: PropTypes.func, - reactionInit: PropTypes.func, - onReactionLongPress: PropTypes.func, getCustomEmoji: PropTypes.func, theme: PropTypes.string }; Reactions.displayName = 'MessageReactions'; AddReaction.propTypes = { - reactionInit: PropTypes.func, theme: PropTypes.string }; AddReaction.displayName = 'MessageAddReaction'; diff --git a/app/containers/message/Reply.js b/app/containers/message/Reply.js index 254beba5f70..2278a90ab27 100644 --- a/app/containers/message/Reply.js +++ b/app/containers/message/Reply.js @@ -1,15 +1,16 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { View, Text, StyleSheet } from 'react-native'; import PropTypes from 'prop-types'; import moment from 'moment'; -import Touchable from 'react-native-platform-touchable'; import isEqual from 'deep-equal'; +import Touchable from './Touchable'; import Markdown from '../markdown'; import openLink from '../../utils/openLink'; import sharedStyles from '../../views/Styles'; import { themes } from '../../constants/colors'; import { withSplit } from '../../split'; +import MessageContext from './Context'; const styles = StyleSheet.create({ button: { @@ -79,12 +80,13 @@ const Title = React.memo(({ attachment, timeFormat, theme }) => { }); const Description = React.memo(({ - attachment, baseUrl, user, getCustomEmoji, theme + attachment, getCustomEmoji, theme }) => { const text = attachment.text || attachment.title; if (!text) { return null; } + const { baseUrl, user } = useContext(MessageContext); return ( { }, (prevProps, nextProps) => isEqual(prevProps.attachment.fields, nextProps.attachment.fields) && prevProps.theme === nextProps.theme); const Reply = React.memo(({ - attachment, timeFormat, baseUrl, user, index, getCustomEmoji, split, theme + attachment, timeFormat, index, getCustomEmoji, split, theme }) => { if (!attachment) { return null; } + const { baseUrl, user } = useContext(MessageContext); const onPress = () => { let url = attachment.title_link || attachment.author_link; @@ -160,8 +163,6 @@ const Reply = React.memo(({ @@ -174,8 +175,6 @@ const Reply = React.memo(({ Reply.propTypes = { attachment: PropTypes.object, timeFormat: PropTypes.string, - baseUrl: PropTypes.string, - user: PropTypes.object, index: PropTypes.number, theme: PropTypes.string, getCustomEmoji: PropTypes.func, @@ -192,8 +191,6 @@ Title.displayName = 'MessageReplyTitle'; Description.propTypes = { attachment: PropTypes.object, - baseUrl: PropTypes.string, - user: PropTypes.object, getCustomEmoji: PropTypes.func, theme: PropTypes.string }; diff --git a/app/containers/message/Touchable.js b/app/containers/message/Touchable.js new file mode 100644 index 00000000000..edd2d63e5e5 --- /dev/null +++ b/app/containers/message/Touchable.js @@ -0,0 +1,25 @@ +import React, { useContext } from 'react'; +import Touchable from 'react-native-platform-touchable'; +import PropTypes from 'prop-types'; + +import MessageContext from './Context'; + +const RCTouchable = React.memo(({ children, ...props }) => { + const { onLongPress } = useContext(MessageContext); + + return ( + + {children} + + ); +}); +RCTouchable.propTypes = { + children: PropTypes.node +}; +RCTouchable.Ripple = (...args) => Touchable.Ripple(...args); +RCTouchable.SelectableBackgroundBorderless = () => Touchable.SelectableBackgroundBorderless(); + +export default RCTouchable; diff --git a/app/containers/message/Urls.js b/app/containers/message/Urls.js index a10459e9ded..e4a2ac4e55a 100644 --- a/app/containers/message/Urls.js +++ b/app/containers/message/Urls.js @@ -1,12 +1,12 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { View, Text, StyleSheet, Clipboard } from 'react-native'; import PropTypes from 'prop-types'; import FastImage from 'react-native-fast-image'; -import Touchable from 'react-native-platform-touchable'; import isEqual from 'lodash/isEqual'; +import Touchable from './Touchable'; import openLink from '../../utils/openLink'; import sharedStyles from '../../views/Styles'; import { themes } from '../../constants/colors'; @@ -15,6 +15,7 @@ import { withSplit } from '../../split'; import { LISTENER } from '../Toast'; import EventEmitter from '../../utils/events'; import I18n from '../../i18n'; +import MessageContext from './Context'; const styles = StyleSheet.create({ button: { @@ -52,10 +53,11 @@ const styles = StyleSheet.create({ } }); -const UrlImage = React.memo(({ image, user, baseUrl }) => { +const UrlImage = React.memo(({ image }) => { if (!image) { return null; } + const { baseUrl, user } = useContext(MessageContext); image = image.includes('http') ? image : `${ baseUrl }/${ image }?rc_uid=${ user.id }&rc_token=${ user.token }`; return ; }, (prevProps, nextProps) => prevProps.image === nextProps.image); @@ -79,7 +81,7 @@ const UrlContent = React.memo(({ title, description, theme }) => ( }); const Url = React.memo(({ - url, index, user, baseUrl, split, theme + url, index, split, theme }) => { if (!url) { return null; @@ -109,7 +111,7 @@ const Url = React.memo(({ background={Touchable.Ripple(themes[theme].bannerBackground)} > <> - + @@ -117,21 +119,19 @@ const Url = React.memo(({ }, (oldProps, newProps) => isEqual(oldProps.url, newProps.url) && oldProps.split === newProps.split && oldProps.theme === newProps.theme); const Urls = React.memo(({ - urls, user, baseUrl, split, theme + urls, split, theme }) => { if (!urls || urls.length === 0) { return null; } return urls.map((url, index) => ( - + )); }, (oldProps, newProps) => isEqual(oldProps.urls, newProps.urls) && oldProps.split === newProps.split && oldProps.theme === newProps.theme); UrlImage.propTypes = { - image: PropTypes.string, - user: PropTypes.object, - baseUrl: PropTypes.string + image: PropTypes.string }; UrlImage.displayName = 'MessageUrlImage'; @@ -145,8 +145,6 @@ UrlContent.displayName = 'MessageUrlContent'; Url.propTypes = { url: PropTypes.object.isRequired, index: PropTypes.number, - user: PropTypes.object, - baseUrl: PropTypes.string, theme: PropTypes.string, split: PropTypes.bool }; @@ -154,8 +152,6 @@ Url.displayName = 'MessageUrl'; Urls.propTypes = { urls: PropTypes.array, - user: PropTypes.object, - baseUrl: PropTypes.string, theme: PropTypes.string, split: PropTypes.bool }; diff --git a/app/containers/message/User.js b/app/containers/message/User.js index 022d2a58bad..827a9b73190 100644 --- a/app/containers/message/User.js +++ b/app/containers/message/User.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import { View, Text, StyleSheet, TouchableOpacity @@ -11,6 +11,7 @@ import { withTheme } from '../../theme'; import MessageError from './MessageError'; import sharedStyles from '../../views/Styles'; import messageStyles from './styles'; +import MessageContext from './Context'; const styles = StyleSheet.create({ container: { @@ -35,13 +36,14 @@ const styles = StyleSheet.create({ }); const User = React.memo(({ - isHeader, useRealName, author, alias, ts, timeFormat, hasError, theme, navToRoomInfo, user, ...props + isHeader, useRealName, author, alias, ts, timeFormat, hasError, theme, navToRoomInfo, ...props }) => { if (isHeader || hasError) { const navParam = { t: 'd', rid: author._id }; + const { user } = useContext(MessageContext); const username = (useRealName && author.name) || author.username; const aliasUsername = alias ? ( @{username}) : null; const time = moment(ts).format(timeFormat); @@ -49,15 +51,14 @@ const User = React.memo(({ return ( navToRoomInfo(navParam)} disabled={author._id === user.id} > - - - {alias || username} - {aliasUsername} - - + + {alias || username} + {aliasUsername} + {time} { hasError && } @@ -76,7 +77,6 @@ User.propTypes = { ts: PropTypes.instanceOf(Date), timeFormat: PropTypes.string, theme: PropTypes.string, - user: PropTypes.obj, navToRoomInfo: PropTypes.func }; User.displayName = 'MessageUser'; diff --git a/app/containers/message/Video.js b/app/containers/message/Video.js index a30c3abe881..c765702e01a 100644 --- a/app/containers/message/Video.js +++ b/app/containers/message/Video.js @@ -1,9 +1,9 @@ -import React from 'react'; +import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import { StyleSheet } from 'react-native'; -import Touchable from 'react-native-platform-touchable'; import isEqual from 'deep-equal'; +import Touchable from './Touchable'; import Markdown from '../markdown'; import openLink from '../../utils/openLink'; import { isIOS, isTablet } from '../../utils/deviceInfo'; @@ -11,6 +11,7 @@ import { CustomIcon } from '../../lib/Icons'; import { formatAttachmentUrl } from '../../lib/utils'; import { themes } from '../../constants/colors'; import sharedStyles from '../../views/Styles'; +import MessageContext from './Context'; const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])]; const isTypeSupported = type => SUPPORTED_TYPES.indexOf(type) !== -1; @@ -27,12 +28,12 @@ const styles = StyleSheet.create({ }); const Video = React.memo(({ - file, baseUrl, user, showAttachment, getCustomEmoji, theme + file, showAttachment, getCustomEmoji, theme }) => { + const { baseUrl, user } = useContext(MessageContext); if (!baseUrl) { return null; } - const onPress = () => { if (isTypeSupported(file.video_type)) { return showAttachment(file); @@ -61,8 +62,6 @@ const Video = React.memo(({ Video.propTypes = { file: PropTypes.object, - baseUrl: PropTypes.string, - user: PropTypes.object, showAttachment: PropTypes.func, getCustomEmoji: PropTypes.func, theme: PropTypes.string diff --git a/app/containers/message/index.js b/app/containers/message/index.js index 1a49b80f683..43559abbe84 100644 --- a/app/containers/message/index.js +++ b/app/containers/message/index.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { KeyboardUtils } from 'react-native-keyboard-input'; import Message from './Message'; +import MessageContext from './Context'; import debounce from '../../utils/debounce'; import { SYSTEM_MESSAGES, getMessageTranslation } from './utils'; import messagesStatus from '../../constants/messagesStatus'; @@ -240,63 +241,68 @@ class MessageContainer extends React.Component { } return ( - + + + ); } } diff --git a/app/views/RoomView/Header/RoomHeaderLeft.js b/app/views/RoomView/Header/RoomHeaderLeft.js index 85b8db31481..670dfd15020 100644 --- a/app/views/RoomView/Header/RoomHeaderLeft.js +++ b/app/views/RoomView/Header/RoomHeaderLeft.js @@ -37,7 +37,6 @@ const RoomHeaderLeft = ({ style={styles.avatar} userId={userId} token={token} - theme={theme} onPress={goRoomActionsView} /> ); diff --git a/storybook/stories/Message.js b/storybook/stories/Message.js index 6231aa3dff7..36920a0cb42 100644 --- a/storybook/stories/Message.js +++ b/storybook/stories/Message.js @@ -8,6 +8,7 @@ import messagesStatus from '../../app/constants/messagesStatus'; import MessageSeparator from '../../app/views/RoomView/Separator'; import { themes } from '../../app/constants/colors'; +import MessageContext from '../../app/containers/message/Context'; let _theme = 'light'; @@ -41,17 +42,32 @@ const getCustomEmoji = (content) => { }; const Message = props => ( - + {}, + onLongPress: () => {}, + reactionInit: () => {}, + onErrorPress: () => {}, + replyBroadcast: () => {}, + onReactionPress: () => {}, + onDiscussionPress: () => {}, + onReactionLongPress: () => {} + }} + > + + ); // eslint-disable-next-line react/prop-types