Unverified Commit e005b58a authored by Sudheer's avatar Sudheer Committed by GitHub
Browse files

MM-11692 Add infinite scroll to webapp (#2032)

* MM-11692 Add infinite scroll

  * Use react new lifecycle methods.
  * Decrease box value variable for layout trashing.
  * Add a fallback to manual retry after a 3 auto retries
  * Update loader styling
  * Load posts when half of clientHeight
  * Remove requestAnimationFrame for load posts API
  *  Remove required for dimensions as it can be not present for local messages
  * Add absolute position back
  * Remove couple of scroll corrections
  * Correct scroll when last message is posted
  * Fix for no dimensions
  * Add a fix to check for images object in OG data
parent 6bef520c
......@@ -175,18 +175,11 @@ export function increasePostVisibility(channelId, focusedPostId) {
return true;
}
dispatch(batchActions([
{
type: ActionTypes.LOADING_POSTS,
data: true,
channelId,
},
{
type: ActionTypes.INCREASE_POST_VISIBILITY,
data: channelId,
amount: POST_INCREASE_AMOUNT,
},
]));
dispatch({
type: ActionTypes.LOADING_POSTS,
data: true,
channelId,
});
const page = Math.floor(currentPostVisibility / POST_INCREASE_AMOUNT);
......@@ -198,13 +191,25 @@ export function increasePostVisibility(channelId, focusedPostId) {
}
const posts = result.data;
dispatch({
const actions = [{
type: ActionTypes.LOADING_POSTS,
data: false,
channelId,
});
}];
if (posts) {
actions.push({
type: ActionTypes.INCREASE_POST_VISIBILITY,
data: channelId,
amount: posts.order.length,
});
}
return posts ? posts.order.length >= POST_INCREASE_AMOUNT : false;
dispatch(batchActions(actions));
return {
moreToLoad: posts ? posts.order.length >= POST_INCREASE_AMOUNT : false,
error: result.error,
};
};
}
......
......@@ -216,43 +216,40 @@ describe('Actions.Posts', () => {
await testStore.dispatch(Actions.increasePostVisibility('current_channel_id'));
expect(testStore.getActions()).toEqual([
{channelId: 'current_channel_id', data: true, type: 'LOADING_POSTS'},
{args: ['current_channel_id', 2, 30], type: 'MOCK_GET_POSTS'},
{
meta: {batch: true},
payload: [
{channelId: 'current_channel_id', data: true, type: 'LOADING_POSTS'},
{amount: 30, data: 'current_channel_id', type: 'INCREASE_POST_VISIBILITY'},
{channelId: 'current_channel_id', data: false, type: 'LOADING_POSTS'},
],
type: 'BATCHING_REDUCER.BATCH',
},
{args: ['current_channel_id', 2, 30], type: 'MOCK_GET_POSTS'},
{channelId: 'current_channel_id', data: false, type: 'LOADING_POSTS'},
]);
await testStore.dispatch(Actions.increasePostVisibility('current_channel_id', 'latest_post_id'));
expect(testStore.getActions()).toEqual([
{channelId: 'current_channel_id', data: true, type: 'LOADING_POSTS'},
{args: ['current_channel_id', 2, 30], type: 'MOCK_GET_POSTS'},
{
meta: {batch: true},
payload: [
{channelId: 'current_channel_id', data: true, type: 'LOADING_POSTS'},
{amount: 30, data: 'current_channel_id', type: 'INCREASE_POST_VISIBILITY'},
{channelId: 'current_channel_id', data: false, type: 'LOADING_POSTS'},
],
type: 'BATCHING_REDUCER.BATCH',
},
{args: ['current_channel_id', 2, 30], type: 'MOCK_GET_POSTS'},
{channelId: 'current_channel_id', data: false, type: 'LOADING_POSTS'},
{channelId: 'current_channel_id', data: true, type: 'LOADING_POSTS'},
{
args: ['current_channel_id', 'latest_post_id', 2, 30],
type: 'MOCK_GET_POSTS_BEFORE',
},
{
meta: {batch: true},
payload: [
{channelId: 'current_channel_id', data: true, type: 'LOADING_POSTS'},
{amount: 30, data: 'current_channel_id', type: 'INCREASE_POST_VISIBILITY'},
{channelId: 'current_channel_id', data: false, type: 'LOADING_POSTS'},
],
type: 'BATCHING_REDUCER.BATCH',
},
{
args: ['current_channel_id', 'latest_post_id', 2, 30],
type: 'MOCK_GET_POSTS_BEFORE',
},
{channelId: 'current_channel_id', data: false, type: 'LOADING_POSTS'},
]);
});
......
......@@ -64,7 +64,8 @@ export default class PostAttachmentOpenGraph extends React.PureComponent {
const removePreview = this.isRemovePreview(props.post, props.currentUser);
const imageUrl = this.getBestImageUrl(props.openGraphData);
const hasLargeImage = props.post.metadata && imageUrl ? this.hasLargeImage(props.post.metadata.images[imageUrl]) : false;
const {metadata} = props.post;
const hasLargeImage = metadata && metadata.images && metadata.images[imageUrl] && imageUrl ? this.hasLargeImage(metadata.images[imageUrl]) : false;
this.state = {
hasLargeImage,
removePreview,
......@@ -76,7 +77,8 @@ export default class PostAttachmentOpenGraph extends React.PureComponent {
if (!Utils.areObjectsEqual(nextProps.post, this.props.post)) {
const removePreview = this.isRemovePreview(nextProps.post, nextProps.currentUser);
const imageUrl = this.getBestImageUrl(nextProps.openGraphData);
const hasLargeImage = nextProps.post.metadata && imageUrl ? this.hasLargeImage(nextProps.post.metadata.images[imageUrl]) : false;
const {metadata} = nextProps.post;
const hasLargeImage = metadata && metadata.images && metadata.images[imageUrl] && imageUrl ? this.hasLargeImage(metadata.images[imageUrl]) : false;
this.setState({
hasLargeImage,
......@@ -149,8 +151,8 @@ export default class PostAttachmentOpenGraph extends React.PureComponent {
imageTag(imageUrl, renderingForLargeImage = false) {
let element = null;
if (!this.props.post.metadata) {
const {metadata} = this.props.post;
if (!metadata) {
return element;
}
......@@ -159,7 +161,7 @@ export default class PostAttachmentOpenGraph extends React.PureComponent {
(!renderingForLargeImage || (renderingForLargeImage && this.props.isEmbedVisible))
) {
if (renderingForLargeImage) {
const imageDimensions = getFileDimensionsForDisplay(this.props.post.metadata.images[imageUrl], MAX_DIMENSIONS_LARGE_IMAGE);
const imageDimensions = getFileDimensionsForDisplay(metadata.images && metadata.images[imageUrl], MAX_DIMENSIONS_LARGE_IMAGE);
element = (
<img
......@@ -169,7 +171,7 @@ export default class PostAttachmentOpenGraph extends React.PureComponent {
/>
);
} else {
const imageDimensions = getFileDimensionsForDisplay(this.props.post.metadata.images[imageUrl], MAX_DIMENSIONS_SMALL_IMAGE);
const imageDimensions = getFileDimensionsForDisplay(metadata.images && metadata.images[imageUrl], MAX_DIMENSIONS_SMALL_IMAGE);
element = this.wrapInSmallImageContainer(
<img
className={'attachment__image attachment__image--opengraph'}
......
......@@ -227,6 +227,7 @@ export default class PostBodyAdditionalContent extends React.PureComponent {
}
if (this.isLinkImage(link)) {
const {metadata} = this.props.post;
return (
<PostImage
channelId={this.props.post.channel_id}
......@@ -234,7 +235,7 @@ export default class PostBodyAdditionalContent extends React.PureComponent {
onLinkLoadError={this.handleLinkLoadError}
onLinkLoaded={this.handleLinkLoaded}
handleImageClick={this.handleImageClick}
dimensions={this.props.post.metadata && this.props.post.metadata.images[link]}
dimensions={metadata && metadata.images && metadata.images[link]}
/>
);
}
......
......@@ -5,7 +5,6 @@ import PropTypes from 'prop-types';
import React from 'react';
import LoadingImagePreview from 'components/loading_image_preview';
import {postListScrollChange} from 'actions/global_actions.jsx';
import * as PostUtils from 'utils/post_utils.jsx';
import {getFileDimensionsForDisplay} from 'utils/file_utils';
......@@ -45,7 +44,7 @@ export default class PostImageEmbed extends React.PureComponent {
/**
* dimensions for empty space to prevent scroll popup.
*/
dimensions: PropTypes.object.isRequired,
dimensions: PropTypes.object,
}
constructor(props) {
......@@ -92,8 +91,6 @@ export default class PostImageEmbed extends React.PureComponent {
errored: false,
});
postListScrollChange();
if (this.props.onLinkLoaded) {
this.props.onLinkLoaded();
}
......@@ -115,10 +112,6 @@ export default class PostImageEmbed extends React.PureComponent {
};
render() {
if (!this.props.dimensions) {
return null;
}
const imageDimensions = getFileDimensionsForDisplay(this.props.dimensions, MAX_IMAGE_DIMENSIONS);
if (this.state.errored || !this.state.loaded) {
return (
......
This diff is collapsed.
......@@ -12,8 +12,6 @@ import {
localizeMessage,
} from 'utils/utils';
import {postListScrollChange} from 'actions/global_actions.jsx';
import LoadingImagePreview from 'components/loading_image_preview';
import ViewImageModal from 'components/view_image';
......@@ -52,9 +50,6 @@ export default class SingleImageView extends React.PureComponent {
window.addEventListener('resize', this.handleResize);
this.setViewPortWidth();
this.loadImage(this.props.fileInfo);
// Timeout used to delay execution until after current render cycle
setTimeout(postListScrollChange, 0);
}
UNSAFE_componentWillReceiveProps(nextProps) { // eslint-disable-line camelcase
......
......@@ -274,9 +274,8 @@
height: 100%;
overflow-y: scroll;
padding: 1em 0 0;
position: absolute;
width: 100%;
position: absolute;
&.active {
display: inline;
}
......@@ -699,6 +698,11 @@
}
}
}
.loading-screen {
position: relative;
height: 40px;
padding: 0px;
}
}
.post {
......
......@@ -37,6 +37,10 @@ export function trimFilename(filename) {
}
export function getFileDimensionsForDisplay(dimensions, {maxHeight, maxWidth}) {
if (!dimensions) {
return null;
}
const {width, height} = dimensions;
if (height <= maxHeight && width <= maxWidth) {
return dimensions;
......
......@@ -93,4 +93,9 @@ describe('FileUtils.getFileDimensionsForDisplay', () => {
const expectedDimensions = getFileDimensionsForDisplay({height: 600, width: 200}, {maxHeight: 300, maxWidth: 300});
expect(expectedDimensions).toEqual({height: 300, width: 100});
});
it('return null if dimensions does not exists', () => {
const expectedDimensions = getFileDimensionsForDisplay(null, {maxHeight: 300, maxWidth: 300});
expect(expectedDimensions).toEqual(null);
});
});
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment