[IMPROVEMENT] Message Touchable (#2082)

* [FIX] Avatar touchable

* [IMPROVEMENT] onLongPress on all Message Touchables

* [IMPROVEMENT] User & baseUrl on MessageContext

* [FIX] Context Access

* [FIX] BaseURL

* Fix User

Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
Djorkaeff Alexandre 2020-04-30 17:05:59 -03:00 committed by GitHub
parent 2ea6d34fd1
commit e46ee13b38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 3831 additions and 4271 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2,12 +2,13 @@ import React from 'react';
import PropTypes from 'prop-types';
import { View } from 'react-native';
import FastImage from 'react-native-fast-image';
import Touchable from 'react-native-platform-touchable';
import { settings as RocketChatSettings } from '@rocket.chat/sdk';
import Touch from '../utils/touch';
import { avatarURL } from '../utils/avatar';
const Avatar = React.memo(({
text, size, baseUrl, borderRadius, style, avatar, type, children, userId, token, onPress, theme
text, size, baseUrl, borderRadius, style, avatar, type, children, userId, token, onPress
}) => {
const avatarStyle = {
width: size,
@ -36,9 +37,9 @@ const Avatar = React.memo(({
if (onPress) {
image = (
<Touch onPress={onPress} theme={theme}>
<Touchable onPress={onPress}>
{image}
</Touch>
</Touchable>
);
}
@ -61,7 +62,6 @@ Avatar.propTypes = {
children: PropTypes.object,
userId: PropTypes.string,
token: PropTypes.string,
theme: PropTypes.string,
onPress: PropTypes.func
};

View File

@ -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 <Image key={file.image_url} file={file} user={user} baseUrl={baseUrl} showAttachment={showAttachment} getCustomEmoji={getCustomEmoji} theme={theme} />;
return <Image key={file.image_url} file={file} showAttachment={showAttachment} getCustomEmoji={getCustomEmoji} theme={theme} />;
}
if (file.audio_url) {
return <Audio key={file.audio_url} file={file} user={user} baseUrl={baseUrl} getCustomEmoji={getCustomEmoji} theme={theme} />;
return <Audio key={file.audio_url} file={file} getCustomEmoji={getCustomEmoji} theme={theme} />;
}
if (file.video_url) {
return <Video key={file.video_url} file={file} user={user} baseUrl={baseUrl} showAttachment={showAttachment} getCustomEmoji={getCustomEmoji} theme={theme} />;
return <Video key={file.video_url} file={file} showAttachment={showAttachment} getCustomEmoji={getCustomEmoji} theme={theme} />;
}
// eslint-disable-next-line react/no-array-index-key
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} user={user} baseUrl={baseUrl} getCustomEmoji={getCustomEmoji} theme={theme} />;
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} theme={theme} />;
});
}, (prevProps, nextProps) => isEqual(prevProps.attachments, nextProps.attachments) && prevProps.theme === nextProps.theme);
Attachments.propTypes = {
attachments: PropTypes.array,
timeFormat: PropTypes.string,
user: PropTypes.object,
baseUrl: PropTypes.string,
showAttachment: PropTypes.func,
getCustomEmoji: PropTypes.func,
theme: PropTypes.string

View File

@ -7,14 +7,15 @@ import { Audio } from 'expo-av';
import Slider from '@react-native-community/slider';
import moment from 'moment';
import equal from 'deep-equal';
import Touchable from 'react-native-platform-touchable';
import Touchable from './Touchable';
import Markdown from '../markdown';
import { CustomIcon } from '../../lib/Icons';
import sharedStyles from '../../views/Styles';
import { themes } from '../../constants/colors';
import { isAndroid, isIOS } from '../../utils/deviceInfo';
import { withSplit } from '../../split';
import MessageContext from './Context';
import ActivityIndicator from '../ActivityIndicator';
const mode = {
@ -91,10 +92,10 @@ Button.propTypes = {
Button.displayName = 'MessageAudioButton';
class MessageAudio extends React.Component {
static contextType = MessageContext;
static propTypes = {
file: PropTypes.object.isRequired,
baseUrl: PropTypes.string.isRequired,
user: PropTypes.object.isRequired,
theme: PropTypes.string,
split: PropTypes.bool,
getCustomEmoji: PropTypes.func
@ -102,13 +103,11 @@ class MessageAudio extends React.Component {
constructor(props) {
super(props);
const { baseUrl, file, user } = props;
this.state = {
loading: false,
currentTime: 0,
duration: 0,
paused: true,
uri: `${ baseUrl }${ file.audio_url }?rc_uid=${ user.id }&rc_token=${ user.token }`
paused: true
};
this.sound = new Audio.Sound();
@ -116,12 +115,13 @@ class MessageAudio extends React.Component {
}
async componentDidMount() {
const { uri } = this.state;
const { file } = this.props;
const { baseUrl, user } = this.context;
this.setState({ loading: true });
try {
await Audio.setAudioModeAsync(mode);
await this.sound.loadAsync({ uri });
await this.sound.loadAsync({ uri: `${ baseUrl }${ file.audio_url }?rc_uid=${ user.id }&rc_token=${ user.token }` });
} catch {
// Do nothing
}
@ -130,7 +130,7 @@ class MessageAudio extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
const {
currentTime, duration, paused, uri, loading
currentTime, duration, paused, loading
} = this.state;
const { file, split, theme } = this.props;
if (nextProps.theme !== theme) {
@ -145,9 +145,6 @@ class MessageAudio extends React.Component {
if (nextState.paused !== paused) {
return true;
}
if (nextState.uri !== uri) {
return true;
}
if (!equal(nextProps.file, file)) {
return true;
}
@ -237,9 +234,10 @@ class MessageAudio extends React.Component {
loading, paused, currentTime, duration
} = this.state;
const {
user, baseUrl, file, getCustomEmoji, split, theme
file, getCustomEmoji, split, theme
} = this.props;
const { description } = file;
const { baseUrl, user } = this.context;
if (!baseUrl) {
return null;

View File

@ -1,17 +1,19 @@
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 { BUTTON_HIT_SLOP } from './utils';
import I18n from '../../i18n';
import { themes } from '../../constants/colors';
import MessageContext from './Context';
const Broadcast = React.memo(({
author, user, broadcast, replyBroadcast, theme
author, broadcast, theme
}) => {
const { user, replyBroadcast } = useContext(MessageContext);
const isOwn = author._id === user.id;
if (broadcast && !isOwn) {
return (
@ -36,10 +38,8 @@ const Broadcast = React.memo(({
Broadcast.propTypes = {
author: PropTypes.object,
user: PropTypes.object,
broadcast: PropTypes.bool,
theme: PropTypes.string,
replyBroadcast: PropTypes.func
theme: PropTypes.string
};
Broadcast.displayName = 'MessageBroadcast';

View File

@ -1,8 +1,8 @@
import React 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 { formatLastMessage, BUTTON_HIT_SLOP } from './utils';
import styles from './styles';
import I18n from '../../i18n';

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useContext } from 'react';
import { Text, View } from 'react-native';
import PropTypes from 'prop-types';
import equal from 'deep-equal';
@ -8,6 +8,7 @@ import styles from './styles';
import Markdown from '../markdown';
import { getInfoMessage } from './utils';
import { themes } from '../../constants/colors';
import MessageContext from './Context';
const Content = React.memo((props) => {
if (props.isInfo) {
@ -26,12 +27,13 @@ const Content = React.memo((props) => {
if (props.tmid && !props.msg) {
content = <Text style={[styles.text, { color: themes[props.theme].bodyText }]}>{I18n.t('Sent_an_attachment')}</Text>;
} else {
const { baseUrl, user } = useContext(MessageContext);
content = (
<Markdown
msg={props.msg}
baseUrl={props.baseUrl}
baseUrl={baseUrl}
getCustomEmoji={props.getCustomEmoji}
username={props.user.username}
username={user.username}
isEdited={props.isEdited}
numberOfLines={(props.tmid && !props.isThreadRoom) ? 1 : 0}
preview={props.tmid && !props.isThreadRoom}
@ -77,8 +79,6 @@ Content.propTypes = {
msg: PropTypes.string,
theme: PropTypes.string,
isEdited: PropTypes.bool,
baseUrl: PropTypes.string,
user: PropTypes.object,
getCustomEmoji: PropTypes.func,
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),

View File

@ -0,0 +1,4 @@
import React from 'react';
const MessageContext = React.createContext();
export default MessageContext;

View File

@ -1,20 +1,22 @@
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 { formatLastMessage, formatMessageCount, BUTTON_HIT_SLOP } from './utils';
import styles from './styles';
import I18n from '../../i18n';
import { CustomIcon } from '../../lib/Icons';
import { DISCUSSION } from './constants';
import { themes } from '../../constants/colors';
import MessageContext from './Context';
const Discussion = React.memo(({
msg, dcount, dlm, onDiscussionPress, theme
msg, dcount, dlm, theme
}) => {
const time = formatLastMessage(dlm);
const buttonText = formatMessageCount(dcount, DISCUSSION);
const { onDiscussionPress } = useContext(MessageContext);
return (
<>
<Text style={[styles.startedDiscussion, { color: themes[theme].auxiliaryText }]}>{I18n.t('Started_discussion')}</Text>
@ -55,8 +57,7 @@ Discussion.propTypes = {
msg: PropTypes.string,
dcount: PropTypes.number,
dlm: PropTypes.string,
theme: PropTypes.string,
onDiscussionPress: PropTypes.func
theme: PropTypes.string
};
Discussion.displayName = 'MessageDiscussion';

View File

@ -1,13 +1,15 @@
import React from 'react';
import React, { useContext } from 'react';
import { Text } from 'react-native';
import PropTypes from 'prop-types';
import shortnameToUnicode from '../../utils/shortnameToUnicode';
import CustomEmoji from '../EmojiPicker/CustomEmoji';
import MessageContext from './Context';
const Emoji = React.memo(({
content, standardEmojiStyle, customEmojiStyle, baseUrl, getCustomEmoji
content, standardEmojiStyle, customEmojiStyle, getCustomEmoji
}) => {
const { baseUrl } = useContext(MessageContext);
const parsedContent = content.replace(/^:|:$/g, '');
const emoji = getCustomEmoji(parsedContent);
if (emoji) {
@ -20,7 +22,6 @@ Emoji.propTypes = {
content: PropTypes.string,
standardEmojiStyle: PropTypes.object,
customEmojiStyle: PropTypes.object,
baseUrl: PropTypes.string,
getCustomEmoji: PropTypes.func
};
Emoji.displayName = 'MessageEmoji';

View File

@ -1,18 +1,19 @@
import React from 'react';
import React, { useContext } from 'react';
import { View } from 'react-native';
import PropTypes from 'prop-types';
import FastImage from 'react-native-fast-image';
import equal from 'deep-equal';
import Touchable from 'react-native-platform-touchable';
import { createImageProgress } from 'react-native-image-progress';
import * as Progress from 'react-native-progress';
import Touchable from './Touchable';
import Markdown from '../markdown';
import styles from './styles';
import { formatAttachmentUrl } from '../../lib/utils';
import { withSplit } from '../../split';
import { themes } from '../../constants/colors';
import sharedStyles from '../../views/Styles';
import MessageContext from './Context';
const ImageProgress = createImageProgress(FastImage);
@ -41,8 +42,9 @@ export const MessageImage = React.memo(({ img, theme }) => (
));
const ImageContainer = React.memo(({
file, imageUrl, baseUrl, user, showAttachment, getCustomEmoji, split, theme
file, imageUrl, showAttachment, getCustomEmoji, split, theme
}) => {
const { baseUrl, user } = useContext(MessageContext);
const img = imageUrl || formatAttachmentUrl(file.image_url, user.id, user.token, baseUrl);
if (!img) {
return null;
@ -71,8 +73,6 @@ const ImageContainer = React.memo(({
ImageContainer.propTypes = {
file: PropTypes.object,
imageUrl: PropTypes.string,
baseUrl: PropTypes.string,
user: PropTypes.object,
showAttachment: PropTypes.func,
theme: PropTypes.string,
getCustomEmoji: PropTypes.func,

View File

@ -1,8 +1,10 @@
import React from 'react';
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { View } from 'react-native';
import Touchable from 'react-native-platform-touchable';
import MessageContext from './Context';
import User from './User';
import styles from './styles';
import RepliedThread from './RepliedThread';
@ -111,10 +113,11 @@ const MessageTouchable = React.memo((props) => {
</View>
);
}
const { onPress, onLongPress } = useContext(MessageContext);
return (
<Touchable
onLongPress={props.onLongPress}
onPress={props.onPress}
onLongPress={onLongPress}
onPress={onPress}
disabled={props.isInfo || props.archived || props.isTemp}
>
<View>
@ -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

View File

@ -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 (
<TouchableOpacity
onPress={() => navToRoomInfo(navParam)}
disabled={author._id === user.id}
>
<Avatar
style={small ? styles.avatarSmall : styles.avatar}
text={avatar ? '' : author.username}
size={small ? 20 : 36}
borderRadius={small ? 2 : 4}
onPress={author._id === user.id ? undefined : () => navToRoomInfo(navParam)}
avatar={avatar}
baseUrl={baseUrl}
userId={user.id}
token={user.token}
/>
</TouchableOpacity>
);
}
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
};

View File

@ -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 (
<Touchable onPress={onErrorPress} style={styles.errorButton} hitSlop={BUTTON_HIT_SLOP}>
<CustomIcon name='warning' color={themes[theme].dangerColor} size={18} />
@ -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';

View File

@ -1,16 +1,19 @@
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 (
<Touchable
onPress={reactionInit}
key='message-add-reaction'
@ -23,11 +26,15 @@ const AddReaction = React.memo(({ reactionInit, theme }) => (
<CustomIcon name='add-reaction' size={21} color={themes[theme].tintColor} />
</View>
</Touchable>
));
);
});
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 (
<Touchable
@ -54,7 +61,7 @@ const Reaction = React.memo(({
});
const Reactions = React.memo(({
reactions, user, baseUrl, onReactionPress, reactionInit, onReactionLongPress, getCustomEmoji, theme
reactions, getCustomEmoji, theme
}) => {
if (!Array.isArray(reactions) || reactions.length === 0) {
return null;
@ -65,25 +72,17 @@ const Reactions = React.memo(({
<Reaction
key={reaction.emoji}
reaction={reaction}
user={user}
baseUrl={baseUrl}
onReactionLongPress={onReactionLongPress}
onReactionPress={onReactionPress}
getCustomEmoji={getCustomEmoji}
theme={theme}
/>
))}
<AddReaction reactionInit={reactionInit} theme={theme} />
<AddReaction theme={theme} />
</View>
);
});
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';

View File

@ -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 (
<Markdown
msg={text}
@ -124,11 +126,12 @@ const Fields = React.memo(({ attachment, theme }) => {
}, (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(({
<Description
attachment={attachment}
timeFormat={timeFormat}
baseUrl={baseUrl}
user={user}
getCustomEmoji={getCustomEmoji}
theme={theme}
/>
@ -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
};

View File

@ -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 (
<Touchable
onLongPress={onLongPress}
{...props}
>
{children}
</Touchable>
);
});
RCTouchable.propTypes = {
children: PropTypes.node
};
RCTouchable.Ripple = (...args) => Touchable.Ripple(...args);
RCTouchable.SelectableBackgroundBorderless = () => Touchable.SelectableBackgroundBorderless();
export default RCTouchable;

View File

@ -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 <FastImage source={{ uri: image }} style={styles.image} resizeMode={FastImage.resizeMode.cover} />;
}, (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)}
>
<>
<UrlImage image={url.image} user={user} baseUrl={baseUrl} />
<UrlImage image={url.image} />
<UrlContent title={url.title} description={url.description} theme={theme} />
</>
</Touchable>
@ -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) => (
<Url url={url} key={url.url} index={index} user={user} baseUrl={baseUrl} split={split} theme={theme} />
<Url url={url} key={url.url} index={index} split={split} theme={theme} />
));
}, (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
};

View File

@ -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 ? (<Text style={[styles.alias, { color: themes[theme].auxiliaryText }]}> @{username}</Text>) : null;
const time = moment(ts).format(timeFormat);
@ -49,15 +51,14 @@ const User = React.memo(({
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.titleContainer}
onPress={() => navToRoomInfo(navParam)}
disabled={author._id === user.id}
>
<View style={styles.titleContainer}>
<Text style={[styles.username, { color: themes[theme].titleText }]} numberOfLines={1}>
{alias || username}
{aliasUsername}
</Text>
</View>
</TouchableOpacity>
<Text style={[messageStyles.time, { color: themes[theme].auxiliaryText }]}>{time}</Text>
{ hasError && <MessageError hasError={hasError} theme={theme} {...props} /> }
@ -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';

View File

@ -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

View File

@ -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,6 +241,20 @@ class MessageContainer extends React.Component {
}
return (
<MessageContext.Provider
value={{
user,
baseUrl,
onPress: this.onPress,
onLongPress: this.onLongPress,
reactionInit: this.reactionInit,
onErrorPress: this.onErrorPress,
replyBroadcast: this.replyBroadcast,
onReactionPress: this.onReactionPress,
onDiscussionPress: this.onDiscussionPress,
onReactionLongPress: this.onReactionLongPress
}}
>
<Message
id={id}
msg={message}
@ -253,13 +268,11 @@ class MessageContainer extends React.Component {
reactions={reactions}
alias={alias}
avatar={avatar}
user={user}
timeFormat={timeFormat}
customThreadTimeFormat={customThreadTimeFormat}
style={style}
archived={archived}
broadcast={broadcast}
baseUrl={baseUrl}
useRealName={useRealName}
isReadReceiptEnabled={isReadReceiptEnabled}
unread={unread}
@ -282,14 +295,6 @@ class MessageContainer extends React.Component {
isInfo={this.isInfo}
isTemp={this.isTemp}
hasError={this.hasError}
onErrorPress={this.onErrorPress}
onPress={this.onPress}
onLongPress={this.onLongPress}
onReactionLongPress={this.onReactionLongPress}
onReactionPress={this.onReactionPress}
replyBroadcast={this.replyBroadcast}
reactionInit={this.reactionInit}
onDiscussionPress={this.onDiscussionPress}
showAttachment={showAttachment}
getCustomEmoji={getCustomEmoji}
navToRoomInfo={navToRoomInfo}
@ -297,6 +302,7 @@ class MessageContainer extends React.Component {
blockAction={blockAction}
theme={theme}
/>
</MessageContext.Provider>
);
}
}

View File

@ -37,7 +37,6 @@ const RoomHeaderLeft = ({
style={styles.avatar}
userId={userId}
token={token}
theme={theme}
onPress={goRoomActionsView}
/>
);

View File

@ -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,6 +42,20 @@ const getCustomEmoji = (content) => {
};
const Message = props => (
<MessageContext.Provider
value={{
user,
baseUrl,
onPress: () => {},
onLongPress: () => {},
reactionInit: () => {},
onErrorPress: () => {},
replyBroadcast: () => {},
onReactionPress: () => {},
onDiscussionPress: () => {},
onReactionLongPress: () => {}
}}
>
<MessageComponent
baseUrl={baseUrl}
user={user}
@ -52,6 +67,7 @@ const Message = props => (
theme={_theme}
{...props}
/>
</MessageContext.Provider>
);
// eslint-disable-next-line react/prop-types