Enhance load image performance

This commit is contained in:
Qolzam
2017-08-24 21:52:34 +07:00
parent 013a8d5c2e
commit bca0752535
9 changed files with 178 additions and 186 deletions

View File

@@ -62,17 +62,18 @@ export const downloadForImageGallery = () => {
/* _____________ CRUD Database_____________ */ /* _____________ CRUD Database_____________ */
/** /**
* Save image in the server * Save image URL in the server
* @param {string} imageName is the name of image * @param {string} imageURL is the URL of image
*/ */
export const dbSaveImage = (imageName) => { export const dbSaveImage = (imageURL,imageFullPath) => {
return (dispatch, getState) => { return (dispatch, getState) => {
var uid = getState().authorize.uid var uid = getState().authorize.uid
var image = { var image = {
creationDate: moment().unix(), creationDate: moment().unix(),
deletationDate: '', deletationDate: '',
name: imageName, URL: imageURL,
fullPath:imageFullPath,
ownerUserId: uid, ownerUserId: uid,
lastEditDate: '', lastEditDate: '',
deleted: false deleted: false
@@ -93,7 +94,7 @@ export const dbSaveImage = (imageName) => {
* Delete an image from database * Delete an image from database
* @param {string} id of image * @param {string} id of image
*/ */
export const dbDeleteImage = (id) => { export const dbDeleteImage = (fullPath) => {
return (dispatch, getState) => { return (dispatch, getState) => {
// Get current user id // Get current user id
@@ -101,11 +102,11 @@ export const dbDeleteImage = (id) => {
// Write the new data simultaneously in the list // Write the new data simultaneously in the list
var updates = {}; var updates = {};
updates[`userFiles/${uid}/files/images/${id}`] = null; updates[`userFiles/${uid}/files/${fullPath}`] = null;
return firebaseRef.update(updates).then((result) => { return firebaseRef.update(updates).then((result) => {
dispatch(deleteImage(id)) dispatch(deleteImage(fullPath))
console.log('image removed: ', id); console.log('image removed: ', fullPath);
}, (error) => { }, (error) => {
console.log(error); console.log(error);
}); });

View File

@@ -85,6 +85,7 @@ export var dbAddPost = (newPost,callBack) => {
tags: newPost.tags || [], tags: newPost.tags || [],
commentCounter: 0, commentCounter: 0,
image: newPost.image || '', image: newPost.image || '',
imageFullPath: newPost.imageFullPath || '',
video:'', video:'',
disableComments: newPost.disableComments ? newPost.disableComments : false, disableComments: newPost.disableComments ? newPost.disableComments : false,
disableSharing: newPost.disableSharing ? newPost.disableSharing : false, disableSharing: newPost.disableSharing ? newPost.disableSharing : false,

View File

@@ -19,6 +19,41 @@ const convertImageToCanvas = (image) => {
return canvas; return canvas;
} }
/**
* Upload image on the server
* @param {file} file
* @param {string} fileName
*/
const uploadImage = (file, fileName, progress) => {
return new Promise((resolve, reject) => {
// Create a storage refrence
var storegeFile = storageRef.child(`images/${fileName}`)
// Upload file
var task = storegeFile.put(file)
task.then((result) => {
resolve(result)
}).catch((error) => {
reject(error)
})
// Upload storage bar
task.on('state_changed', (snapshot) => {
var percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
progress(percentage, true)
}, (error) => {
console.log('========== Upload Image ============')
console.log(error)
console.log('====================================')
}, (complete) => {
progress(100, false)
})
})
}
/** /**
* Constraint image size * Constraint image size
* @param {file} file * @param {file} file
@@ -103,6 +138,7 @@ export default {
dataURLToBlob, dataURLToBlob,
convertImageToCanvas, convertImageToCanvas,
getExtension, getExtension,
constraintImage constraintImage,
uploadImage
} }

View File

@@ -153,6 +153,9 @@ export class EditProfile extends Component {
* Set banner image url * Set banner image url
*/ */
handleRequestSetBanner = (url) => { handleRequestSetBanner = (url) => {
console.log('==========Banner==================');
console.log(url);
console.log('====================================');
this.setState({ this.setState({
banner: url banner: url
}) })
@@ -433,8 +436,7 @@ export class EditProfile extends Component {
const mapDispatchToProps = (dispatch, ownProps) => { const mapDispatchToProps = (dispatch, ownProps) => {
return { return {
update: (info) => dispatch(userActions.dbUpdateUserInfo(info)), update: (info) => dispatch(userActions.dbUpdateUserInfo(info)),
onRequestClose: () => dispatch(userActions.closeEditProfile()), onRequestClose: () => dispatch(userActions.closeEditProfile())
getImage: (name) => dispatch(imageGalleryActions.dbDownloadImage(name))
} }
} }

View File

@@ -17,7 +17,6 @@ import uuid from 'uuid'
// - Import actions // - Import actions
import * as imageGalleryActions from 'imageGalleryActions' import * as imageGalleryActions from 'imageGalleryActions'
import * as fileActions from 'fileActions'
import * as globalActions from 'globalActions' import * as globalActions from 'globalActions'
// - Import app components // - Import app components
@@ -59,8 +58,8 @@ export class ImageGallery extends Component {
* @param {event} evt passed by on click event on add image * @param {event} evt passed by on click event on add image
* @param {string} name is the name of the image * @param {string} name is the name of the image
*/ */
handleSetImage = (evt, name) => { handleSetImage = (evt, URL,fullPath) => {
this.props.set(name) this.props.set(URL,fullPath)
this.close() this.close()
} }
@@ -69,8 +68,8 @@ export class ImageGallery extends Component {
* @param {event} evt passed by on click event on delete image * @param {event} evt passed by on click event on delete image
* @param {integer} id is the image identifier which selected to delete * @param {integer} id is the image identifier which selected to delete
*/ */
handleDeleteImage = (evt, id) => { handleDeleteImage = (evt, fullPath) => {
this.props.deleteImage(id) this.props.deleteImage(fullPath)
} }
componentDidMount() { componentDidMount() {
@@ -87,9 +86,20 @@ export class ImageGallery extends Component {
* @memberof ImageGallery * @memberof ImageGallery
*/ */
handleSendResizedImage = (event) => { handleSendResizedImage = (event) => {
const { resizedImage, fileName } = event.detail
this.props.saveImage(resizedImage, fileName)
const { resizedImage, fileName } = event.detail
const {saveImageGallery} = this.props
FileAPI.uploadImage(resizedImage, fileName, (percent, status) => {
console.log('============= Upload progress ===============');
console.log(percent);
console.log('====================================');
}).then((result) => {
/* Add image to image gallery */
saveImageGallery(result.downloadURL,result.metadata.fullPath)
})
} }
/** /**
@@ -116,9 +126,9 @@ export class ImageGallery extends Component {
return (<GridTile return (<GridTile
key={image.id} key={image.id}
title={<SvgDelete hoverColor={grey200} color="white" color="white" style={{ marginLeft: "5px", cursor: "pointer" }} onClick={evt => this.handleDeleteImage(evt, image.id)} />} title={<SvgDelete hoverColor={grey200} color="white" color="white" style={{ marginLeft: "5px", cursor: "pointer" }} onClick={evt => this.handleDeleteImage(evt, image.fullPath)} />}
subtitle={<span></span>} subtitle={<span></span>}
actionIcon={<SvgAddImage hoverColor={grey200} color="white" style={{ marginRight: "5px", cursor: "pointer" }} onClick={evt => this.handleSetImage(evt, image.name)} />} actionIcon={<SvgAddImage hoverColor={grey200} color="white" style={{ marginRight: "5px", cursor: "pointer" }} onClick={evt => this.handleSetImage(evt, image.URL,image.fullPath)} />}
> >
<div> <div>
<div style={{ overflowY: "hidden", overflowX: "auto" }}> <div style={{ overflowY: "hidden", overflowX: "auto" }}>
@@ -126,7 +136,7 @@ export class ImageGallery extends Component {
<div style={{ display: "block" }}> <div style={{ display: "block" }}>
<div style={{ display: "block", marginRight: "8px", transition: "transform .25s" }}> <div style={{ display: "block", marginRight: "8px", transition: "transform .25s" }}>
<li style={{ width: "100%", margin: 0, verticalAlign: "bottom", position: "static", display: "inline-block" }}> <li style={{ width: "100%", margin: 0, verticalAlign: "bottom", position: "static", display: "inline-block" }}>
<Img fileName={image.name} style={{ width: "100%", height: "auto" }} /> <Img fileName={image.URL} style={{ width: "100%", height: "auto" }} />
</li> </li>
</div> </div>
@@ -214,12 +224,8 @@ export class ImageGallery extends Component {
*/ */
const mapDispatchToProps = (dispatch, ownProps) => { const mapDispatchToProps = (dispatch, ownProps) => {
return { return {
saveImage: (file, fileName) => { saveImageGallery: (imageURL,imageFullPath) => dispatch(imageGalleryActions.dbSaveImage(imageURL,imageFullPath)),
dispatch(imageGalleryActions.dbUploadImage(file, fileName)) deleteImage: (fullPath) => dispatch(imageGalleryActions.dbDeleteImage(fullPath))
},
deleteImage: (id) => {
dispatch(imageGalleryActions.dbDeleteImage(id))
}
} }
} }

View File

@@ -43,7 +43,6 @@ export class Img extends Component {
} }
// Binding functions to `this` // Binding functions to `this`
this.getImageURL = this.getImageURL.bind(this)
this.handleLoadImage = this.handleLoadImage.bind(this) this.handleLoadImage = this.handleLoadImage.bind(this)
} }
@@ -59,29 +58,6 @@ export class Img extends Component {
}) })
} }
/**
* Get image url if it is not exist on redux store
*
* @memberof Img
*/
getImageURL = () => {
let { fileName } = this.props
if (fileName && fileName !== '') {
if (this.props.imageRequests.indexOf(fileName) > -1)
return
this.props.getImage(fileName)
}
}
componentWillMount() {
let { fileName } = this.props
if (this.props.imageRequests.indexOf(fileName) > -1)
return
this.getImageURL()
}
/** /**
* Reneder component DOM * Reneder component DOM
* @return {react element} return the DOM which rendered by component * @return {react element} return the DOM which rendered by component
@@ -114,7 +90,7 @@ export class Img extends Component {
let { isImageLoaded } = this.state let { isImageLoaded } = this.state
return ( return (
<div> <div>
<img onLoad={this.handleLoadImage} src={this.props.avatarURL[fileName] || ''} style={isImageLoaded ? style : { display: 'none' }} /> <img onLoad={this.handleLoadImage} src={fileName || ''} style={isImageLoaded ? style : { display: 'none' }} />
<div style={{ backgroundColor: 'blue' }} style={isImageLoaded ? { display: 'none' } : styles.loding}> <div style={{ backgroundColor: 'blue' }} style={isImageLoaded ? { display: 'none' } : styles.loding}>
<div style={styles.loadingContent}> <div style={styles.loadingContent}>
<SvgImage style={styles.loadingImage} /> <SvgImage style={styles.loadingImage} />
@@ -136,8 +112,7 @@ export class Img extends Component {
*/ */
const mapDispatchToProps = (dispatch, ownProps) => { const mapDispatchToProps = (dispatch, ownProps) => {
return { return {
getImage: (name) => dispatch(imageGalleryActions.dbDownloadImage(name))
} }
} }

View File

@@ -60,7 +60,6 @@ export class ImgCover extends Component {
} }
// Binding functions to `this` // Binding functions to `this`
this.getImageURL = this.getImageURL.bind(this)
this.handleLoadImage = this.handleLoadImage.bind(this) this.handleLoadImage = this.handleLoadImage.bind(this)
} }
@@ -75,29 +74,6 @@ export class ImgCover extends Component {
}) })
} }
/**
* Get image url if it is not exist on redux store
*
* @memberof Img
*/
getImageURL = () => {
let { fileName } = this.props
if (fileName && fileName !== '') {
if (this.props.imageRequests.indexOf(fileName) > -1)
return
this.props.getImage(fileName)
}
}
componentWillMount() {
let { fileName } = this.props
if (this.props.imageRequests.indexOf(fileName) > -1)
return
this.getImageURL()
}
/** /**
* Reneder component DOM * Reneder component DOM
* @return {react element} return the DOM which rendered by component * @return {react element} return the DOM which rendered by component
@@ -112,7 +88,7 @@ export class ImgCover extends Component {
*/ */
const styles = { const styles = {
cover: { cover: {
backgroundImage: 'url(' + (this.props.avatarURL[fileName] || '#') + ')', backgroundImage: 'url(' + (fileName || '') + ')',
backgroundSize: 'cover', backgroundSize: 'cover',
backgroundRepeat: 'no-repeat', backgroundRepeat: 'no-repeat',
backgroundPosition: 'center', backgroundPosition: 'center',
@@ -153,7 +129,7 @@ export class ImgCover extends Component {
<div>Image has not loaded</div> <div>Image has not loaded</div>
</div> </div>
</div> </div>
<img onLoad={this.handleLoadImage} src={this.props.avatarURL[fileName] || ''} style={{ display: 'none'}} /> <img onLoad={this.handleLoadImage} src={fileName || ''} style={{ display: 'none'}} />
</div> </div>
) )
} }
@@ -169,8 +145,6 @@ export class ImgCover extends Component {
*/ */
const mapDispatchToProps = (dispatch, ownProps) => { const mapDispatchToProps = (dispatch, ownProps) => {
return { return {
getImage: (name) => dispatch(imageGalleryActions.dbDownloadImage(name))
} }
} }

View File

@@ -82,9 +82,13 @@ export class PostWrite extends Component {
*/ */
postText: this.props.edit ? this.props.text : '', postText: this.props.edit ? this.props.text : '',
/** /**
* The image of the post * The URL image of the post
*/ */
image: this.props.edit ? this.props.image : '', image: this.props.edit ? this.props.image : '',
/**
* The path identifier of image on the server
*/
imageFullPath: this.props.edit ? this.props.imageFullPath : '',
/** /**
* If it's true gallery will be open * If it's true gallery will be open
*/ */
@@ -116,31 +120,31 @@ export class PostWrite extends Component {
} }
/** /**
* Toggle comments of the post to disable/enable * Toggle comments of the post to disable/enable
* *
* *
* @memberof PostWrite * @memberof PostWrite
*/ */
handleToggleComments = () => { handleToggleComments = () => {
this.setState({ this.setState({
disableComments: !this.state.disableComments, disableComments: !this.state.disableComments,
disabledPost: false disabledPost: false
}) })
} }
/** /**
* Toggle sharing of the post to disable/enable * Toggle sharing of the post to disable/enable
* *
* *
* @memberof PostWrite * @memberof PostWrite
*/ */
handleToggleSharing = () => { handleToggleSharing = () => {
this.setState({ this.setState({
disableSharing: !this.state.disableSharing, disableSharing: !this.state.disableSharing,
disabledPost: false disabledPost: false
}) })
} }
/** /**
* Romove the image of post * Romove the image of post
@@ -151,6 +155,7 @@ handleToggleSharing = () => {
handleRemoveImage = () => { handleRemoveImage = () => {
this.setState({ this.setState({
image: '', image: '',
imageFullPath: '',
disabledPost: false disabledPost: false
}) })
} }
@@ -161,52 +166,71 @@ handleToggleSharing = () => {
*/ */
handlePost = (evt) => { handlePost = (evt) => {
var image = this.state.image const {
var tags = PostAPI.getContentTags(this.state.postText) image,
imageFullPath,
disableComments,
disableSharing,
postText } = this.state
const {
id,
avatar,
name,
edit,
onRequestClose,
post,
update } = this.props
var tags = PostAPI.getContentTags(postText)
// In edit status we should fire update if not we should fire post function // In edit status we should fire update if not we should fire post function
if (!this.props.edit) { if (!edit) {
if (image !== '') { if (image !== '') {
this.props.post({ post({
body: this.state.postText, body: postText,
tags: tags, tags: tags,
image: image, image: image,
avatar: this.props.avatar, imageFullPath: imageFullPath,
name: this.props.name, avatar: avatar,
disableComments: this.state.disableComments, name: name,
disableSharing: this.state.disableSharing disableComments: disableComments,
}, this.props.onRequestClose) disableSharing: disableSharing
}, onRequestClose)
} }
else { else {
this.props.post({ post({
body: this.state.postText, body: postText,
tags: tags, tags: tags,
avatar: this.props.avatar, avatar: avatar,
name: this.props.name, name: name,
disableComments: this.state.disableComments, disableComments: disableComments,
disableSharing: this.state.disableSharing disableSharing: disableSharing
}, this.props.onRequestClose) }, onRequestClose)
} }
} }
// In edit status we pass post to update functions // In edit status we pass post to update functions
else { else {
this.props.update({ update({
id: this.props.id, id: id,
body: this.state.postText, body: postText,
tags: tags, tags: tags,
image: image, image: image,
disableComments: this.state.disableComments, imageFullPath: imageFullPath,
disableSharing: this.state.disableSharing disableComments: disableComments,
}, this.props.onRequestClose) disableSharing: disableSharing
}, onRequestClose)
} }
} }
/** /**
* Set post image url * Set post image url
*/ */
onRequestSetImage = (url) => { onRequestSetImage = (url, fullPath) => {
this.setState({ this.setState({
image: url, image: url,
imageFullPath: fullPath,
disabledPost: false disabledPost: false
}) })
} }
@@ -252,32 +276,32 @@ handleToggleSharing = () => {
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if(!nextProps.open){ if (!nextProps.open) {
this.setState({ this.setState({
/** /**
* Post text * Post text
*/ */
postText: this.props.edit ? this.props.text : '', postText: this.props.edit ? this.props.text : '',
/** /**
* The image of the post * The image of the post
*/ */
image: this.props.edit ? this.props.image : '', image: this.props.edit ? this.props.image : '',
/** /**
* If it's true gallery will be open * If it's true gallery will be open
*/ */
galleryOpen: false, galleryOpen: false,
/** /**
* If it's true post button will be disabled * If it's true post button will be disabled
*/ */
disabledPost: true, disabledPost: true,
/** /**
* If it's true comment will be disabled on post * If it's true comment will be disabled on post
*/ */
disableComments: this.props.edit ? this.props.disableComments : false, disableComments: this.props.edit ? this.props.disableComments : false,
/** /**
* If it's true share will be disabled on post * If it's true share will be disabled on post
*/ */
disableSharing: this.props.edit ? this.props.disableSharing : false, disableSharing: this.props.edit ? this.props.disableSharing : false,
}) })
} }
@@ -364,7 +388,7 @@ handleToggleSharing = () => {
<div style={this.props.style}> <div style={this.props.style}>
{this.props.children} {this.props.children}
<Dialog <Dialog
id= {this.props.id || 0} id={this.props.id || 0}
actions={writeActions} actions={writeActions}
modal={false} modal={false}
open={this.props.open} open={this.props.open}
@@ -397,7 +421,7 @@ handleToggleSharing = () => {
hintStyle={{ fontWeight: 200, fontSize: "14px" }} hintStyle={{ fontWeight: 200, fontSize: "14px" }}
textareaStyle={{ fontWeight: 200, fontSize: "14px" }} textareaStyle={{ fontWeight: 200, fontSize: "14px" }}
style={{ margin: "0 16px", flexShrink: 0, width: "initial", flexGrow: 1 }} style={{ margin: "0 16px", flexShrink: 0, width: "initial", flexGrow: 1 }}
/> />
{(this.state.image && this.state.image !== '') {(this.state.image && this.state.image !== '')
@@ -462,7 +486,7 @@ handleToggleSharing = () => {
const mapDispatchToProps = (dispatch, ownProps) => { const mapDispatchToProps = (dispatch, ownProps) => {
return { return {
post: (post, callBack) => dispatch(postActions.dbAddImagePost(post, callBack)), post: (post, callBack) => dispatch(postActions.dbAddImagePost(post, callBack)),
update: (post,callBack) => dispatch(postActions.dbUpdatePost(post, callBack)) update: (post, callBack) => dispatch(postActions.dbUpdatePost(post, callBack))
} }
} }

View File

@@ -51,46 +51,21 @@ export class ImgCover extends Component {
} }
// Binding functions to `this` // Binding functions to `this`
this.getImageURL = this.getImageURL.bind(this)
} }
componentWillReceiveProps(nextProps) {
const { fileName, avatarURL } = this.props
if (fileName && !avatarURL[fileName]) {
if (this.props.imageRequests.indexOf(fileName) > -1)
return
this.getImageURL()
}
}
getImageURL = () => {
let { fileName } = this.props
if (fileName && fileName !== '') {
if (this.props.imageRequests.indexOf(fileName) > -1)
return
this.props.getImage(fileName)
}
}
componentWillMount() {
let { fileName } = this.props
if (this.props.imageRequests.indexOf(fileName) > -1)
return
this.getImageURL()
}
/** /**
* Reneder component DOM * Reneder component DOM
* @return {react element} return the DOM which rendered by component * @return {react element} return the DOM which rendered by component
*/ */
render() { render() {
let { fileName, style, size, onTouchTap, avatarURL } = this.props let { fileName, style, size, onTouchTap } = this.props
return ( return (
<Avatar src={avatarURL[fileName] || ''} size={size || 36} style={style} onTouchTap={onTouchTap} /> <Avatar src={fileName || ''} size={size || 36} style={style} onTouchTap={onTouchTap} />
) )
} }
@@ -106,8 +81,6 @@ export class ImgCover extends Component {
*/ */
const mapDispatchToProps = (dispatch, ownProps) => { const mapDispatchToProps = (dispatch, ownProps) => {
return { return {
getImage: (name) => dispatch(imageGalleryActions.dbDownloadImage(name))
} }
} }