From c1f73c2766b60e7a1141dbf3c3833b480f215b83 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sat, 28 Dec 2019 00:46:11 +0100 Subject: [PATCH 1/4] streamlined first run --- src/component/fileDownloadButton/view.js | 15 +-- src/i18n.js | 5 +- src/index.js | 1 + src/page/file/view.js | 148 +++++++++++++++-------- src/page/firstRun/view.js | 17 ++- 5 files changed, 118 insertions(+), 68 deletions(-) diff --git a/src/component/fileDownloadButton/view.js b/src/component/fileDownloadButton/view.js index 8b2c0fe..06a458f 100644 --- a/src/component/fileDownloadButton/view.js +++ b/src/component/fileDownloadButton/view.js @@ -45,6 +45,7 @@ class FileDownloadButton extends React.PureComponent { doPause, style, openFile, + onFileActionPress, onButtonLayout, } = this.props; @@ -72,19 +73,7 @@ class FileDownloadButton extends React.PureComponent { text={isPlayable ? __('Play') : isViewable ? __('View') : __('Download')} onLayout={onButtonLayout} style={[style, fileDownloadButtonStyle.container]} - onPress={() => { - NativeModules.Firebase.track('purchase_uri', { uri: uri }); - purchaseUri(uri, costInfo, !isPlayable); - if (NativeModules.UtilityModule) { - NativeModules.UtilityModule.checkDownloads(); - } - if (isPlayable && onPlay) { - this.props.onPlay(); - } - if (isViewable && onView) { - this.props.onView(); - } - }} + onPress={onFileActionPress} /> ); } else if (fileInfo && fileInfo.download_path) { diff --git a/src/i18n.js b/src/i18n.js index 96ca1ae..fd19c7b 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -52,8 +52,9 @@ function checkMessageAndSave(message, messagesFilePath) { ); */ }) .catch(err => { - if (err) { - throw err; + if (err && !isProduction) { + // only do this when not in production + console.error(err); } }); } diff --git a/src/index.js b/src/index.js index a82ebf5..74b01f0 100644 --- a/src/index.js +++ b/src/index.js @@ -57,6 +57,7 @@ window.__ = __; const globalExceptionHandler = (error, isFatal) => { if (error && NativeModules.Firebase) { + console.log(error); NativeModules.Firebase.logException(isFatal, error.message ? error.message : 'No message', JSON.stringify(error)); } }; diff --git a/src/page/file/view.js b/src/page/file/view.js index 403df20..5b077c0 100644 --- a/src/page/file/view.js +++ b/src/page/file/view.js @@ -101,29 +101,27 @@ class FilePage extends React.PureComponent { onComponentFocused = () => { StatusBar.setHidden(false); - NativeModules.Firebase.setCurrentScreen('File'); + NativeModules.Firebase.setCurrentScreen('File').then(result => { + DeviceEventEmitter.addListener('onDownloadStarted', this.handleDownloadStarted); + DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated); + DeviceEventEmitter.addListener('onDownloadCompleted', this.handleDownloadCompleted); + DeviceEventEmitter.addListener('onStoragePermissionGranted', this.handleStoragePermissionGranted); + DeviceEventEmitter.addListener('onStoragePermissionRefused', this.handleStoragePermissionRefused); - DeviceEventEmitter.addListener('onDownloadStarted', this.handleDownloadStarted); - DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated); - DeviceEventEmitter.addListener('onDownloadCompleted', this.handleDownloadCompleted); + const { fetchMyClaims, fileInfo, isResolvingUri, resolveUri, navigation } = this.props; + const { uri, uriVars } = navigation.state.params; + this.setState({ uri, uriVars }); - const { fetchMyClaims, fileInfo, isResolvingUri, resolveUri, navigation } = this.props; - const { uri, uriVars } = navigation.state.params; - this.setState({ uri, uriVars }); + if (!isResolvingUri) resolveUri(uri); - if (!isResolvingUri) resolveUri(uri); + this.fetchFileInfo(this.props); + this.fetchCostInfo(this.props); - this.fetchFileInfo(this.props); - this.fetchCostInfo(this.props); + fetchMyClaims(); - fetchMyClaims(); - - if (NativeModules.Firebase) { NativeModules.Firebase.track('open_file_page', { uri: uri }); - } - if (NativeModules.UtilityModule) { NativeModules.UtilityModule.keepAwakeOn(); - } + }); }; componentDidMount() { @@ -236,9 +234,9 @@ class FilePage extends React.PureComponent { resolveUri(uri); } - if (title && !this.state.didSearchRecommended) { + /* if (title && !this.state.didSearchRecommended) { this.setState({ didSearchRecommended: true }, () => searchRecommended(title)); - } + } */ // Returned to the page. If mediaLoaded, and currentMediaInfo is different, update if (this.state.mediaLoaded && window.currentMediaInfo && window.currentMediaInfo.uri !== this.state.uri) { @@ -402,6 +400,8 @@ class FilePage extends React.PureComponent { DeviceEventEmitter.removeListener('onDownloadStarted', this.handleDownloadStarted); DeviceEventEmitter.removeListener('onDownloadUpdated', this.handleDownloadUpdated); DeviceEventEmitter.removeListener('onDownloadCompleted', this.handleDownloadCompleted); + DeviceEventEmitter.removeListener('onStoragePermissionGranted', this.handleStoragePermissionGranted); + DeviceEventEmitter.removeListener('onStoragePermissionRefused', this.handleStoragePermissionRefused); } handleDownloadStarted = evt => { @@ -422,6 +422,32 @@ class FilePage extends React.PureComponent { completeDownload(uri, outpoint, fileInfo); }; + handleStoragePermissionGranted = () => { + // permission was allowed. proceed to download + const { notify } = this.props; + + // update the configured download folder and then download + NativeModules.UtilityModule.getDownloadDirectory().then(downloadDirectory => { + Lbry.settings_set({ + key: 'download_directory', + value: downloadDirectory, + }) + .then(() => this.performDownload()) + .catch(() => { + notify({ message: 'The file could not be downloaded to the default download directory.', isError: true }); + }); + }); + }; + + handleStoragePermissionRefused = () => { + const { notify } = this.props; + this.setState({ downloadPressed: false }); + notify({ + message: __('The file could not be downloaded because the permission to write to storage was not granted.'), + isError: true, + }); + }; + localUriForFileInfo = fileInfo => { if (!fileInfo) { return null; @@ -589,14 +615,50 @@ class FilePage extends React.PureComponent { )); }; - onFileDownloadButtonPlayed = () => { - const { setPlayerVisible } = this.props; - this.startTime = Date.now(); - this.setState({ downloadPressed: true, autoPlayMedia: true, stopDownloadConfirmed: false }); - setPlayerVisible(); + onFileDownloadButtonPressed = () => { + const { costInfo, contentType, purchaseUri, setPlayerVisible } = this.props; + const { uri } = this.state; + const mediaType = Lbry.getMediaType(contentType); + const isPlayable = mediaType === 'video' || mediaType === 'audio'; + const isViewable = mediaType === 'image' || mediaType === 'text'; + + NativeModules.Firebase.track('purchase_uri', { uri: uri }); + + if (!isPlayable) { + this.checkStoragePermissionForDownload(); + } else { + purchaseUri(uri, costInfo, !isPlayable); + } + + if (isPlayable) { + this.startTime = Date.now(); + this.setState({ downloadPressed: true, autoPlayMedia: true, stopDownloadConfirmed: false }); + setPlayerVisible(); + } + if (isViewable) { + this.setState({ downloadPressed: true }); + } }; onDownloadPressed = () => { + this.checkStoragePermissionForDownload(); + }; + + checkStoragePermissionForDownload = () => { + this.setState({ downloadPressed: true }, () => { + // check if we the permission to write to external storage has been granted + NativeModules.UtilityModule.canReadWriteStorage().then(canReadWrite => { + if (!canReadWrite) { + // request permission + NativeModules.UtilityModule.requestStoragePermission(); + } else { + this.performDownload(); + } + }); + }); + }; + + performDownload = () => { const { claim, costInfo, purchaseUri } = this.props; this.setState( { @@ -604,7 +666,10 @@ class FilePage extends React.PureComponent { autoPlayMedia: false, stopDownloadConfirmed: false, }, - () => purchaseUri(claim.permanent_url, costInfo, true) + () => { + purchaseUri(claim.permanent_url, costInfo, true); + NativeModules.UtilityModule.checkDownloads(); + } ); }; @@ -621,14 +686,7 @@ class FilePage extends React.PureComponent { // file already in library or URI already purchased, use fileGet directly this.setState({ fileGetStarted: true }, () => fileGet(uri, true)); } else { - this.setState( - { - downloadPressed: true, - autoPlayMedia: false, - stopDownloadConfirmed: false, - }, - () => purchaseUri(uri, costInfo, true) - ); + this.checkStoragePermissionForDownload(); } }; @@ -665,17 +723,6 @@ class FilePage extends React.PureComponent { } }; - onMediaContainerPressed = () => { - const { costInfo, contentType, purchaseUri } = this.props; - const { uri } = this.state; - const mediaType = Lbry.getMediaType(contentType); - const isPlayable = mediaType === 'video' || mediaType === 'audio'; - purchaseUri(uri, costInfo, isPlayable); - if (isPlayable) { - this.onFileDownloadButtonPlayed(); - } - }; - render() { const { balance, @@ -835,10 +882,12 @@ class FilePage extends React.PureComponent { if (fileInfo && !this.state.autoDownloadStarted && this.state.uriVars && this.state.uriVars.download === 'true') { this.setState({ autoDownloadStarted: true }, () => { - purchaseUri(uri, costInfo, !isPlayable); - if (NativeModules.UtilityModule) { - NativeModules.UtilityModule.checkDownloads(); + if (!isPlayable) { + this.checkStoragePermissionForDownload(); + } else { + purchaseUri(uri, costInfo, !isPlayable); } + NativeModules.UtilityModule.checkDownloads(); }); } @@ -872,7 +921,7 @@ class FilePage extends React.PureComponent { {(canOpen || (!fileInfo || (isPlayable && !canLoadMedia)) || (!canOpen && fileInfo)) && ( this.openFile(localFileUri, mediaType)} isPlayable={isPlayable} isViewable={isViewable} - onPlay={this.onFileDownloadButtonPlayed} - onView={() => this.setState({ downloadPressed: true })} + onFileActionPress={this.onFileDownloadButtonPressed} onButtonLayout={() => this.setState({ downloadButtonShown: true })} /> )} @@ -1159,7 +1207,7 @@ class FilePage extends React.PureComponent { {isSearchingRecommendContent && ( )} - {!isSearchingRecommendContent && recommendedContent && recommendedContent.length > 0 && ( + {false && !isSearchingRecommendContent && recommendedContent && recommendedContent.length > 0 && ( )} diff --git a/src/page/firstRun/view.js b/src/page/firstRun/view.js index d1bc448..d7a156e 100644 --- a/src/page/firstRun/view.js +++ b/src/page/firstRun/view.js @@ -228,7 +228,13 @@ class FirstRunScreen extends React.PureComponent { handleContinuePressed = () => { const { notify, user, hasSyncedWallet } = this.props; const pageIndex = FirstRunScreen.pages.indexOf(this.state.currentPage); - if (Constants.FIRST_RUN_PAGE_WALLET === this.state.currentPage) { + + if (Constants.FIRST_RUN_PAGE_WELCOME === this.state.currentPage) { + // only show the welcome screen on first run + this.closeFinalPage(); + } + + /* if (Constants.FIRST_RUN_PAGE_WALLET === this.state.currentPage) { // do apply sync to check if the password is valid if (hasSyncedWallet) { this.checkWalletPassword(); @@ -256,7 +262,7 @@ class FirstRunScreen extends React.PureComponent { } else { this.showNextPage(); } - } + } */ }; handleEmailCollectPageContinue() { @@ -500,7 +506,12 @@ class FirstRunScreen extends React.PureComponent { {Constants.FIRST_RUN_PAGE_SKIP_ACCOUNT !== this.state.currentPage && Constants.FIRST_RUN_PAGE_EMAIL_VERIFY !== this.state.currentPage && ( - {Constants.FIRST_RUN_PAGE_WALLET === this.state.currentPage ? __('Use LBRY') : __('Continue')} » + {[Constants.FIRST_RUN_PAGE_WALLET, Constants.FIRST_RUN_PAGE_WELCOME].includes( + this.state.currentPage + ) + ? __('Use LBRY') + : __('Continue')}{' '} + » )} -- 2.45.2 From a32c7f32f8c05cf9bbbe9aee1fbfbf467b40fff6 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sat, 28 Dec 2019 01:12:07 +0100 Subject: [PATCH 2/4] download button tweaks --- src/component/fileDownloadButton/view.js | 3 ++ src/page/file/view.js | 40 +++++++++--------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/component/fileDownloadButton/view.js b/src/component/fileDownloadButton/view.js index 06a458f..d2f7ae8 100644 --- a/src/component/fileDownloadButton/view.js +++ b/src/component/fileDownloadButton/view.js @@ -49,6 +49,9 @@ class FileDownloadButton extends React.PureComponent { onButtonLayout, } = this.props; + console.log('uri=' + uri); + console.log(fileInfo); + if ((fileInfo && !fileInfo.stopped) || loading || downloading) { const progress = fileInfo && fileInfo.written_bytes ? (fileInfo.written_bytes / fileInfo.total_bytes) * 100 : 0, label = fileInfo ? __('%progress%% complete', { progress: progress.toFixed(0) }) : __('Connecting...'); diff --git a/src/page/file/view.js b/src/page/file/view.js index 5b077c0..77ef5fb 100644 --- a/src/page/file/view.js +++ b/src/page/file/view.js @@ -179,7 +179,8 @@ class FilePage extends React.PureComponent { (this.state.fileGetStarted || prevPurchasedUris.length !== purchasedUris.length) && NativeModules.UtilityModule ) { - if (purchasedUris.includes(uri)) { + const { permanent_url: permanentUrl } = claim; + if (purchasedUris.includes(uri) || purchasedUris.includes(permanentUrl)) { const { nout, txid } = claim; const outpoint = `${txid}:${nout}`; NativeModules.UtilityModule.queueDownload(outpoint); @@ -252,15 +253,7 @@ class FilePage extends React.PureComponent { const mediaType = Lbry.getMediaType(contentType); const isViewable = mediaType === 'image' || mediaType === 'text'; if (claim && costInfo && costInfo.cost === 0 && !this.state.autoGetAttempted && isViewable) { - this.setState( - { - autoGetAttempted: true, - downloadPressed: true, - autoPlayMedia: true, - stopDownloadConfirmed: false, - }, - () => purchaseUri(claim.permanent_url, costInfo, true) - ); + this.setState({ autoGetAttempted: true }, () => this.checkStoragePermissionForDownload()); } } @@ -429,7 +422,7 @@ class FilePage extends React.PureComponent { // update the configured download folder and then download NativeModules.UtilityModule.getDownloadDirectory().then(downloadDirectory => { Lbry.settings_set({ - key: 'download_directory', + key: 'download_dir', value: downloadDirectory, }) .then(() => this.performDownload()) @@ -616,12 +609,12 @@ class FilePage extends React.PureComponent { }; onFileDownloadButtonPressed = () => { - const { costInfo, contentType, purchaseUri, setPlayerVisible } = this.props; - const { uri } = this.state; + const { claim, costInfo, contentType, purchaseUri, setPlayerVisible } = this.props; const mediaType = Lbry.getMediaType(contentType); const isPlayable = mediaType === 'video' || mediaType === 'audio'; const isViewable = mediaType === 'image' || mediaType === 'text'; + const { permanent_url: uri } = claim; NativeModules.Firebase.track('purchase_uri', { uri: uri }); if (!isPlayable) { @@ -645,16 +638,14 @@ class FilePage extends React.PureComponent { }; checkStoragePermissionForDownload = () => { - this.setState({ downloadPressed: true }, () => { - // check if we the permission to write to external storage has been granted - NativeModules.UtilityModule.canReadWriteStorage().then(canReadWrite => { - if (!canReadWrite) { - // request permission - NativeModules.UtilityModule.requestStoragePermission(); - } else { - this.performDownload(); - } - }); + // check if we the permission to write to external storage has been granted + NativeModules.UtilityModule.canReadWriteStorage().then(canReadWrite => { + if (!canReadWrite) { + // request permission + NativeModules.UtilityModule.requestStoragePermission(); + } else { + this.performDownload(); + } }); }; @@ -957,8 +948,7 @@ class FilePage extends React.PureComponent { {((isPlayable && !completed && !canLoadMedia) || canOpen || - (!completed && !this.state.streamingMode)) && - !this.state.downloadPressed && ( + (!completed && !this.state.streamingMode)) && ( Date: Sat, 28 Dec 2019 10:59:30 +0100 Subject: [PATCH 3/4] fix downloads. file page tweaks. --- src/component/AppNavigator.js | 27 + src/component/fileDownloadButton/view.js | 8 - src/component/fileListItem/view.js | 8 +- src/component/relatedContent/view.js | 15 +- src/index.js | 3 +- src/page/file/index.js | 15 +- src/page/file/view.js | 915 +++++++++++------------ src/styles/fileList.js | 5 + 8 files changed, 498 insertions(+), 498 deletions(-) diff --git a/src/component/AppNavigator.js b/src/component/AppNavigator.js index a28da3c..9c83ca0 100644 --- a/src/component/AppNavigator.js +++ b/src/component/AppNavigator.js @@ -51,6 +51,7 @@ import { selectHashChanged, selectUser, } from 'lbryinc'; +import { doStartDownload, doUpdateDownload, doCompleteDownload } from 'redux/actions/file'; import { makeSelectClientSetting, selectFullscreenMode } from 'redux/selectors/settings'; import { decode as atob } from 'base-64'; import { dispatchNavigateBack, dispatchNavigateToUri, transformUrl } from 'utils/helper'; @@ -311,6 +312,10 @@ class AppWithNavigationState extends React.Component { this.emailVerifyCheckInterval = setInterval(() => this.checkEmailVerification(), 5000); Linking.addEventListener('url', this._handleUrl); + DeviceEventEmitter.addListener('onDownloadStarted', this.handleDownloadStarted); + DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated); + DeviceEventEmitter.addListener('onDownloadCompleted', this.handleDownloadCompleted); + // call /sync/get with interval this.syncGetInterval = setInterval(() => { this.setState({ syncHashChanged: false }); // reset local state @@ -345,7 +350,29 @@ class AppWithNavigationState extends React.Component { ); }; + handleDownloadStarted = evt => { + const { dispatch } = this.props; + const { uri, outpoint, fileInfo } = evt; + dispatch(doStartDownload(uri, outpoint, fileInfo)); + }; + + handleDownloadUpdated = evt => { + const { dispatch } = this.props; + const { uri, outpoint, fileInfo, progress } = evt; + dispatch(doUpdateDownload(uri, outpoint, fileInfo, progress)); + }; + + handleDownloadCompleted = evt => { + const { dispatch } = this.props; + const { uri, outpoint, fileInfo } = evt; + dispatch(doCompleteDownload(uri, outpoint, fileInfo)); + }; + componentWillUnmount() { + DeviceEventEmitter.removeListener('onDownloadStarted', this.handleDownloadStarted); + DeviceEventEmitter.removeListener('onDownloadUpdated', this.handleDownloadUpdated); + DeviceEventEmitter.removeListener('onDownloadCompleted', this.handleDownloadCompleted); + AppState.removeEventListener('change', this._handleAppStateChange); BackHandler.removeEventListener('hardwareBackPress'); Linking.removeEventListener('url', this._handleUrl); diff --git a/src/component/fileDownloadButton/view.js b/src/component/fileDownloadButton/view.js index d2f7ae8..cbb77b3 100644 --- a/src/component/fileDownloadButton/view.js +++ b/src/component/fileDownloadButton/view.js @@ -11,11 +11,6 @@ class FileDownloadButton extends React.PureComponent { } } - componentWillReceiveProps(nextProps) { - // this.checkAvailability(nextProps.uri); - // this.restartDownload(nextProps); - } - restartDownload(props) { const { downloading, fileInfo, uri, restartDownload } = props; @@ -49,9 +44,6 @@ class FileDownloadButton extends React.PureComponent { onButtonLayout, } = this.props; - console.log('uri=' + uri); - console.log(fileInfo); - if ((fileInfo && !fileInfo.stopped) || loading || downloading) { const progress = fileInfo && fileInfo.written_bytes ? (fileInfo.written_bytes / fileInfo.total_bytes) * 100 : 0, label = fileInfo ? __('%progress%% complete', { progress: progress.toFixed(0) }) : __('Connecting...'); diff --git a/src/component/fileListItem/view.js b/src/component/fileListItem/view.js index 7cb4c7c..a5f9664 100644 --- a/src/component/fileListItem/view.js +++ b/src/component/fileListItem/view.js @@ -158,7 +158,13 @@ class FileListItem extends React.PureComponent { )} {fileInfo && fileInfo.completed && fileInfo.download_path && ( - + )} {featuredResult && ( diff --git a/src/component/relatedContent/view.js b/src/component/relatedContent/view.js index 4e0630d..8f626f8 100644 --- a/src/component/relatedContent/view.js +++ b/src/component/relatedContent/view.js @@ -8,18 +8,11 @@ import fileListStyle from 'styles/fileList'; import relatedContentStyle from 'styles/relatedContent'; export default class RelatedContent extends React.PureComponent { - state = { - urlsResolved: false, - }; - - componentDidUpdate(prevProps) { + componentDidMount() { const { resolveUris, recommendedContent } = this.props; - - if (recommendedContent && recommendedContent.length > 0 && !this.state.urisResolved) { - this.setState({ urisResolved: true }, () => { - // batch resolve the uris - resolveUris(recommendedContent); - }); + if (recommendedContent && recommendedContent.length > 0) { + // batch resolve the uris + resolveUris(recommendedContent); } } diff --git a/src/index.js b/src/index.js index 74b01f0..c3cf079 100644 --- a/src/index.js +++ b/src/index.js @@ -57,8 +57,7 @@ window.__ = __; const globalExceptionHandler = (error, isFatal) => { if (error && NativeModules.Firebase) { - console.log(error); - NativeModules.Firebase.logException(isFatal, error.message ? error.message : 'No message', JSON.stringify(error)); + NativeModules.Firebase.logException(!!isFatal, error.message ? error.message : 'No message', JSON.stringify(error)); } }; setJSExceptionHandler(globalExceptionHandler, true); diff --git a/src/page/file/index.js b/src/page/file/index.js index 263b305..36dd480 100644 --- a/src/page/file/index.js +++ b/src/page/file/index.js @@ -8,6 +8,7 @@ import { doPurchaseUri, doDeletePurchasedUri, doResolveUri, + doResolveUris, doSearch, doSendTip, doToast, @@ -28,6 +29,7 @@ import { selectPurchasedUris, selectFailedPurchaseUris, selectPurchaseUriErrorMessage, + selectResolvingUris, selectIsSearching, } from 'lbry-redux'; import { @@ -39,13 +41,7 @@ import { selectRewardContentClaimIds, selectBlackListedOutpoints, } from 'lbryinc'; -import { - doStartDownload, - doUpdateDownload, - doCompleteDownload, - doDeleteFile, - doStopDownloadingFile, -} from 'redux/actions/file'; +import { doDeleteFile, doStopDownloadingFile } from 'redux/actions/file'; import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doToggleFullscreenMode } from 'redux/actions/settings'; import { selectDrawerStack } from 'redux/selectors/drawer'; @@ -77,6 +73,7 @@ const select = (state, props) => { thumbnail: makeSelectThumbnailForUri(contentUri)(state), title: makeSelectTitleForUri(contentUri)(state), recommendedContent: makeSelectRecommendedContentForUri(contentUri)(state), + resolvingUris: selectResolvingUris(state), isSearchingRecommendContent: selectIsSearching(state), viewCount: makeSelectViewCountForUri(contentUri)(state), }; @@ -100,14 +97,12 @@ const perform = dispatch => ({ purchaseUri: (uri, costInfo, saveFile) => dispatch(doPurchaseUri(uri, costInfo, saveFile)), deletePurchasedUri: uri => dispatch(doDeletePurchasedUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)), + resolveUris: uris => dispatch(doResolveUris(uris)), searchRecommended: query => dispatch(doSearch(query, 20, undefined, true)), sendTip: (amount, claimId, isSupport, successCallback, errorCallback) => dispatch(doSendTip(amount, claimId, isSupport, successCallback, errorCallback)), setPlayerVisible: () => dispatch(doSetPlayerVisible(true)), stopDownload: (uri, fileInfo) => dispatch(doStopDownloadingFile(uri, fileInfo)), - startDownload: (uri, outpoint, fileInfo) => dispatch(doStartDownload(uri, outpoint, fileInfo)), - updateDownload: (uri, outpoint, fileInfo, progress) => dispatch(doUpdateDownload(uri, outpoint, fileInfo, progress)), - completeDownload: (uri, outpoint, fileInfo) => dispatch(doCompleteDownload(uri, outpoint, fileInfo)), toggleFullscreenMode: mode => dispatch(doToggleFullscreenMode(mode)), }); diff --git a/src/page/file/view.js b/src/page/file/view.js index 77ef5fb..0cc1156 100644 --- a/src/page/file/view.js +++ b/src/page/file/view.js @@ -72,6 +72,7 @@ class FilePage extends React.PureComponent { fileViewLogged: false, fullscreenMode: false, fileGetStarted: false, + hasCheckedAllResolved: false, imageUrls: null, isLandscape: false, mediaLoaded: false, @@ -102,17 +103,14 @@ class FilePage extends React.PureComponent { onComponentFocused = () => { StatusBar.setHidden(false); NativeModules.Firebase.setCurrentScreen('File').then(result => { - DeviceEventEmitter.addListener('onDownloadStarted', this.handleDownloadStarted); - DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated); - DeviceEventEmitter.addListener('onDownloadCompleted', this.handleDownloadCompleted); DeviceEventEmitter.addListener('onStoragePermissionGranted', this.handleStoragePermissionGranted); DeviceEventEmitter.addListener('onStoragePermissionRefused', this.handleStoragePermissionRefused); - const { fetchMyClaims, fileInfo, isResolvingUri, resolveUri, navigation } = this.props; + const { claim, fetchMyClaims, fileInfo, isResolvingUri, resolveUri, navigation } = this.props; const { uri, uriVars } = navigation.state.params; this.setState({ uri, uriVars }); - if (!isResolvingUri) resolveUri(uri); + if (!isResolvingUri && !claim) resolveUri(uri); this.fetchFileInfo(this.props); this.fetchCostInfo(this.props); @@ -149,6 +147,7 @@ class FilePage extends React.PureComponent { navigation, contentType, notify, + recommendedContent: prevRecommendedContent, drawerStack: prevDrawerStack, } = this.props; const { uri } = navigation.state.params; @@ -160,6 +159,8 @@ class FilePage extends React.PureComponent { purchaseUriErrorMessage, streamingUrl, drawerStack, + recommendedContent, + resolveUris, } = nextProps; if (Constants.ROUTE_FILE === currentRoute && currentRoute !== prevRoute) { @@ -175,10 +176,7 @@ class FilePage extends React.PureComponent { const mediaType = Lbry.getMediaType(contentType); const isPlayable = mediaType === 'video' || mediaType === 'audio'; - if ( - (this.state.fileGetStarted || prevPurchasedUris.length !== purchasedUris.length) && - NativeModules.UtilityModule - ) { + if (this.state.fileGetStarted || prevPurchasedUris.length !== purchasedUris.length) { const { permanent_url: permanentUrl } = claim; if (purchasedUris.includes(uri) || purchasedUris.includes(permanentUrl)) { const { nout, txid } = claim; @@ -215,9 +213,23 @@ class FilePage extends React.PureComponent { if (claim && !this.state.viewCountFetched) { this.setState({ viewCountFetched: true }, () => fetchViewCount(claim.claim_id)); } + + if ( + (!prevRecommendedContent && recommendedContent) || + (recommendedContent && prevRecommendedContent && recommendedContent.length !== prevRecommendedContent.length) + ) { + resolveUris(recommendedContent); + } } - componentDidUpdate(prevProps) { + shouldComponentUpdate(nextProps, nextState) { + return ( + Object.keys(this.difference(nextProps, this.props)).length > 0 || + Object.keys(this.difference(nextState, this.state)).length > 0 + ); + } + + componentDidUpdate(prevProps, prevState) { const { claim, contentType, @@ -227,7 +239,6 @@ class FilePage extends React.PureComponent { resolveUri, navigation, purchaseUri, - searchRecommended, title, } = this.props; const { uri } = this.state; @@ -235,10 +246,6 @@ class FilePage extends React.PureComponent { resolveUri(uri); } - /* if (title && !this.state.didSearchRecommended) { - this.setState({ didSearchRecommended: true }, () => searchRecommended(title)); - } */ - // Returned to the page. If mediaLoaded, and currentMediaInfo is different, update if (this.state.mediaLoaded && window.currentMediaInfo && window.currentMediaInfo.uri !== this.state.uri) { const { metadata } = this.props; @@ -390,31 +397,10 @@ class FilePage extends React.PureComponent { } window.player = null; - DeviceEventEmitter.removeListener('onDownloadStarted', this.handleDownloadStarted); - DeviceEventEmitter.removeListener('onDownloadUpdated', this.handleDownloadUpdated); - DeviceEventEmitter.removeListener('onDownloadCompleted', this.handleDownloadCompleted); DeviceEventEmitter.removeListener('onStoragePermissionGranted', this.handleStoragePermissionGranted); DeviceEventEmitter.removeListener('onStoragePermissionRefused', this.handleStoragePermissionRefused); } - handleDownloadStarted = evt => { - const { startDownload } = this.props; - const { uri, outpoint, fileInfo } = evt; - startDownload(uri, outpoint, fileInfo); - }; - - handleDownloadUpdated = evt => { - const { updateDownload } = this.props; - const { uri, outpoint, fileInfo, progress } = evt; - updateDownload(uri, outpoint, fileInfo, progress); - }; - - handleDownloadCompleted = evt => { - const { completeDownload } = this.props; - const { uri, outpoint, fileInfo } = evt; - completeDownload(uri, outpoint, fileInfo); - }; - handleStoragePermissionGranted = () => { // permission was allowed. proceed to download const { notify } = this.props; @@ -538,6 +524,7 @@ class FilePage extends React.PureComponent { }; onPlaybackStarted = () => { + const { searchRecommended, title } = this.props; let timeToStartMillis, timeToStart; if (this.startTime) { timeToStartMillis = Date.now() - this.startTime; @@ -555,6 +542,11 @@ class FilePage extends React.PureComponent { payload['time_to_start_ms'] = timeToStartMillis; } NativeModules.Firebase.track('play', payload); + + // only fetch recommended content after playback has started + if (title) { + searchRecommended(title); + } }; onPlaybackFinished = () => { @@ -748,7 +740,7 @@ class FilePage extends React.PureComponent { let innerContent = null; if ((isResolvingUri && !claim) || !claim) { return ( - + {isResolvingUri && ( @@ -786,442 +778,433 @@ class FilePage extends React.PureComponent { ); } - if (claim) { - if (isChannel) { - return ; - } - - let isClaimBlackListed = false; - - if (blackListedOutpoints) { - for (let i = 0; i < blackListedOutpoints.length; i += 1) { - const outpoint = blackListedOutpoints[i]; - if (outpoint.txid === claim.txid && outpoint.nout === claim.nout) { - isClaimBlackListed = true; - break; - } + let isClaimBlackListed = false; + if (blackListedOutpoints) { + for (let i = 0; i < blackListedOutpoints.length; i += 1) { + const outpoint = blackListedOutpoints[i]; + if (outpoint.txid === claim.txid && outpoint.nout === claim.nout) { + isClaimBlackListed = true; + break; } } + } - if (isClaimBlackListed) { - return ( - - - - {__( - 'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications.' - )} - - - - - - ); - } - - let tags = []; - if (claim && claim.value && claim.value.tags) { - tags = claim.value.tags; - } - - const completed = fileInfo && fileInfo.completed; - const isRewardContent = rewardedContentClaimIds.includes(claim.claim_id); - const description = metadata.description ? metadata.description : null; - const mediaType = Lbry.getMediaType(contentType); - const isPlayable = mediaType === 'video' || mediaType === 'audio'; - const isWebViewable = mediaType === 'text'; - const { height, signing_channel: signingChannel, value } = claim; - const channelName = signingChannel && signingChannel.name; - const channelClaimId = claim && claim.signing_channel && claim.signing_channel.claim_id; - const fullUri = `${claim.name}#${claim.claim_id}`; - const canEdit = myClaimUris.includes(normalizeURI(fullUri)); - const showActions = - (canEdit || (fileInfo && fileInfo.download_path)) && - !this.state.fullscreenMode && - !this.state.showImageViewer && - !this.state.showWebView; - const showFileActions = - canEdit || - (fileInfo && - fileInfo.download_path && - (completed || (fileInfo && !fileInfo.stopped && fileInfo.written_bytes < fileInfo.total_bytes))); - const fullChannelUri = - channelClaimId && channelClaimId.trim().length > 0 - ? normalizeURI(`${channelName}#${channelClaimId}`) - : normalizeURI(channelName); - const shortChannelUri = signingChannel ? signingChannel.short_url : null; - - const playerStyle = [ - filePageStyle.player, - this.state.isLandscape - ? filePageStyle.containedPlayerLandscape - : this.state.fullscreenMode - ? filePageStyle.fullscreenPlayer - : filePageStyle.containedPlayer, - ]; - const playerBgStyle = [filePageStyle.playerBackground, filePageStyle.containedPlayerBackground]; - const fsPlayerBgStyle = [filePageStyle.playerBackground, filePageStyle.fullscreenPlayerBackground]; - // at least 2MB (or the full download) before media can be loaded - const canLoadMedia = - this.state.streamingMode || - (fileInfo && (fileInfo.written_bytes >= 2097152 || fileInfo.written_bytes === fileInfo.total_bytes)); // 2MB = 1024*1024*2 - const duration = claim && claim.value && claim.value.video ? claim.value.video.duration : null; - const isViewable = mediaType === 'image' || mediaType === 'text'; - const canOpen = isViewable && completed; - const localFileUri = this.localUriForFileInfo(fileInfo); - const unsupported = !isPlayable && !canOpen; - - if (fileInfo && !this.state.autoDownloadStarted && this.state.uriVars && this.state.uriVars.download === 'true') { - this.setState({ autoDownloadStarted: true }, () => { - if (!isPlayable) { - this.checkStoragePermissionForDownload(); - } else { - purchaseUri(uri, costInfo, !isPlayable); - } - NativeModules.UtilityModule.checkDownloads(); - }); - } - - if (this.state.downloadPressed && canOpen && !this.state.autoOpened) { - // automatically open a web viewable or image file after the download button is pressed - this.setState({ autoOpened: true }, () => this.openFile(localFileUri, mediaType)); - } - - return ( - - {!this.state.fullscreenMode && } - {this.state.showWebView && isWebViewable && ( - - )} - - {this.state.showImageViewer && ( - null} - /> - )} - - {!this.state.showWebView && ( - - - {(canOpen || (!fileInfo || (isPlayable && !canLoadMedia)) || (!canOpen && fileInfo)) && ( - - )} - {!unsupported && - (!this.state.downloadButtonShown || this.state.downloadPressed) && - !this.state.mediaLoaded && ( - - )} - - {unsupported && fileInfo && completed && ( - - - - {__('Unsupported Content')} - - Sorry, we are unable to display this content in the app. You can find the file named{' '} - {fileInfo.file_name} in your - downloads folder. - - - - )} - - {((isPlayable && !completed && !canLoadMedia) || - canOpen || - (!completed && !this.state.streamingMode)) && ( - this.openFile(localFileUri, mediaType)} - isPlayable={isPlayable} - isViewable={isViewable} - onFileActionPress={this.onFileDownloadButtonPressed} - onButtonLayout={() => this.setState({ downloadButtonShown: true })} - /> - )} - {!fileInfo && ( - - )} - - - - - - {(this.state.streamingMode || (canLoadMedia && fileInfo && isPlayable)) && ( - { - this.playerBackground = ref; - }} - onLayout={evt => { - if (!this.state.playerBgHeight) { - this.setState({ playerBgHeight: evt.nativeEvent.layout.height }); - } - }} - /> - )} - {(this.state.streamingMode || (canLoadMedia && fileInfo && isPlayable)) && this.state.fullscreenMode && ( - - )} - {(this.state.streamingMode || (canLoadMedia && fileInfo && isPlayable)) && ( - { - this.player = ref; - }} - uri={uri} - source={this.playerUriForFileInfo(fileInfo)} - style={playerStyle} - autoPlay={autoplay || this.state.autoPlayMedia} - onFullscreenToggled={this.handleFullscreenToggle} - onLayout={evt => { - if (!this.state.playerHeight) { - this.setState({ playerHeight: evt.nativeEvent.layout.height }); - } - }} - onMediaLoaded={() => this.onMediaLoaded(channelName, title, uri)} - onBackButtonPressed={this.onBackButtonPressed} - onPlaybackStarted={this.onPlaybackStarted} - onPlaybackFinished={this.onPlaybackFinished} - thumbnail={thumbnail} - position={position} - /> - )} - - { - this.scrollView = ref; - }} - > - this.setState({ showDescription: !this.state.showDescription })} - > - - - - {title} - - {isRewardContent && } - - - - - - {viewCount === 1 && __('%view% view', { view: viewCount })} - {viewCount > 1 && __('%view% views', { view: viewCount })} - - - - - - - - {__('Share')} - - - this.setState({ showTipView: true })} - > - - {__('Tip')} - - - {!canEdit && !isPlayable && ( - - {!fileInfo || - (fileInfo.written_bytes <= 0 && !completed && ( - - - {__('Download')} - - ))} - - {!completed && - fileInfo && - !fileInfo.stopped && - fileInfo.written_bytes > 0 && - fileInfo.written_bytes < fileInfo.total_bytes && - !this.state.stopDownloadConfirmed && ( - - - {__('Stop')} - - )} - - {completed && fileInfo && fileInfo.written_bytes >= fileInfo.total_bytes && ( - - - {__('Open')} - - )} - - )} - - {!canEdit && ( - Linking.openURL(`https://lbry.com/dmca/${claim.claim_id}`)} - > - - {__('Report')} - - )} - - {canEdit && ( - - - {__('Edit')} - - )} - - {(completed || canEdit) && ( - - - {__('Delete')} - - )} - - - - - {channelName && ( - { - navigateToUri( - navigation, - normalizeURI(shortChannelUri || fullChannelUri), - null, - false, - fullChannelUri - ); - }} - /> - )} - {!channelName && ( - - {__('Anonymous')} - - )} - - - - {false && ((isPlayable && !fileInfo) || (isPlayable && fileInfo && !fileInfo.download_path)) && ( -