2018-07-17 19:10:27 +00:00
|
|
|
import React, { Component } from 'react';
|
2021-09-13 20:41:05 +00:00
|
|
|
import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
2019-09-16 20:26:32 +00:00
|
|
|
import { Q } from '@nozbe/watermelondb';
|
2022-03-02 14:18:01 +00:00
|
|
|
import { Observable, Subscription } from 'rxjs';
|
2018-07-17 19:10:27 +00:00
|
|
|
|
2019-09-16 20:26:32 +00:00
|
|
|
import database from '../../lib/database';
|
2018-07-17 19:10:27 +00:00
|
|
|
import RocketChat from '../../lib/rocketchat';
|
|
|
|
import log from '../../utils/log';
|
|
|
|
import I18n from '../../i18n';
|
2019-03-01 16:49:11 +00:00
|
|
|
import { CustomIcon } from '../../lib/Icons';
|
2022-04-07 14:10:03 +00:00
|
|
|
import { themes } from '../../lib/constants';
|
2019-03-29 19:36:07 +00:00
|
|
|
import sharedStyles from '../Styles';
|
2019-12-04 16:39:53 +00:00
|
|
|
import { withTheme } from '../../theme';
|
2022-03-02 14:18:01 +00:00
|
|
|
import { IUser, TUploadModel } from '../../definitions';
|
2018-07-17 19:10:27 +00:00
|
|
|
|
|
|
|
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,
|
2019-03-29 19:36:07 +00:00
|
|
|
...sharedStyles.textRegular
|
2018-07-17 19:10:27 +00:00
|
|
|
},
|
|
|
|
progress: {
|
|
|
|
position: 'absolute',
|
|
|
|
bottom: 0,
|
|
|
|
height: 3
|
|
|
|
},
|
|
|
|
tryAgainButtonText: {
|
|
|
|
fontSize: 16,
|
2019-03-29 19:36:07 +00:00
|
|
|
lineHeight: 20,
|
|
|
|
...sharedStyles.textMedium
|
2018-07-17 19:10:27 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-03-02 14:18:01 +00:00
|
|
|
interface IUploadProgressProps {
|
|
|
|
width: number;
|
|
|
|
rid: string;
|
|
|
|
user: Pick<IUser, 'id' | 'username' | 'token'>;
|
|
|
|
baseUrl: string;
|
|
|
|
theme?: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface IUploadProgressState {
|
|
|
|
uploads: TUploadModel[];
|
|
|
|
}
|
|
|
|
|
|
|
|
class UploadProgress extends Component<IUploadProgressProps, IUploadProgressState> {
|
|
|
|
private mounted = false;
|
|
|
|
private ranInitialUploadCheck = false;
|
|
|
|
private uploadsObservable?: Observable<TUploadModel[]>;
|
|
|
|
private uploadsSubscription?: Subscription;
|
2018-07-17 19:10:27 +00:00
|
|
|
|
2022-03-02 14:18:01 +00:00
|
|
|
constructor(props: IUploadProgressProps) {
|
2018-07-17 19:10:27 +00:00
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
uploads: []
|
|
|
|
};
|
2019-09-17 14:43:49 +00:00
|
|
|
this.init();
|
2018-07-17 19:10:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
2019-09-16 20:26:32 +00:00
|
|
|
this.mounted = true;
|
2018-07-17 19:10:27 +00:00
|
|
|
}
|
|
|
|
|
2019-09-16 20:26:32 +00:00
|
|
|
componentWillUnmount() {
|
|
|
|
if (this.uploadsSubscription && this.uploadsSubscription.unsubscribe) {
|
|
|
|
this.uploadsSubscription.unsubscribe();
|
2018-12-21 10:55:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-16 20:26:32 +00:00
|
|
|
init = () => {
|
|
|
|
const { rid } = this.props;
|
2021-09-13 20:41:05 +00:00
|
|
|
if (!rid) {
|
|
|
|
return;
|
|
|
|
}
|
2019-09-16 20:26:32 +00:00
|
|
|
|
|
|
|
const db = database.active;
|
2022-02-01 13:39:09 +00:00
|
|
|
this.uploadsObservable = db.get('uploads').query(Q.where('rid', rid)).observeWithColumns(['progress', 'error']);
|
2021-09-13 20:41:05 +00:00
|
|
|
|
|
|
|
this.uploadsSubscription = this.uploadsObservable.subscribe(uploads => {
|
|
|
|
if (this.mounted) {
|
|
|
|
this.setState({ uploads });
|
|
|
|
} else {
|
2022-03-02 14:18:01 +00:00
|
|
|
// @ts-ignore
|
2021-09-13 20:41:05 +00:00
|
|
|
this.state.uploads = uploads;
|
|
|
|
}
|
|
|
|
if (!this.ranInitialUploadCheck) {
|
|
|
|
this.uploadCheck();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
2018-07-17 19:10:27 +00:00
|
|
|
|
2019-09-16 20:26:32 +00:00
|
|
|
uploadCheck = () => {
|
|
|
|
this.ranInitialUploadCheck = true;
|
|
|
|
const { uploads } = this.state;
|
2021-09-13 20:41:05 +00:00
|
|
|
uploads.forEach(async u => {
|
2019-09-16 20:26:32 +00:00
|
|
|
if (!RocketChat.isUploadActive(u.path)) {
|
|
|
|
try {
|
2019-09-25 21:31:53 +00:00
|
|
|
const db = database.active;
|
2022-03-02 14:18:01 +00:00
|
|
|
await db.write(async () => {
|
2019-09-16 20:26:32 +00:00
|
|
|
await u.update(() => {
|
|
|
|
u.error = true;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} catch (e) {
|
|
|
|
log(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2021-09-13 20:41:05 +00:00
|
|
|
};
|
2019-09-16 20:26:32 +00:00
|
|
|
|
2022-03-02 14:18:01 +00:00
|
|
|
deleteUpload = async (item: TUploadModel) => {
|
2019-02-01 13:30:12 +00:00
|
|
|
try {
|
2019-09-16 20:26:32 +00:00
|
|
|
const db = database.active;
|
2022-03-02 14:18:01 +00:00
|
|
|
await db.write(async () => {
|
2019-09-16 20:26:32 +00:00
|
|
|
await item.destroyPermanently();
|
|
|
|
});
|
2019-02-01 13:30:12 +00:00
|
|
|
} catch (e) {
|
2019-08-23 13:18:47 +00:00
|
|
|
log(e);
|
2019-02-01 13:30:12 +00:00
|
|
|
}
|
2021-09-13 20:41:05 +00:00
|
|
|
};
|
2018-07-17 19:10:27 +00:00
|
|
|
|
2022-03-02 14:18:01 +00:00
|
|
|
cancelUpload = async (item: TUploadModel) => {
|
2018-07-17 19:10:27 +00:00
|
|
|
try {
|
2019-09-16 20:26:32 +00:00
|
|
|
await RocketChat.cancelUpload(item);
|
2018-07-17 19:10:27 +00:00
|
|
|
} catch (e) {
|
2019-08-23 13:18:47 +00:00
|
|
|
log(e);
|
2018-07-17 19:10:27 +00:00
|
|
|
}
|
2021-09-13 20:41:05 +00:00
|
|
|
};
|
2018-07-17 19:10:27 +00:00
|
|
|
|
2022-03-02 14:18:01 +00:00
|
|
|
tryAgain = async (item: TUploadModel) => {
|
2019-07-29 16:33:28 +00:00
|
|
|
const { rid, baseUrl: server, user } = this.props;
|
2018-09-25 19:28:42 +00:00
|
|
|
|
2018-07-17 19:10:27 +00:00
|
|
|
try {
|
2019-09-16 20:26:32 +00:00
|
|
|
const db = database.active;
|
2022-03-02 14:18:01 +00:00
|
|
|
await db.write(async () => {
|
2019-09-16 20:26:32 +00:00
|
|
|
await item.update(() => {
|
|
|
|
item.error = false;
|
|
|
|
});
|
2018-07-17 19:10:27 +00:00
|
|
|
});
|
2019-07-29 16:33:28 +00:00
|
|
|
await RocketChat.sendFileMessage(rid, item, undefined, server, user);
|
2018-07-17 19:10:27 +00:00
|
|
|
} catch (e) {
|
2019-08-23 13:18:47 +00:00
|
|
|
log(e);
|
2018-07-17 19:10:27 +00:00
|
|
|
}
|
2021-09-13 20:41:05 +00:00
|
|
|
};
|
2018-07-17 19:10:27 +00:00
|
|
|
|
2022-03-02 14:18:01 +00:00
|
|
|
renderItemContent = (item: TUploadModel) => {
|
2020-06-17 17:35:58 +00:00
|
|
|
const { width, theme } = this.props;
|
2018-09-25 19:28:42 +00:00
|
|
|
|
2018-07-17 19:10:27 +00:00
|
|
|
if (!item.error) {
|
2021-09-13 20:41:05 +00:00
|
|
|
return [
|
|
|
|
<View key='row' style={styles.row}>
|
2022-03-02 14:18:01 +00:00
|
|
|
<CustomIcon name='attach' size={20} color={themes[theme!].auxiliaryText} />
|
2021-09-13 20:41:05 +00:00
|
|
|
<Text
|
2022-03-02 14:18:01 +00:00
|
|
|
style={[styles.descriptionContainer, styles.descriptionText, { color: themes[theme!].auxiliaryText }]}
|
2021-09-13 20:41:05 +00:00
|
|
|
numberOfLines={1}>
|
|
|
|
{I18n.t('Uploading')} {item.name}
|
|
|
|
</Text>
|
2022-03-02 14:18:01 +00:00
|
|
|
<CustomIcon name='close' size={20} color={themes[theme!].auxiliaryText} onPress={() => this.cancelUpload(item)} />
|
2021-09-13 20:41:05 +00:00
|
|
|
</View>,
|
|
|
|
<View
|
|
|
|
key='progress'
|
2022-03-02 14:18:01 +00:00
|
|
|
style={[styles.progress, { width: (width * (item.progress ?? 0)) / 100, backgroundColor: themes[theme!].tintColor }]}
|
2021-09-13 20:41:05 +00:00
|
|
|
/>
|
|
|
|
];
|
2018-07-17 19:10:27 +00:00
|
|
|
}
|
|
|
|
return (
|
|
|
|
<View style={styles.row}>
|
2022-03-02 14:18:01 +00:00
|
|
|
<CustomIcon name='warning' size={20} color={themes[theme!].dangerColor} />
|
2018-07-17 19:10:27 +00:00
|
|
|
<View style={styles.descriptionContainer}>
|
2022-03-02 14:18:01 +00:00
|
|
|
<Text style={[styles.descriptionText, { color: themes[theme!].auxiliaryText }]} numberOfLines={1}>
|
2021-09-13 20:41:05 +00:00
|
|
|
{I18n.t('Error_uploading')} {item.name}
|
|
|
|
</Text>
|
2018-07-17 19:10:27 +00:00
|
|
|
<TouchableOpacity onPress={() => this.tryAgain(item)}>
|
2022-03-02 14:18:01 +00:00
|
|
|
<Text style={[styles.tryAgainButtonText, { color: themes[theme!].tintColor }]}>{I18n.t('Try_again')}</Text>
|
2018-07-17 19:10:27 +00:00
|
|
|
</TouchableOpacity>
|
|
|
|
</View>
|
2022-03-02 14:18:01 +00:00
|
|
|
<CustomIcon name='close' size={20} color={themes[theme!].auxiliaryText} onPress={() => this.deleteUpload(item)} />
|
2018-07-17 19:10:27 +00:00
|
|
|
</View>
|
|
|
|
);
|
2021-09-13 20:41:05 +00:00
|
|
|
};
|
2018-07-17 19:10:27 +00:00
|
|
|
|
2019-09-16 20:26:32 +00:00
|
|
|
// TODO: transform into stateless and update based on its own observable changes
|
2022-03-02 14:18:01 +00:00
|
|
|
renderItem = (item: TUploadModel, index: number) => {
|
2019-12-04 16:39:53 +00:00
|
|
|
const { theme } = this.props;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<View
|
|
|
|
key={item.path}
|
|
|
|
style={[
|
|
|
|
styles.item,
|
|
|
|
index !== 0 ? { marginTop: 10 } : {},
|
|
|
|
{
|
2022-03-02 14:18:01 +00:00
|
|
|
backgroundColor: themes[theme!].chatComponentBackground,
|
|
|
|
borderColor: themes[theme!].borderColor
|
2019-12-04 16:39:53 +00:00
|
|
|
}
|
2021-09-13 20:41:05 +00:00
|
|
|
]}>
|
2019-12-04 16:39:53 +00:00
|
|
|
{this.renderItemContent(item)}
|
|
|
|
</View>
|
|
|
|
);
|
2021-09-13 20:41:05 +00:00
|
|
|
};
|
2018-07-17 19:10:27 +00:00
|
|
|
|
|
|
|
render() {
|
|
|
|
const { uploads } = this.state;
|
2021-09-13 20:41:05 +00:00
|
|
|
return <ScrollView style={styles.container}>{uploads.map((item, i) => this.renderItem(item, i))}</ScrollView>;
|
2018-07-17 19:10:27 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-07 13:51:34 +00:00
|
|
|
|
2020-06-17 17:35:58 +00:00
|
|
|
export default withTheme(UploadProgress);
|