From 0f72bb34c2605babf275303625cd5b75d4e90d52 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Mon, 29 Jun 2020 11:28:07 -0400 Subject: [PATCH] MM-15719 Use metadata only to render post additional content (#4386) * MM-15719 Use metadata only to render post additional content * Default link to empty instead of undefined * Feedback review --- app/actions/views/channel.js | 12 --- .../file_attachment_list.js | 17 ----- .../file_attachment_list.test.js | 60 --------------- app/components/file_attachment_list/index.js | 13 +--- app/components/markdown/markdown.js | 5 ++ .../markdown/markdown_image/markdown_image.js | 12 --- .../markdown/markdown_table_image/index.js | 2 - .../markdown_table_image.js | 3 +- .../attachment_image/index.js | 8 +- .../attachment_image/index.test.js | 23 ------ .../message_attachments/message_attachment.js | 3 + .../post_attachment_opengraph/index.js | 13 +--- .../post_attachment_opengraph.js | 28 +------ app/components/post_body/post_body.js | 2 +- app/components/post_body/post_body.test.js | 16 ++++ .../post_body_additional_content/index.js | 75 +++++++------------ .../post_body_additional_content.js | 44 +++++------ app/components/reactions/index.js | 3 +- app/components/reactions/reactions.js | 8 -- app/components/reactions/reactions.test.js | 1 - app/screens/table_image/table_image.js | 24 +++--- 21 files changed, 93 insertions(+), 279 deletions(-) diff --git a/app/actions/views/channel.js b/app/actions/views/channel.js index cdf613bd1..47785d37b 100644 --- a/app/actions/views/channel.js +++ b/app/actions/views/channel.js @@ -11,7 +11,6 @@ import { getChannelByNameAndTeamName, leaveChannel as serviceLeaveChannel, } from '@mm-redux/actions/channels'; -import {getFilesForPost} from '@mm-redux/actions/files'; import {savePreferences} from '@mm-redux/actions/preferences'; import {selectTeam} from '@mm-redux/actions/teams'; import {Client4} from '@mm-redux/client'; @@ -110,17 +109,6 @@ export function fetchPostActionWithRetry(action, maxTries = MAX_RETRIES) { }; } -export function loadFilesForPostIfNecessary(postId) { - return async (dispatch, getState) => { - const {files} = getState().entities; - const fileIdsForPost = files.fileIdsByPostId[postId]; - - if (!fileIdsForPost?.length) { - await dispatch(getFilesForPost(postId)); - } - }; -} - export function loadThreadIfNecessary(rootId) { return (dispatch, getState) => { const state = getState(); diff --git a/app/components/file_attachment_list/file_attachment_list.js b/app/components/file_attachment_list/file_attachment_list.js index 48fd95e50..1837b29d2 100644 --- a/app/components/file_attachment_list/file_attachment_list.js +++ b/app/components/file_attachment_list/file_attachment_list.js @@ -17,9 +17,6 @@ const MAX_VISIBLE_ROW_IMAGES = 4; export default class FileAttachmentList extends ImageViewPort { static propTypes = { - actions: PropTypes.shape({ - loadFilesForPostIfNecessary: PropTypes.func.isRequired, - }).isRequired, canDownloadFiles: PropTypes.bool.isRequired, fileIds: PropTypes.array.isRequired, files: PropTypes.array, @@ -45,22 +42,12 @@ export default class FileAttachmentList extends ImageViewPort { }); } - componentDidMount() { - super.componentDidMount(); - const {files} = this.props; - - if (files.length === 0) { - this.loadFilesForPost(); - } - } - componentDidUpdate(prevProps) { if (prevProps.files.length !== this.props.files.length) { this.filesForGallery = this.getFilesForGallery(this.props); this.buildGalleryFiles().then((results) => { this.galleryFiles = results; }); - this.loadFilesForPost(); } } @@ -139,10 +126,6 @@ export default class FileAttachmentList extends ImageViewPort { isSingleImage = (files) => (files.length === 1 && this.isImage(files[0])); - loadFilesForPost = async () => { - await this.props.actions.loadFilesForPostIfNecessary(this.props.postId); - } - renderItems = (items, moreImagesCount, includeGutter = false) => { const {canDownloadFiles, isReplyPost, onLongPress, theme} = this.props; const isSingleImage = this.isSingleImage(items); diff --git a/app/components/file_attachment_list/file_attachment_list.test.js b/app/components/file_attachment_list/file_attachment_list.test.js index 92bd0ceab..61cdd636f 100644 --- a/app/components/file_attachment_list/file_attachment_list.test.js +++ b/app/components/file_attachment_list/file_attachment_list.test.js @@ -11,8 +11,6 @@ jest.mock('react-native-file-viewer', () => ({ })); describe('FileAttachmentList', () => { - const loadFilesForPostIfNecessary = jest.fn().mockImplementationOnce(() => Promise.resolve({data: {}})); - const files = [{ create_at: 1546893090093, delete_at: 0, @@ -55,9 +53,6 @@ describe('FileAttachmentList', () => { }; const baseProps = { - actions: { - loadFilesForPostIfNecessary, - }, canDownloadFiles: true, deviceHeight: 680, deviceWidth: 660, @@ -162,45 +157,9 @@ describe('FileAttachmentList', () => { expect(wrapper.getElement()).toMatchSnapshot(); }); - test('should call loadFilesForPostIfNecessary when files does not exist', async () => { - const props = { - ...baseProps, - files: undefined, - }; - - shallow( - , - ); - expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledWith(props.postId); - }); - - test('should call loadFilesForPostIfNecessary on componentUpdate and when files does not exist', async () => { - const loadFilesForPostIfNecessaryMock = jest.fn().mockImplementationOnce(() => Promise.resolve({data: {}})); - const props = { - ...baseProps, - files: [], - actions: { - loadFilesForPostIfNecessary: loadFilesForPostIfNecessaryMock, - }, - }; - - shallow( - , - ); - expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledTimes(1); - expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledWith(props.postId); - await loadFilesForPostIfNecessaryMock(); - expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledTimes(2); - expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledWith(props.postId); - }); - test('should call getFilesForGallery on props change', async () => { - const loadFilesForPostIfNecessaryMock = jest.fn().mockImplementationOnce(() => Promise.resolve({data: {}})); const props = { ...baseProps, - actions: { - loadFilesForPostIfNecessary: loadFilesForPostIfNecessaryMock, - }, }; const wrapper = shallow( @@ -211,23 +170,4 @@ describe('FileAttachmentList', () => { wrapper.setProps({files: [files[0], files[1]]}); expect(wrapper.instance().getFilesForGallery).toHaveBeenCalled(); }); - - test('should call loadFilesForPostIfNecessary when files object empty', async () => { - const loadFilesForPostIfNecessaryMock = jest.fn().mockImplementationOnce(() => Promise.resolve({data: {}})); - const props = { - ...baseProps, - actions: { - loadFilesForPostIfNecessary: loadFilesForPostIfNecessaryMock, - }, - }; - - const wrapper = shallow( - , - ); - wrapper.setProps({files: []}); - expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledTimes(1); - expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledWith(props.postId); - wrapper.setProps({test: 'test'}); - expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledTimes(1); - }); }); diff --git a/app/components/file_attachment_list/index.js b/app/components/file_attachment_list/index.js index ca8025f10..dca584149 100644 --- a/app/components/file_attachment_list/index.js +++ b/app/components/file_attachment_list/index.js @@ -1,15 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; import {canDownloadFilesOnMobile} from '@mm-redux/selectors/entities/general'; import {makeGetFilesForPost} from '@mm-redux/selectors/entities/files'; import {getTheme} from '@mm-redux/selectors/entities/preferences'; -import {loadFilesForPostIfNecessary} from 'app/actions/views/channel'; - import FileAttachmentList from './file_attachment_list'; function makeMapStateToProps() { @@ -23,12 +20,4 @@ function makeMapStateToProps() { }; } -function mapDispatchToProps(dispatch) { - return { - actions: bindActionCreators({ - loadFilesForPostIfNecessary, - }, dispatch), - }; -} - -export default connect(makeMapStateToProps, mapDispatchToProps)(FileAttachmentList); +export default connect(makeMapStateToProps)(FileAttachmentList); diff --git a/app/components/markdown/markdown.js b/app/components/markdown/markdown.js index ccf1e8daa..1cf5571a4 100644 --- a/app/components/markdown/markdown.js +++ b/app/components/markdown/markdown.js @@ -179,10 +179,15 @@ export default class Markdown extends PureComponent { }; renderImage = ({linkDestination, reactChildren, context, src}) => { + if (!this.props.imagesMetadata) { + return null; + } + if (context.indexOf('table') !== -1) { // We have enough problems rendering images as is, so just render a link inside of a table return ( diff --git a/app/components/markdown/markdown_image/markdown_image.js b/app/components/markdown/markdown_image/markdown_image.js index becde228c..73d495de0 100644 --- a/app/components/markdown/markdown_image/markdown_image.js +++ b/app/components/markdown/markdown_image/markdown_image.js @@ -6,7 +6,6 @@ import React from 'react'; import {intlShape} from 'react-intl'; import { Clipboard, - Image, Linking, Platform, StyleSheet, @@ -57,11 +56,6 @@ export default class MarkdownImage extends ImageViewPort { }; } - componentDidMount() { - super.componentDidMount(); - this.loadImageSize(this.getSource()); - } - setImageRef = (ref) => { this.imageRef = ref; } @@ -169,12 +163,6 @@ export default class MarkdownImage extends ImageViewPort { previewImageAtIndex([this.itemRef], 0, files); }; - loadImageSize = (source) => { - if (!this.state.originalWidth) { - Image.getSize(source, this.handleSizeReceived, this.handleSizeFailed); - } - }; - render() { if (isGifTooLarge(this.props.imagesMetadata?.[this.props.source])) { return null; diff --git a/app/components/markdown/markdown_table_image/index.js b/app/components/markdown/markdown_table_image/index.js index ed4e50be7..04a1604dc 100644 --- a/app/components/markdown/markdown_table_image/index.js +++ b/app/components/markdown/markdown_table_image/index.js @@ -4,14 +4,12 @@ import {connect} from 'react-redux'; import {getCurrentUrl} from '@mm-redux/selectors/entities/general'; -import {getTheme} from '@mm-redux/selectors/entities/preferences'; import MarkdownTableImage from './markdown_table_image'; function mapStateToProps(state) { return { serverURL: getCurrentUrl(state), - theme: getTheme(state), }; } diff --git a/app/components/markdown/markdown_table_image/markdown_table_image.js b/app/components/markdown/markdown_table_image/markdown_table_image.js index a13e3c717..90a18f1cf 100644 --- a/app/components/markdown/markdown_table_image/markdown_table_image.js +++ b/app/components/markdown/markdown_table_image/markdown_table_image.js @@ -14,10 +14,10 @@ import {goToScreen} from 'app/actions/navigation'; export default class MarkdownTableImage extends React.PureComponent { static propTypes = { children: PropTypes.node.isRequired, + imagesMetadata: PropTypes.object, source: PropTypes.string.isRequired, textStyle: CustomPropTypes.Style.isRequired, serverURL: PropTypes.string, - theme: PropTypes.object.isRequired, }; static contextTypes = { @@ -32,6 +32,7 @@ export default class MarkdownTableImage extends React.PureComponent { defaultMessage: 'Image', }); const passProps = { + imagesMetadata: this.props.imagesMetadata, imageSource: this.getImageSource(), }; diff --git a/app/components/message_attachments/attachment_image/index.js b/app/components/message_attachments/attachment_image/index.js index b696adcdf..50e9d278b 100644 --- a/app/components/message_attachments/attachment_image/index.js +++ b/app/components/message_attachments/attachment_image/index.js @@ -3,7 +3,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import {Image, View} from 'react-native'; +import {View} from 'react-native'; import ProgressiveImage from 'app/components/progressive_image'; import TouchableWithFeedback from 'app/components/touchable_with_feedback'; @@ -110,13 +110,7 @@ export default class AttachmentImage extends PureComponent { if (imageMetadata) { this.setImageDimensionsFromMeta(imageURL, imageMetadata); - return; } - - Image.getSize(imageURL, (width, height) => { - const dimensions = calculateDimensions(height, width, this.maxImageWidth); - this.setImageDimensions(imageURL, dimensions, width, height); - }, () => null); }; setViewPortMaxWidth = () => { diff --git a/app/components/message_attachments/attachment_image/index.test.js b/app/components/message_attachments/attachment_image/index.test.js index 1ffb4c7f5..e34fdf714 100644 --- a/app/components/message_attachments/attachment_image/index.test.js +++ b/app/components/message_attachments/attachment_image/index.test.js @@ -1,12 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Image} from 'react-native'; import {shallow} from 'enzyme'; import React from 'react'; -const originalGetSizeFn = Image.getSize; - import Preferences from '@mm-redux/constants/preferences'; import AttachmentImage from './index'; @@ -20,10 +17,6 @@ describe('AttachmentImage', () => { theme: Preferences.THEMES.default, }; - afterEach(() => { - Image.getSize = originalGetSizeFn; - }); - test('it matches snapshot', () => { const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); @@ -47,22 +40,6 @@ describe('AttachmentImage', () => { expect(state.imageUri).toBe(null); }); - test('it calls Image.getSize if metadata is not present', () => { - const getSizeFn = jest.fn((_, callback) => { - callback(64, 64); - }); - Image.getSize = getSizeFn; - - const props = {...baseProps, imageMetadata: null}; - const wrapper = shallow(); - - const state = wrapper.state(); - expect(state.hasImage).toBe(true); - expect(state.imageUri).toBe('https://images.com/image.png'); - expect(state.originalWidth).toBe(64); - expect(getSizeFn).toHaveBeenCalled(); - }); - test('it updates image when imageUrl prop changes', () => { const wrapper = shallow(); diff --git a/app/components/message_attachments/message_attachment.js b/app/components/message_attachments/message_attachment.js index 464944716..5839e3cb5 100644 --- a/app/components/message_attachments/message_attachment.js +++ b/app/components/message_attachments/message_attachment.js @@ -49,6 +49,7 @@ export default class MessageAttachment extends PureComponent { const style = getStyleSheet(theme); const STATUS_COLORS = getStatusColors(theme); + const hasImage = Boolean(metadata?.images?.[attachment.image_url]); let borderStyle; if (attachment.color) { @@ -111,6 +112,7 @@ export default class MessageAttachment extends PureComponent { actions={attachment.actions} postId={postId} /> + {hasImage && + } ); diff --git a/app/components/post_attachment_opengraph/index.js b/app/components/post_attachment_opengraph/index.js index 4214c917e..c20adc909 100644 --- a/app/components/post_attachment_opengraph/index.js +++ b/app/components/post_attachment_opengraph/index.js @@ -2,9 +2,6 @@ // See LICENSE.txt for license information. import {connect} from 'react-redux'; -import {bindActionCreators} from 'redux'; - -import {getOpenGraphMetadata} from '@mm-redux/actions/posts'; import {getDimensions} from 'app/selectors/device'; @@ -16,12 +13,4 @@ function mapStateToProps(state) { }; } -function mapDispatchToProps(dispatch) { - return { - actions: bindActionCreators({ - getOpenGraphMetadata, - }, dispatch), - }; -} - -export default connect(mapStateToProps, mapDispatchToProps)(PostAttachmentOpenGraph); +export default connect(mapStateToProps)(PostAttachmentOpenGraph); diff --git a/app/components/post_attachment_opengraph/post_attachment_opengraph.js b/app/components/post_attachment_opengraph/post_attachment_opengraph.js index 9d688c1f6..8780538dd 100644 --- a/app/components/post_attachment_opengraph/post_attachment_opengraph.js +++ b/app/components/post_attachment_opengraph/post_attachment_opengraph.js @@ -3,7 +3,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import {Image, Linking, Text, View} from 'react-native'; +import {Linking, Text, View} from 'react-native'; import FastImage from 'react-native-fast-image'; import {TABLET_WIDTH} from '@components/sidebars/drawer_layout'; @@ -19,9 +19,6 @@ const VIEWPORT_IMAGE_REPLY_OFFSET = 13; export default class PostAttachmentOpenGraph extends PureComponent { static propTypes = { - actions: PropTypes.shape({ - getOpenGraphMetadata: PropTypes.func.isRequired, - }).isRequired, deviceHeight: PropTypes.number.isRequired, deviceWidth: PropTypes.number.isRequired, imagesMetadata: PropTypes.object, @@ -40,23 +37,11 @@ export default class PostAttachmentOpenGraph extends PureComponent { componentDidMount() { this.mounted = true; - this.fetchData(this.props.link, this.props.openGraphData); - if (this.state.openGraphImageUrl) { this.getImageSize(this.state.openGraphImageUrl); } } - componentDidUpdate(prevProps, prevState) { - if (prevProps.link !== this.props.link) { - this.fetchData(this.props.link, this.props.openGraphData); - } - - if (prevState.openGraphImageUrl !== this.state.openGraphImageUrl) { - this.getImageSize(this.state.openGraphImageUrl); - } - } - componentWillUnmount() { this.mounted = false; } @@ -65,12 +50,6 @@ export default class PostAttachmentOpenGraph extends PureComponent { this.itemRef = ref; }; - fetchData = (url, openGraphData) => { - if (!openGraphData) { - this.props.actions.getOpenGraphMetadata(url); - } - }; - getBestImageUrlAndDimensions = (data) => { if (!data || !data.images) { return { @@ -147,11 +126,6 @@ export default class PostAttachmentOpenGraph extends PureComponent { if (ogImage?.width && ogImage?.height) { this.setImageSize(imageUrl, ogImage.width, ogImage.height); - } else { - // if we get to this point there can be a scroll pop - Image.getSize(imageUrl, (width, height) => { - this.setImageSize(imageUrl, width, height); - }, () => null); } }; diff --git a/app/components/post_body/post_body.js b/app/components/post_body/post_body.js index 7459e1448..0ad73b874 100644 --- a/app/components/post_body/post_body.js +++ b/app/components/post_body/post_body.js @@ -274,7 +274,7 @@ export default class PostBody extends PureComponent { return null; } - if (metadata && !metadata.embeds) { + if (!metadata?.embeds?.length) { return null; } diff --git a/app/components/post_body/post_body.test.js b/app/components/post_body/post_body.test.js index b453e4a1b..cc2a33680 100644 --- a/app/components/post_body/post_body.test.js +++ b/app/components/post_body/post_body.test.js @@ -49,9 +49,25 @@ describe('PostBody', () => { }; test('should mount additional content for non-system messages', () => { + const metadata = { + embeds: [{ + type: 'opengraph', + url: 'https://youtu.be/g-EXttb1C9A', + }], + images: { + 'https://i.ytimg.com/vi/g-EXttb1C9A/maxresdefault.jpg': { + format: 'jpeg', + frame_count: 0, + height: 720, + width: 1280, + }, + }, + }; + const props = { ...baseProps, isSystemMessage: false, + metadata, }; const wrapper = shallowWithIntl(); diff --git a/app/components/post_body_additional_content/index.js b/app/components/post_body_additional_content/index.js index 8ca3a5eb0..f41975bc1 100644 --- a/app/components/post_body_additional_content/index.js +++ b/app/components/post_body_additional_content/index.js @@ -7,30 +7,15 @@ import {bindActionCreators} from 'redux'; import {getRedirectLocation} from '@mm-redux/actions/general'; import {Preferences} from '@mm-redux/constants'; import {getConfig} from '@mm-redux/selectors/entities/general'; -import {getOpenGraphMetadataForUrl, getExpandedLink} from '@mm-redux/selectors/entities/posts'; +import {getOpenGraphMetadataForUrl as selectOpenGraphMetadataForUrl, getExpandedLink as selectExpandedLink} from '@mm-redux/selectors/entities/posts'; import {getBool, getTheme} from '@mm-redux/selectors/entities/preferences'; import {ViewTypes} from 'app/constants'; import {getDimensions} from 'app/selectors/device'; -import {extractFirstLink} from 'app/utils/url'; import PostBodyAdditionalContent from './post_body_additional_content'; -function makeGetFirstLink() { - let link; - let lastMessage; - - return (message) => { - if (message !== lastMessage) { - link = extractFirstLink(message); - lastMessage = message; - } - - return link; - }; -} - -function getOpenGraphData(metadata, url) { +function selectOpenGraphData(metadata, url) { if (!metadata || !metadata.embeds) { return null; } @@ -40,39 +25,35 @@ function getOpenGraphData(metadata, url) { }); } -function makeMapStateToProps() { - const getFirstLink = makeGetFirstLink(); +function mapStateToProps(state, ownProps) { + const config = getConfig(state); + const link = ownProps.metadata.embeds[0]?.url || ''; + let expandedLink; + if (link) { + expandedLink = selectExpandedLink(state, link); + } - return function mapStateToProps(state, ownProps) { - const config = getConfig(state); - const link = getFirstLink(ownProps.message); - let expandedLink; - if (link) { - expandedLink = getExpandedLink(state, link); - } + // Link previews used to be an advanced settings until server version 4.4 when it was changed to be a display setting. + // We are checking both here until we bump the server requirement for the mobile apps. + const previewsEnabled = (getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, `${ViewTypes.FEATURE_TOGGLE_PREFIX}${ViewTypes.EMBED_PREVIEW}`) || + getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.LINK_PREVIEW_DISPLAY, true)); - // Link previews used to be an advanced settings until server version 4.4 when it was changed to be a display setting. - // We are checking both here until we bump the server requirement for the mobile apps. - const previewsEnabled = (getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, `${ViewTypes.FEATURE_TOGGLE_PREFIX}${ViewTypes.EMBED_PREVIEW}`) || - getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.LINK_PREVIEW_DISPLAY, true)); + const removeLinkPreview = ownProps.postProps.remove_link_preview === 'true'; - const removeLinkPreview = ownProps.postProps.remove_link_preview === 'true'; + let openGraphData = selectOpenGraphMetadataForUrl(state, ownProps.postId, link); + if (!openGraphData) { + const data = selectOpenGraphData(ownProps.metadata, link); + openGraphData = data?.data; + } - let openGraphData = getOpenGraphMetadataForUrl(state, ownProps.postId, link); - if (!openGraphData) { - const data = getOpenGraphData(ownProps.metadata, link); - openGraphData = data?.data; - } - - return { - ...getDimensions(state), - googleDeveloperKey: config.GoogleDeveloperKey, - link, - expandedLink, - openGraphData, - showLinkPreviews: previewsEnabled && config.EnableLinkPreviews === 'true' && !removeLinkPreview, - theme: getTheme(state), - }; + return { + ...getDimensions(state), + googleDeveloperKey: config.GoogleDeveloperKey, + link, + expandedLink, + openGraphData, + showLinkPreviews: previewsEnabled && config.EnableLinkPreviews === 'true' && !removeLinkPreview, + theme: getTheme(state), }; } @@ -84,4 +65,4 @@ function mapDispatchToProps(dispatch) { }; } -export default connect(makeMapStateToProps, mapDispatchToProps)(PostBodyAdditionalContent); +export default connect(mapStateToProps, mapDispatchToProps)(PostBodyAdditionalContent); diff --git a/app/components/post_body_additional_content/post_body_additional_content.js b/app/components/post_body_additional_content/post_body_additional_content.js index 699aa9c09..6143bbe0c 100644 --- a/app/components/post_body_additional_content/post_body_additional_content.js +++ b/app/components/post_body_additional_content/post_body_additional_content.js @@ -34,24 +34,24 @@ export default class PostBodyAdditionalContent extends ImageViewPort { actions: PropTypes.shape({ getRedirectLocation: PropTypes.func.isRequired, }).isRequired, - link: PropTypes.string.isRequired, - message: PropTypes.string.isRequired, + baseTextStyle: CustomPropTypes.Style, + blockStyles: PropTypes.object, deviceHeight: PropTypes.number.isRequired, deviceWidth: PropTypes.number.isRequired, + expandedLink: PropTypes.string, + googleDeveloperKey: PropTypes.string, + isReplyPost: PropTypes.bool, + link: PropTypes.string.isRequired, + message: PropTypes.string.isRequired, + metadata: PropTypes.object, + onHashtagPress: PropTypes.func, + onPermalinkPress: PropTypes.func, + openGraphData: PropTypes.object, postId: PropTypes.string.isRequired, postProps: PropTypes.object.isRequired, showLinkPreviews: PropTypes.bool.isRequired, theme: PropTypes.object.isRequired, - baseTextStyle: CustomPropTypes.Style, - blockStyles: PropTypes.object, - googleDeveloperKey: PropTypes.string, - metadata: PropTypes.object, - isReplyPost: PropTypes.bool, - onHashtagPress: PropTypes.func, - onPermalinkPress: PropTypes.func, - openGraphData: PropTypes.object, textStyles: PropTypes.object, - expandedLink: PropTypes.string, }; static contextTypes = { @@ -122,10 +122,6 @@ export default class PostBodyAdditionalContent extends ImageViewPort { if (img && img.height && img.width) { this.setImageSize(path, img.width, img.height); - } else { - Image.getSize(path, (width, height) => { - this.setImageSize(path, width, height); - }, () => this.setState({linkLoadError: true})); } } }; @@ -137,7 +133,7 @@ export default class PostBodyAdditionalContent extends ImageViewPort { imageUrl = link; } else if (isYoutubeLink(link)) { const videoId = getYouTubeVideoId(link); - imageUrl = `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`; + imageUrl = Object.keys(this.props.metadata.images)[0] || `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`; } return imageUrl; @@ -221,12 +217,12 @@ export default class PostBodyAdditionalContent extends ImageViewPort { const {link, expandedLink, actions} = this.props; if (link) { - let imageUrl = this.getImageUrl(link); - if (isYoutubeLink(link)) { return; } + let imageUrl = this.getImageUrl(link); + if (!imageUrl) { if (!expandedLink || linkChanged) { actions.getRedirectLocation(link); @@ -295,6 +291,10 @@ export default class PostBodyAdditionalContent extends ImageViewPort { const imageMetadata = this.props.metadata?.images?.[link]; const {width, height, uri} = this.state; + if (!imageMetadata) { + return null; + } + return ( ); @@ -390,8 +390,8 @@ export default class PostBodyAdditionalContent extends ImageViewPort { MAX_YOUTUBE_IMAGE_WIDTH, getViewPortWidth(this.props.isReplyPost, this.hasPermanentSidebar()), ); - const imgUrl = `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`; + const imgUrl = Object.keys(this.props.metadata.images)[0] || `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`; return ( { const {theme} = this.props; const {formatMessage} = this.context.intl; diff --git a/app/components/reactions/reactions.test.js b/app/components/reactions/reactions.test.js index 28021283a..cc898b037 100644 --- a/app/components/reactions/reactions.test.js +++ b/app/components/reactions/reactions.test.js @@ -12,7 +12,6 @@ describe('Reactions', () => { const baseProps = { actions: { addReaction: jest.fn(), - getReactionsForPost: jest.fn(), removeReaction: jest.fn(), }, canAddReaction: true, diff --git a/app/screens/table_image/table_image.js b/app/screens/table_image/table_image.js index 24429c25f..17a90c623 100644 --- a/app/screens/table_image/table_image.js +++ b/app/screens/table_image/table_image.js @@ -14,23 +14,21 @@ import FastImage from 'react-native-fast-image'; export default class TableImage extends React.PureComponent { static propTypes = { deviceWidth: PropTypes.number.isRequired, + imagesMetadata: PropTypes.object, imageSource: PropTypes.string.isRequired, }; constructor(props) { super(props); + const dimensions = props.imagesMetadata?.[props.imageSource]; this.state = { imageSource: '', - width: -1, - height: -1, + width: dimensions?.width || -1, + height: dimensions?.height || -1, }; } - componentDidMount() { - this.getImageSize(this.props.imageSource); - } - static getDerivedStateFromProps(nextProps, state) { if (nextProps.imageSource !== state.imageSource) { return { @@ -44,16 +42,16 @@ export default class TableImage extends React.PureComponent { componentDidUpdate(prevProps) { if (prevProps.imageSource !== this.props.imageSource) { - this.getImageSize(this.props.imageSource); + this.getImageSize(); } } - getImageSize = (imageSource) => { - Image.getSize(imageSource, (width, height) => { - this.setState({ - width, - height, - }); + getImageSize = () => { + const {imageSource, imagesMetadata} = this.props; + const dimensions = imagesMetadata?.[imageSource]; + this.setState({ + width: dimensions?.width || -1, + height: dimensions?.height || -1, }); }