Files
mattermost-mobile/app/components/post_draft/uploads/upload_item/upload_item.js
Mattermost Build e711b36789 [MM-29132] Update upload item styling (#4853) (#4856)
* Update upload item styling

* Use font size 9

(cherry picked from commit 85382e695a)

Co-authored-by: Miguel Alatzar <migbot@users.noreply.github.com>
2020-10-01 11:36:56 -07:00

277 lines
8.3 KiB
JavaScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {StyleSheet, Text, View} from 'react-native';
import RNFetchBlob from 'rn-fetch-blob';
import {AnimatedCircularProgress} from 'react-native-circular-progress';
import {Client4} from '@mm-redux/client';
import mattermostBucket from 'app/mattermost_bucket';
import FileAttachmentImage from '@components/file_attachment_list/file_attachment_image';
import FileAttachmentIcon from '@components/file_attachment_list/file_attachment_icon';
import {buildFileUploadData, encodeHeaderURIStringToUTF8} from '@utils/file';
import {emptyFunction} from '@utils/general';
import ImageCacheManager from '@utils/image_cache_manager';
import UploadRemove from './upload_remove';
import UploadRetry from './upload_retry';
import {analytics} from '@init/analytics.ts';
export default class UploadItem extends PureComponent {
static propTypes = {
channelId: PropTypes.string.isRequired,
file: PropTypes.object.isRequired,
handleRemoveFile: PropTypes.func.isRequired,
retryFileUpload: PropTypes.func.isRequired,
rootId: PropTypes.string,
theme: PropTypes.object.isRequired,
uploadComplete: PropTypes.func.isRequired,
uploadFailed: PropTypes.func.isRequired,
};
state = {
progress: 0,
};
componentDidMount() {
const {file} = this.props;
if (file.loading) {
this.downloadAndUploadFile(file);
}
}
componentDidUpdate(prevProps) {
const {file: prevFile} = prevProps;
const {file} = this.props;
if (prevFile.failed !== file.failed && file.loading) {
this.downloadAndUploadFile(file);
}
}
handleRetryFileUpload = (file) => {
if (!file.failed) {
return;
}
this.props.retryFileUpload(file, this.props.rootId);
};
handleRemoveFile = (clientId, channelId, rootId) => {
const {handleRemoveFile} = this.props;
if (this.uploadPromise) {
this.uploadPromise.cancel(() => {
this.canceled = true;
handleRemoveFile(clientId, channelId, rootId);
});
} else {
handleRemoveFile(clientId, channelId, rootId);
}
};
handleUploadCompleted = (res) => {
const {channelId, file, rootId, uploadComplete, uploadFailed} = this.props;
const response = JSON.parse(res.data);
if (res.respInfo.status === 200 || res.respInfo.status === 201) {
const data = response.file_infos.map((f) => {
return {
...f,
clientId: file.clientId,
};
});
uploadComplete(data, channelId, rootId);
} else {
uploadFailed([file.clientId], channelId, rootId, response.message);
}
this.uploadPromise = null;
};
handleUploadError = (error) => {
const {channelId, file, rootId, uploadFailed} = this.props;
if (!this.canceled) {
uploadFailed([file.clientId], channelId, rootId, error);
}
this.uploadPromise = null;
};
handleUploadProgress = (loaded, total) => {
this.setState({progress: Math.floor((loaded / total) * 100)});
};
isImageType = () => {
const {file} = this.props;
if (file.has_preview_image || file.mime_type === 'image/gif' ||
(file.localPath && file.type && file.type.includes('image'))) {
return true;
}
return false;
};
downloadAndUploadFile = async (file) => {
const newFile = {...file};
if (newFile.localPath.startsWith('http')) {
try {
newFile.localPath = await ImageCacheManager.cache(newFile.name, newFile.localPath, emptyFunction);
} catch (e) {
this.handleUploadError(e);
return;
}
}
this.uploadFile(newFile);
}
uploadFile = async (file) => {
const {channelId} = this.props;
const fileData = buildFileUploadData(file);
const headers = {
...Client4.getOptions({method: 'post'}).headers,
'Content-Type': 'multipart/form-data',
};
const fileInfo = {
name: 'files',
filename: encodeHeaderURIStringToUTF8(fileData.name),
data: RNFetchBlob.wrap(file.localPath.replace('file://', '')),
type: fileData.type,
};
const data = [
{name: 'channel_id', data: channelId},
{name: 'client_ids', data: file.clientId},
fileInfo,
];
analytics.trackAPI('api_files_upload');
const certificate = await mattermostBucket.getPreference('cert');
const options = {
timeout: 60000,
certificate,
};
this.uploadPromise = RNFetchBlob.config(options).fetch('POST', Client4.getFilesRoute(), headers, data);
this.uploadPromise.uploadProgress(this.handleUploadProgress);
this.uploadPromise.then(this.handleUploadCompleted).catch(this.handleUploadError);
};
renderProgress = (fill) => {
const realFill = Number(fill.toFixed(0));
return (
<View>
<Text style={styles.progressText}>
{`${realFill}%`}
</Text>
</View>
);
};
render() {
const {
channelId,
file,
rootId,
theme,
} = this.props;
const {progress} = this.state;
let filePreviewComponent;
if (this.isImageType()) {
filePreviewComponent = (
<View style={styles.filePreview}>
<FileAttachmentImage
file={file}
theme={theme}
resizeMode='center'
/>
</View>
);
} else {
filePreviewComponent = (
<View style={styles.filePreview}>
<FileAttachmentIcon
file={file}
theme={theme}
wrapperHeight={53}
wrapperWidth={53}
/>
</View>
);
}
return (
<View
key={file.clientId}
style={styles.preview}
>
<View style={styles.previewContainer}>
{filePreviewComponent}
{file.failed &&
<UploadRetry
file={file}
onPress={this.handleRetryFileUpload}
/>
}
{file.loading && !file.failed &&
<View style={styles.progressCircleContent}>
<AnimatedCircularProgress
size={36}
fill={progress}
width={2}
backgroundColor='rgba(255, 255, 255, 0.5)'
tintColor='white'
rotation={0}
>
{this.renderProgress}
</AnimatedCircularProgress>
</View>
}
</View>
<UploadRemove
theme={this.props.theme}
channelId={channelId}
clientId={file.clientId}
onPress={this.handleRemoveFile}
rootId={rootId}
/>
</View>
);
}
}
const styles = StyleSheet.create({
preview: {
paddingTop: 5,
marginLeft: 12,
},
previewContainer: {
height: 56,
width: 56,
borderRadius: 4,
},
progressCircleContent: {
alignItems: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
height: 56,
width: 56,
justifyContent: 'center',
position: 'absolute',
borderRadius: 4,
},
progressText: {
color: 'white',
fontSize: 9,
fontWeight: 'bold',
},
filePreview: {
width: 56,
height: 56,
},
});