import React, { Component } from 'react';
import {
View, Text, StyleSheet, TouchableOpacity, ScrollView
} from 'react-native';
import PropTypes from 'prop-types';
import { Q } from '@nozbe/watermelondb';
import database from '../../lib/database';
import RocketChat from '../../lib/rocketchat';
import log from '../../utils/log';
import I18n from '../../i18n';
import { CustomIcon } from '../../lib/Icons';
import { themes } from '../../constants/colors';
import sharedStyles from '../Styles';
import { withTheme } from '../../theme';
const styles = StyleSheet.create({
container: {
position: 'absolute',
top: 0,
width: '100%',
maxHeight: 246
},
item: {
height: 54,
borderBottomWidth: StyleSheet.hairlineWidth,
justifyContent: 'center',
paddingHorizontal: 20
row: {
flexDirection: 'row',
alignItems: 'center'
descriptionContainer: {
flexDirection: 'column',
flex: 1,
marginLeft: 10
descriptionText: {
fontSize: 16,
lineHeight: 20,
...sharedStyles.textRegular
progress: {
bottom: 0,
height: 3
tryAgainButtonText: {
...sharedStyles.textMedium
}
});
class UploadProgress extends Component {
static propTypes = {
width: PropTypes.number,
rid: PropTypes.string,
theme: PropTypes.string,
user: PropTypes.shape({
id: PropTypes.string.isRequired,
username: PropTypes.string.isRequired,
token: PropTypes.string.isRequired
}),
baseUrl: PropTypes.string.isRequired
constructor(props) {
super(props);
this.mounted = false;
this.ranInitialUploadCheck = false;
this.state = {
uploads: []
};
this.init();
componentDidMount() {
this.mounted = true;
componentWillUnmount() {
if (this.uploadsSubscription && this.uploadsSubscription.unsubscribe) {
this.uploadsSubscription.unsubscribe();
init = () => {
const { rid } = this.props;
if (!rid) { return; }
const db = database.active;
this.uploadsObservable = db.collections
.get('uploads')
.query(
Q.where('rid', rid)
)
.observeWithColumns(['progress', 'error']);
this.uploadsSubscription = this.uploadsObservable
.subscribe((uploads) => {
if (this.mounted) {
this.setState({ uploads });
} else {
this.state.uploads = uploads;
if (!this.ranInitialUploadCheck) {
this.uploadCheck();
uploadCheck = () => {
this.ranInitialUploadCheck = true;
const { uploads } = this.state;
uploads.forEach(async(u) => {
if (!RocketChat.isUploadActive(u.path)) {
try {
await db.action(async() => {
await u.update(() => {
u.error = true;
} catch (e) {
log(e);
deleteUpload = async(item) => {
await item.destroyPermanently();
cancelUpload = async(item) => {
await RocketChat.cancelUpload(item);
tryAgain = async(item) => {
const { rid, baseUrl: server, user } = this.props;
await item.update(() => {
item.error = false;
await RocketChat.sendFileMessage(rid, item, undefined, server, user);
renderItemContent = (item) => {
const { width, theme } = this.props;
if (!item.error) {
return (
[
<View key='row' style={styles.row}>
<CustomIcon name='clip' size={20} color={themes[theme].auxiliaryText} />
<Text style={[styles.descriptionContainer, styles.descriptionText, { color: themes[theme].auxiliaryText }]} numberOfLines={1}>
{I18n.t('Uploading')} {item.name}
</Text>
<CustomIcon name='Cross' size={20} color={themes[theme].auxiliaryText} onPress={() => this.cancelUpload(item)} />
</View>,
<View key='progress' style={[styles.progress, { width: (width * item.progress) / 100, backgroundColor: themes[theme].tintColor }]} />
]
);
<View style={styles.row}>
<CustomIcon name='warning' size={20} color={themes[theme].dangerColor} />
<View style={styles.descriptionContainer}>
<Text style={[styles.descriptionText, { color: themes[theme].auxiliaryText }]} numberOfLines={1}>{I18n.t('Error_uploading')} {item.name}</Text>
<TouchableOpacity onPress={() => this.tryAgain(item)}>
<Text style={[styles.tryAgainButtonText, { color: themes[theme].tintColor }]}>{I18n.t('Try_again')}</Text>
</TouchableOpacity>
</View>
<CustomIcon name='Cross' size={20} color={themes[theme].auxiliaryText} onPress={() => this.deleteUpload(item)} />
// TODO: transform into stateless and update based on its own observable changes
renderItem = (item, index) => {
const { theme } = this.props;
<View
key={item.path}
style={[
styles.item,
index !== 0 ? { marginTop: 10 } : {},
{
backgroundColor: themes[theme].chatComponentBackground,
borderColor: themes[theme].borderColor
]}
>
{this.renderItemContent(item)}
render() {
<ScrollView style={styles.container}>
{uploads.map((item, i) => this.renderItem(item, i))}
</ScrollView>
export default withTheme(UploadProgress);