Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] Add image loading indicator #8238

Merged
merged 9 commits into from
Apr 3, 2022
27 changes: 27 additions & 0 deletions src/components/ImageView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import styles from '../../styles/styles';
import * as StyleUtils from '../../styles/StyleUtils';
import canUseTouchScreen from '../../libs/canUseTouchscreen';
import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
import FullscreenLoadingIndicator from '../FullscreenLoadingIndicator';

const propTypes = {
/** URL to full-sized image */
Expand All @@ -23,7 +24,10 @@ class ImageView extends PureComponent {
this.onContainerPressIn = this.onContainerPressIn.bind(this);
this.onContainerPress = this.onContainerPress.bind(this);
this.onContainerPressOut = this.onContainerPressOut.bind(this);
this.imageLoadingStart = this.imageLoadingStart.bind(this);
this.imageLoadingEnd = this.imageLoadingEnd.bind(this);
this.state = {
isLoading: false,
containerHeight: 0,
containerWidth: 0,
isZoomed: false,
Expand Down Expand Up @@ -227,6 +231,14 @@ class ImageView extends PureComponent {
this.setState(prevState => ({isDragging: prevState.isMouseDown}));
}

imageLoadingStart() {
this.setState({isLoading: true});
}

imageLoadingEnd() {
this.setState({isLoading: false});
}

render() {
if (this.canUseTouchScreen) {
return (
Expand All @@ -240,7 +252,14 @@ class ImageView extends PureComponent {
styles.h100,
]}
resizeMode="contain"
onLoadStart={this.imageLoadingStart}
onLoadEnd={this.imageLoadingEnd}
/>
{this.state.isLoading && (
<FullscreenLoadingIndicator
style={[styles.opacity1, styles.bgTransparent]}
/>
)}
</View>
);
}
Expand Down Expand Up @@ -274,8 +293,16 @@ class ImageView extends PureComponent {
styles.w100,
]}
resizeMode="contain"
onLoadStart={this.imageLoadingStart}
onLoadEnd={this.imageLoadingEnd}
/>
</Pressable>

{this.state.isLoading && (
<FullscreenLoadingIndicator
style={[styles.opacity1, styles.bgTransparent]}
/>
)}
</View>
);
}
Expand Down
31 changes: 28 additions & 3 deletions src/components/ImageView/index.native.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {View, InteractionManager, PanResponder} from 'react-native';
import {
View, InteractionManager, PanResponder,
} from 'react-native';
import Image from 'react-native-fast-image';
import ImageZoom from 'react-native-image-pan-zoom';
import ImageSize from 'react-native-image-size';
Expand All @@ -9,6 +11,7 @@ import styles from '../../styles/styles';
import * as StyleUtils from '../../styles/StyleUtils';
import variables from '../../styles/variables';
import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
import FullscreenLoadingIndicator from '../FullscreenLoadingIndicator';

/**
* On the native layer, we use a image library to handle zoom functionality
Expand All @@ -25,6 +28,7 @@ class ImageView extends PureComponent {
super(props);

this.state = {
isLoading: false,
thumbnailWidth: 100,
thumbnailHeight: 100,
imageWidth: undefined,
Expand All @@ -43,6 +47,9 @@ class ImageView extends PureComponent {
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: this.updatePanResponderTouches.bind(this),
});

this.imageLoadingStart = this.imageLoadingStart.bind(this);
this.imageLoadingEnd = this.imageLoadingEnd.bind(this);
}

componentDidMount() {
Expand Down Expand Up @@ -100,6 +107,14 @@ class ImageView extends PureComponent {
return false;
}

imageLoadingStart() {
this.setState({isLoading: true});
}

imageLoadingEnd() {
this.setState({isLoading: false});
}

render() {
// Default windowHeight accounts for the modal header height
const windowHeight = this.props.windowHeight - variables.contentHeaderHeight;
Expand All @@ -120,7 +135,10 @@ class ImageView extends PureComponent {
<Image
source={{uri: this.props.url}}
style={StyleUtils.getWidthAndHeightStyle(this.state.thumbnailWidth, this.state.thumbnailHeight)}
resizeMode={Image.resizeMode.contain}
resizeMode="contain"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this change necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was not necessary. I did this change to be consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only file where we are using Image.resizeMode.contain everywhere it is contain

/>
<FullscreenLoadingIndicator
style={[styles.opacity1, styles.bgTransparent]}
/>
</View>
);
Expand Down Expand Up @@ -177,7 +195,9 @@ class ImageView extends PureComponent {
this.props.style,
]}
source={{uri: this.props.url}}
resizeMode={Image.resizeMode.contain}
resizeMode="contain"
onLoadStart={this.imageLoadingStart}
onLoadEnd={this.imageLoadingEnd}
/>
{/**
Create an invisible view on top of the image so we can capture and set the amount of touches before
Expand All @@ -194,6 +214,11 @@ class ImageView extends PureComponent {
]}
/>
</ImageZoom>
{this.state.isLoading && (
<FullscreenLoadingIndicator
style={[styles.opacity1, styles.bgTransparent]}
/>
)}
</View>
);
}
Expand Down
44 changes: 39 additions & 5 deletions src/components/ImageWithSizeCalculation.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, {PureComponent} from 'react';
import {Image} from 'react-native';
import {View, Image} from 'react-native';
import PropTypes from 'prop-types';
import Log from '../libs/Log';
import styles from '../styles/styles';
import makeCancellablePromise from '../libs/MakeCancellablePromise';
import FullscreenLoadingIndicator from './FullscreenLoadingIndicator';

const propTypes = {
/** Url for image to display */
Expand All @@ -29,6 +30,17 @@ const defaultProps = {
* it can be appropriately resized.
*/
class ImageWithSizeCalculation extends PureComponent {
constructor(props) {
super(props);

this.state = {
isLoading: false,
};

this.imageLoadingStart = this.imageLoadingStart.bind(this);
this.imageLoadingEnd = this.imageLoadingEnd.bind(this);
}

componentDidMount() {
this.calculateImageSize();
}
Expand Down Expand Up @@ -83,17 +95,39 @@ class ImageWithSizeCalculation extends PureComponent {
});
}

imageLoadingStart() {
this.setState({isLoading: true});
}

imageLoadingEnd() {
this.setState({isLoading: false});
}

render() {
return (
<Image
<View
style={[
styles.w100,
styles.h100,
this.props.style,
]}
source={{uri: this.props.url}}
resizeMode="contain"
/>
>
<Image
style={[
styles.w100,
styles.h100,
]}
source={{uri: this.props.url}}
resizeMode="contain"
onLoadStart={this.imageLoadingStart}
onLoadEnd={this.imageLoadingEnd}
/>
{this.state.isLoading && (
<FullscreenLoadingIndicator
style={[styles.opacity1, styles.bgTransparent]}
/>
)}
</View>
);
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/styles/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ const styles = {
backgroundColor: 'transparent',
},

opacity1: {
opacity: 1,
},

textDanger: {
color: colors.red,
},
Expand Down