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)) && (
-
- )}
- {channelName && (
-
- )}
- {false && channelName && (
-
- )}
-
-
-
- {this.state.showDescription && description && description.length > 0 && (
-
- )}
- {this.state.showDescription && description && (
-
-
- {this.linkify(description)}
-
- {tags && tags.length > 0 && (
-
- {__('Tags')}
- {this.renderTags(tags)}
-
- )}
-
- )}
-
- {costInfo && parseFloat(costInfo.cost) > balance && !fileInfo && (
-
- )}
-
-
-
- {isSearchingRecommendContent && (
-
- )}
- {false && !isSearchingRecommendContent && recommendedContent && recommendedContent.length > 0 && (
-
- )}
-
-
- )}
- {this.state.showTipView && (
- this.setState({ showTipView: false })}
- onOverlayPress={() => this.setState({ showTipView: false })}
- onSendTipSuccessful={() => this.setState({ showTipView: false })}
- />
- )}
- {!this.state.fullscreenMode &&
- !this.state.showTipView &&
- !this.state.showImageViewer &&
- !this.state.showWebView && }
+ if (isClaimBlackListed) {
+ innerContent = (
+
+
+ {__(
+ 'In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications.'
+ )}
+
+
);
}
- return null;
+ 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 (
+ !this.state.autoDownloadStarted &&
+ claim &&
+ costInfo &&
+ ((isPlayable && costInfo.cost === 0) || (this.state.uriVars && this.state.uriVars.download === 'true'))
+ ) {
+ this.setState({ autoDownloadStarted: true }, () => {
+ if (!isPlayable) {
+ this.checkStoragePermissionForDownload();
+ } else {
+ purchaseUri(claim.permanent_url, 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));
+ }
+
+ if (isChannel) {
+ return ;
+ }
+
+ 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
+ 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)) && (
+
+ )}
+ {channelName && (
+
+ )}
+ {false && channelName && (
+
+ )}
+
+
+
+ {this.state.showDescription && description && description.length > 0 && (
+
+ )}
+ {this.state.showDescription && description && (
+
+
+ {this.linkify(description)}
+
+ {tags && tags.length > 0 && (
+
+ {__('Tags')}
+ {this.renderTags(tags)}
+
+ )}
+
+ )}
+
+ {costInfo && parseFloat(costInfo.cost) > balance && !fileInfo && (
+
+ )}
+
+
+
+ {isSearchingRecommendContent && (
+
+ )}
+ {!isSearchingRecommendContent && recommendedContent && recommendedContent.length > 0 && (
+
+ )}
+
+
+ )}
+ {this.state.showTipView && (
+ this.setState({ showTipView: false })}
+ onOverlayPress={() => this.setState({ showTipView: false })}
+ onSendTipSuccessful={() => this.setState({ showTipView: false })}
+ />
+ )}
+ {!this.state.fullscreenMode &&
+ !this.state.showTipView &&
+ !this.state.showImageViewer &&
+ !this.state.showWebView && }
+
+ );
}
}
diff --git a/src/styles/fileList.js b/src/styles/fileList.js
index 117a25e..7c73e85 100644
--- a/src/styles/fileList.js
+++ b/src/styles/fileList.js
@@ -94,6 +94,11 @@ const fileListStyle = StyleSheet.create({
top: 8,
left: 8,
},
+ featuredDownloadedIcon: {
+ position: 'absolute',
+ left: 16,
+ top: 16,
+ },
fileItem: {
marginLeft: 24,
marginRight: 24,