display circular download progress on file page

This commit is contained in:
Akinwale Ariwodola 2020-01-20 23:11:14 +01:00
parent 3717a8072b
commit 3f21c4e08c
8 changed files with 69 additions and 29 deletions

5
package-lock.json generated
View file

@ -9905,6 +9905,11 @@
"prop-types": "^15.5.10" "prop-types": "^15.5.10"
} }
}, },
"react-native-progress-circle": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/react-native-progress-circle/-/react-native-progress-circle-2.1.0.tgz",
"integrity": "sha512-VP0s92bgbTMQy4hQzPU4LlGyFj3z5u7i1HYFG8/yzXXfGkX1cxKS4xOlE+OTaObWC99w7Bodi3h8R7En2nQPYw=="
},
"react-native-reanimated": { "react-native-reanimated": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-1.4.0.tgz", "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-1.4.0.tgz",

View file

@ -30,6 +30,7 @@
"react-native-image-zoom-viewer": "^2.2.5", "react-native-image-zoom-viewer": "^2.2.5",
"react-native-password-strength-meter": "^0.0.2", "react-native-password-strength-meter": "^0.0.2",
"react-native-phone-input": "lbryio/react-native-phone-input", "react-native-phone-input": "lbryio/react-native-phone-input",
"react-native-progress-circle": "2.1.0",
"react-native-reanimated": "1.4.0", "react-native-reanimated": "1.4.0",
"react-native-safe-area-context": "^0.6.2", "react-native-safe-area-context": "^0.6.2",
"react-native-snackbar": "2.0.4", "react-native-snackbar": "2.0.4",

View file

@ -204,7 +204,7 @@ window.store = store;
const persistor = persistStore(store, null, err => { const persistor = persistStore(store, null, err => {
if (err) { if (err) {
console.log('Unable to load saved SETTINGS'); // console.log('Unable to load saved SETTINGS');
} }
}); });
window.persistor = persistor; window.persistor = persistor;

View file

@ -38,6 +38,7 @@ import FloatingWalletBalance from 'component/floatingWalletBalance';
import Link from 'component/link'; import Link from 'component/link';
import MediaPlayer from 'component/mediaPlayer'; import MediaPlayer from 'component/mediaPlayer';
import ModalTipView from 'component/modalTipView'; import ModalTipView from 'component/modalTipView';
import ProgressCircle from 'react-native-progress-circle';
import RelatedContent from 'component/relatedContent'; import RelatedContent from 'component/relatedContent';
import SubscribeButton from 'component/subscribeButton'; import SubscribeButton from 'component/subscribeButton';
import SubscribeNotificationButton from 'component/subscribeNotificationButton'; import SubscribeNotificationButton from 'component/subscribeNotificationButton';
@ -118,6 +119,7 @@ class FilePage extends React.PureComponent {
NativeModules.Firebase.setCurrentScreen('File').then(result => { NativeModules.Firebase.setCurrentScreen('File').then(result => {
const { setPlayerVisible } = this.props; const { setPlayerVisible } = this.props;
DeviceEventEmitter.addListener('onDownloadAborted', this.handleDownloadAborted);
DeviceEventEmitter.addListener('onStoragePermissionGranted', this.handleStoragePermissionGranted); DeviceEventEmitter.addListener('onStoragePermissionGranted', this.handleStoragePermissionGranted);
DeviceEventEmitter.addListener('onStoragePermissionRefused', this.handleStoragePermissionRefused); DeviceEventEmitter.addListener('onStoragePermissionRefused', this.handleStoragePermissionRefused);
@ -182,11 +184,7 @@ class FilePage extends React.PureComponent {
this.onComponentFocused(); this.onComponentFocused();
} }
if ( if (failedPurchaseUris.includes(uri) && prevPurchaseUriErrorMessage !== purchaseUriErrorMessage) {
failedPurchaseUris.includes(uri) &&
!purchasedUris.includes(uri) &&
prevPurchaseUriErrorMessage !== purchaseUriErrorMessage
) {
if (purchaseUriErrorMessage && purchaseUriErrorMessage.trim().length > 0) { if (purchaseUriErrorMessage && purchaseUriErrorMessage.trim().length > 0) {
notify({ message: purchaseUriErrorMessage, isError: true }); notify({ message: purchaseUriErrorMessage, isError: true });
} }
@ -425,10 +423,29 @@ class FilePage extends React.PureComponent {
if (window.currentMediaInfo) { if (window.currentMediaInfo) {
window.currentMediaInfo = null; window.currentMediaInfo = null;
} }
DeviceEventEmitter.removeListener('onDownloadAborted', this.handleDownloadAborted);
DeviceEventEmitter.removeListener('onStoragePermissionGranted', this.handleStoragePermissionGranted); DeviceEventEmitter.removeListener('onStoragePermissionGranted', this.handleStoragePermissionGranted);
DeviceEventEmitter.removeListener('onStoragePermissionRefused', this.handleStoragePermissionRefused); DeviceEventEmitter.removeListener('onStoragePermissionRefused', this.handleStoragePermissionRefused);
} }
handleDownloadAborted = evt => {
const { deletePurchasedUri, fileInfo, stopDownload } = this.props;
const { uri, outpoint } = evt;
const purchaseUrl = normalizeURI(this.getPurchaseUrl());
if (purchaseUrl === uri) {
stopDownload(uri, fileInfo);
deletePurchasedUri(uri);
NativeModules.UtilityModule.deleteDownload(normalizeURI(uri));
this.setState({
downloadPressed: false,
fileViewLogged: false,
mediaLoaded: false,
stopDownloadConfirmed: true,
});
}
};
handleStoragePermissionGranted = () => { handleStoragePermissionGranted = () => {
// permission was allowed. proceed to download // permission was allowed. proceed to download
const { notify } = this.props; const { notify } = this.props;
@ -1208,20 +1225,33 @@ class FilePage extends React.PureComponent {
{!canEdit && ( {!canEdit && (
<View style={filePageStyle.sharedLargeButton}> <View style={filePageStyle.sharedLargeButton}>
{(!fileInfo || (fileInfo.written_bytes <= 0 && !completed)) && ( {!this.state.downloadPressed &&
(!fileInfo || !fileInfo.download_path || (fileInfo.written_bytes <= 0 && !completed)) && (
<TouchableOpacity style={filePageStyle.innerLargeButton} onPress={this.onDownloadPressed}> <TouchableOpacity style={filePageStyle.innerLargeButton} onPress={this.onDownloadPressed}>
<Icon name={'download'} size={16} style={filePageStyle.largeButtonIcon} /> <Icon name={'download'} size={16} style={filePageStyle.largeButtonIcon} />
<Text style={filePageStyle.largeButtonText}>{__('Download')}</Text> <Text style={filePageStyle.largeButtonText}>{__('Download')}</Text>
</TouchableOpacity> </TouchableOpacity>
)} )}
{this.state.downloadPressed && (!fileInfo || fileInfo.written_bytes === 0) && (
<ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />
)}
{!completed && {!completed &&
fileInfo && fileInfo &&
fileInfo.written_bytes > 0 && fileInfo.written_bytes > 0 &&
fileInfo.written_bytes < fileInfo.total_bytes && fileInfo.written_bytes < fileInfo.total_bytes &&
!this.state.stopDownloadConfirmed && ( !this.state.stopDownloadConfirmed && (
<TouchableOpacity style={filePageStyle.innerLargeButton} onPress={this.onStopDownloadPressed}> <TouchableOpacity style={filePageStyle.innerLargeButton} onPress={this.onStopDownloadPressed}>
<Icon name={'stop'} size={16} style={filePageStyle.largeButtonIcon} /> <ProgressCircle
percent={(fileInfo.written_bytes / fileInfo.total_bytes) * 100}
radius={9}
borderWidth={2}
shadowColor={Colors.ActionGrey}
color={Colors.NextLbryGreen}
>
<Icon name={'stop'} size={6} style={filePageStyle.largeButtonIcon} />
</ProgressCircle>
<Text style={filePageStyle.largeButtonText}>{__('Stop')}</Text> <Text style={filePageStyle.largeButtonText}>{__('Stop')}</Text>
</TouchableOpacity> </TouchableOpacity>
)} )}

View file

@ -11,7 +11,7 @@ import Button from 'component/button';
import ProgressBar from 'component/progressBar'; import ProgressBar from 'component/progressBar';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Constants, { DrawerRoutes } from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants, { DrawerRoutes, InnerDrawerRoutes } from 'constants'; // eslint-disable-line node/no-deprecated-api
import splashStyle from 'styles/splash'; import splashStyle from 'styles/splash';
import RNFS from 'react-native-fs'; import RNFS from 'react-native-fs';
@ -60,10 +60,10 @@ class SplashScreen extends React.PureComponent {
// no launch url, check if there's a last route in stack to navigate to. // no launch url, check if there's a last route in stack to navigate to.
const { route, params } = lastRouteInStack; const { route, params } = lastRouteInStack;
if (route) { if (route) {
if (!DrawerRoutes.includes(route) && isURIValid(route)) { if (DrawerRoutes.includes(route)) {
navigateToUri(navigation, route);
} else {
navigation.navigate({ routeName: route, params }); navigation.navigate({ routeName: route, params });
} else if (!InnerDrawerRoutes.includes(route) && isURIValid(route)) {
navigateToUri(navigation, route);
} }
} }
} }

View file

@ -59,22 +59,24 @@ export function doCompleteDownload(uri, outpoint, fileInfo) {
export function doStopDownloadingFile(uri, fileInfo) { export function doStopDownloadingFile(uri, fileInfo) {
return dispatch => { return dispatch => {
let params = { status: 'stop' }; let params = { status: 'stop' };
if (fileInfo.sd_hash) { if (fileInfo) {
params.sd_hash = fileInfo.sd_hash; if (fileInfo.sd_hash) {
} params.sd_hash = fileInfo.sd_hash;
if (fileInfo.stream_hash) { }
params.stream_hash = fileInfo.stream_hash; if (fileInfo.stream_hash) {
} params.stream_hash = fileInfo.stream_hash;
}
Lbry.file_set_status(params).then(() => { Lbry.file_set_status(params).then(() => {
dispatch({ dispatch({
type: ACTIONS.DOWNLOADING_CANCELED, type: ACTIONS.DOWNLOADING_CANCELED,
data: { uri, outpoint: fileInfo.outpoint }, data: { uri, outpoint: fileInfo.outpoint },
});
// Should also delete the file after the user stops downloading
dispatch(doDeleteFile(fileInfo.outpoint, uri));
}); });
}
// Should also delete the file after the user stops downloading
dispatch(doDeleteFile(fileInfo.outpoint, uri));
});
}; };
} }
@ -95,7 +97,7 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
}); });
// If the file is for a claim we published then also abandon the claim // If the file is for a claim we published then also abandon the claim
/*const myClaimsOutpoints = selectMyClaimsOutpoints(state); /* const myClaimsOutpoints = selectMyClaimsOutpoints(state);
if (abandonClaim && myClaimsOutpoints.indexOf(outpoint) !== -1) { if (abandonClaim && myClaimsOutpoints.indexOf(outpoint) !== -1) {
const byOutpoint = selectFileInfosByOutpoint(state); const byOutpoint = selectFileInfosByOutpoint(state);
const fileInfo = byOutpoint[outpoint]; const fileInfo = byOutpoint[outpoint];
@ -106,7 +108,7 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
dispatch(doAbandonClaim(txid, nout)); dispatch(doAbandonClaim(txid, nout));
} }
}*/ } */
dispatch({ dispatch({
type: ACTIONS.FILE_DELETE, type: ACTIONS.FILE_DELETE,

View file

@ -12,6 +12,7 @@ const Colors = {
TagGreen: '#e3f6f1', TagGreen: '#e3f6f1',
TagGrape: '#da77f255', TagGrape: '#da77f255',
LightGrey: '#cccccc', LightGrey: '#cccccc',
ActionGrey: '#aaaaaa',
LighterGrey: '#e5e5e5', LighterGrey: '#e5e5e5',
Orange: '#ffbb00', Orange: '#ffbb00',
Red: '#ff0000', Red: '#ff0000',

View file

@ -399,9 +399,10 @@ const filePageStyle = StyleSheet.create({
flex: 0.2, flex: 0.2,
}, },
largeButtonIcon: { largeButtonIcon: {
color: Colors.DescriptionGrey, color: Colors.ActionGrey,
}, },
largeButtonText: { largeButtonText: {
color: Colors.ActionGrey,
fontFamily: 'Inter-Regular', fontFamily: 'Inter-Regular',
fontSize: 12, fontSize: 12,
marginTop: 4, marginTop: 4,