Compare commits
3 commits
master
...
first-run-
Author | SHA1 | Date | |
---|---|---|---|
|
8ae6b88410 | ||
|
a32c7f32f8 | ||
|
c1f73c2766 |
10 changed files with 597 additions and 554 deletions
|
@ -51,6 +51,7 @@ import {
|
||||||
selectHashChanged,
|
selectHashChanged,
|
||||||
selectUser,
|
selectUser,
|
||||||
} from 'lbryinc';
|
} from 'lbryinc';
|
||||||
|
import { doStartDownload, doUpdateDownload, doCompleteDownload } from 'redux/actions/file';
|
||||||
import { makeSelectClientSetting, selectFullscreenMode } from 'redux/selectors/settings';
|
import { makeSelectClientSetting, selectFullscreenMode } from 'redux/selectors/settings';
|
||||||
import { decode as atob } from 'base-64';
|
import { decode as atob } from 'base-64';
|
||||||
import { dispatchNavigateBack, dispatchNavigateToUri, transformUrl } from 'utils/helper';
|
import { dispatchNavigateBack, dispatchNavigateToUri, transformUrl } from 'utils/helper';
|
||||||
|
@ -311,6 +312,10 @@ class AppWithNavigationState extends React.Component {
|
||||||
this.emailVerifyCheckInterval = setInterval(() => this.checkEmailVerification(), 5000);
|
this.emailVerifyCheckInterval = setInterval(() => this.checkEmailVerification(), 5000);
|
||||||
Linking.addEventListener('url', this._handleUrl);
|
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
|
// call /sync/get with interval
|
||||||
this.syncGetInterval = setInterval(() => {
|
this.syncGetInterval = setInterval(() => {
|
||||||
this.setState({ syncHashChanged: false }); // reset local state
|
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() {
|
componentWillUnmount() {
|
||||||
|
DeviceEventEmitter.removeListener('onDownloadStarted', this.handleDownloadStarted);
|
||||||
|
DeviceEventEmitter.removeListener('onDownloadUpdated', this.handleDownloadUpdated);
|
||||||
|
DeviceEventEmitter.removeListener('onDownloadCompleted', this.handleDownloadCompleted);
|
||||||
|
|
||||||
AppState.removeEventListener('change', this._handleAppStateChange);
|
AppState.removeEventListener('change', this._handleAppStateChange);
|
||||||
BackHandler.removeEventListener('hardwareBackPress');
|
BackHandler.removeEventListener('hardwareBackPress');
|
||||||
Linking.removeEventListener('url', this._handleUrl);
|
Linking.removeEventListener('url', this._handleUrl);
|
||||||
|
|
|
@ -11,11 +11,6 @@ class FileDownloadButton extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
// this.checkAvailability(nextProps.uri);
|
|
||||||
// this.restartDownload(nextProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
restartDownload(props) {
|
restartDownload(props) {
|
||||||
const { downloading, fileInfo, uri, restartDownload } = props;
|
const { downloading, fileInfo, uri, restartDownload } = props;
|
||||||
|
|
||||||
|
@ -45,6 +40,7 @@ class FileDownloadButton extends React.PureComponent {
|
||||||
doPause,
|
doPause,
|
||||||
style,
|
style,
|
||||||
openFile,
|
openFile,
|
||||||
|
onFileActionPress,
|
||||||
onButtonLayout,
|
onButtonLayout,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -72,19 +68,7 @@ class FileDownloadButton extends React.PureComponent {
|
||||||
text={isPlayable ? __('Play') : isViewable ? __('View') : __('Download')}
|
text={isPlayable ? __('Play') : isViewable ? __('View') : __('Download')}
|
||||||
onLayout={onButtonLayout}
|
onLayout={onButtonLayout}
|
||||||
style={[style, fileDownloadButtonStyle.container]}
|
style={[style, fileDownloadButtonStyle.container]}
|
||||||
onPress={() => {
|
onPress={onFileActionPress}
|
||||||
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();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (fileInfo && fileInfo.download_path) {
|
} else if (fileInfo && fileInfo.download_path) {
|
||||||
|
|
|
@ -158,7 +158,13 @@ class FileListItem extends React.PureComponent {
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{fileInfo && fileInfo.completed && fileInfo.download_path && (
|
{fileInfo && fileInfo.completed && fileInfo.download_path && (
|
||||||
<Icon style={fileListStyle.downloadedIcon} solid color={Colors.NextLbryGreen} name={'folder'} size={16} />
|
<Icon
|
||||||
|
style={featuredResult ? fileListStyle.featuredDownloadedIcon : fileListStyle.downloadedIcon}
|
||||||
|
solid
|
||||||
|
color={Colors.NextLbryGreen}
|
||||||
|
name={'folder'}
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<View style={fileListStyle.detailsContainer}>
|
<View style={fileListStyle.detailsContainer}>
|
||||||
{featuredResult && (
|
{featuredResult && (
|
||||||
|
|
|
@ -8,18 +8,11 @@ import fileListStyle from 'styles/fileList';
|
||||||
import relatedContentStyle from 'styles/relatedContent';
|
import relatedContentStyle from 'styles/relatedContent';
|
||||||
|
|
||||||
export default class RelatedContent extends React.PureComponent {
|
export default class RelatedContent extends React.PureComponent {
|
||||||
state = {
|
componentDidMount() {
|
||||||
urlsResolved: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
const { resolveUris, recommendedContent } = this.props;
|
const { resolveUris, recommendedContent } = this.props;
|
||||||
|
if (recommendedContent && recommendedContent.length > 0) {
|
||||||
if (recommendedContent && recommendedContent.length > 0 && !this.state.urisResolved) {
|
|
||||||
this.setState({ urisResolved: true }, () => {
|
|
||||||
// batch resolve the uris
|
// batch resolve the uris
|
||||||
resolveUris(recommendedContent);
|
resolveUris(recommendedContent);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,9 @@ function checkMessageAndSave(message, messagesFilePath) {
|
||||||
); */
|
); */
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
if (err) {
|
if (err && !isProduction) {
|
||||||
throw err;
|
// only do this when not in production
|
||||||
|
console.error(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ window.__ = __;
|
||||||
|
|
||||||
const globalExceptionHandler = (error, isFatal) => {
|
const globalExceptionHandler = (error, isFatal) => {
|
||||||
if (error && NativeModules.Firebase) {
|
if (error && NativeModules.Firebase) {
|
||||||
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);
|
setJSExceptionHandler(globalExceptionHandler, true);
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
doPurchaseUri,
|
doPurchaseUri,
|
||||||
doDeletePurchasedUri,
|
doDeletePurchasedUri,
|
||||||
doResolveUri,
|
doResolveUri,
|
||||||
|
doResolveUris,
|
||||||
doSearch,
|
doSearch,
|
||||||
doSendTip,
|
doSendTip,
|
||||||
doToast,
|
doToast,
|
||||||
|
@ -28,6 +29,7 @@ import {
|
||||||
selectPurchasedUris,
|
selectPurchasedUris,
|
||||||
selectFailedPurchaseUris,
|
selectFailedPurchaseUris,
|
||||||
selectPurchaseUriErrorMessage,
|
selectPurchaseUriErrorMessage,
|
||||||
|
selectResolvingUris,
|
||||||
selectIsSearching,
|
selectIsSearching,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import {
|
import {
|
||||||
|
@ -39,13 +41,7 @@ import {
|
||||||
selectRewardContentClaimIds,
|
selectRewardContentClaimIds,
|
||||||
selectBlackListedOutpoints,
|
selectBlackListedOutpoints,
|
||||||
} from 'lbryinc';
|
} from 'lbryinc';
|
||||||
import {
|
import { doDeleteFile, doStopDownloadingFile } from 'redux/actions/file';
|
||||||
doStartDownload,
|
|
||||||
doUpdateDownload,
|
|
||||||
doCompleteDownload,
|
|
||||||
doDeleteFile,
|
|
||||||
doStopDownloadingFile,
|
|
||||||
} from 'redux/actions/file';
|
|
||||||
import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
|
import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
|
||||||
import { doToggleFullscreenMode } from 'redux/actions/settings';
|
import { doToggleFullscreenMode } from 'redux/actions/settings';
|
||||||
import { selectDrawerStack } from 'redux/selectors/drawer';
|
import { selectDrawerStack } from 'redux/selectors/drawer';
|
||||||
|
@ -77,6 +73,7 @@ const select = (state, props) => {
|
||||||
thumbnail: makeSelectThumbnailForUri(contentUri)(state),
|
thumbnail: makeSelectThumbnailForUri(contentUri)(state),
|
||||||
title: makeSelectTitleForUri(contentUri)(state),
|
title: makeSelectTitleForUri(contentUri)(state),
|
||||||
recommendedContent: makeSelectRecommendedContentForUri(contentUri)(state),
|
recommendedContent: makeSelectRecommendedContentForUri(contentUri)(state),
|
||||||
|
resolvingUris: selectResolvingUris(state),
|
||||||
isSearchingRecommendContent: selectIsSearching(state),
|
isSearchingRecommendContent: selectIsSearching(state),
|
||||||
viewCount: makeSelectViewCountForUri(contentUri)(state),
|
viewCount: makeSelectViewCountForUri(contentUri)(state),
|
||||||
};
|
};
|
||||||
|
@ -100,14 +97,12 @@ const perform = dispatch => ({
|
||||||
purchaseUri: (uri, costInfo, saveFile) => dispatch(doPurchaseUri(uri, costInfo, saveFile)),
|
purchaseUri: (uri, costInfo, saveFile) => dispatch(doPurchaseUri(uri, costInfo, saveFile)),
|
||||||
deletePurchasedUri: uri => dispatch(doDeletePurchasedUri(uri)),
|
deletePurchasedUri: uri => dispatch(doDeletePurchasedUri(uri)),
|
||||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||||
|
resolveUris: uris => dispatch(doResolveUris(uris)),
|
||||||
searchRecommended: query => dispatch(doSearch(query, 20, undefined, true)),
|
searchRecommended: query => dispatch(doSearch(query, 20, undefined, true)),
|
||||||
sendTip: (amount, claimId, isSupport, successCallback, errorCallback) =>
|
sendTip: (amount, claimId, isSupport, successCallback, errorCallback) =>
|
||||||
dispatch(doSendTip(amount, claimId, isSupport, successCallback, errorCallback)),
|
dispatch(doSendTip(amount, claimId, isSupport, successCallback, errorCallback)),
|
||||||
setPlayerVisible: () => dispatch(doSetPlayerVisible(true)),
|
setPlayerVisible: () => dispatch(doSetPlayerVisible(true)),
|
||||||
stopDownload: (uri, fileInfo) => dispatch(doStopDownloadingFile(uri, fileInfo)),
|
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)),
|
toggleFullscreenMode: mode => dispatch(doToggleFullscreenMode(mode)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ class FilePage extends React.PureComponent {
|
||||||
fileViewLogged: false,
|
fileViewLogged: false,
|
||||||
fullscreenMode: false,
|
fullscreenMode: false,
|
||||||
fileGetStarted: false,
|
fileGetStarted: false,
|
||||||
|
hasCheckedAllResolved: false,
|
||||||
imageUrls: null,
|
imageUrls: null,
|
||||||
isLandscape: false,
|
isLandscape: false,
|
||||||
mediaLoaded: false,
|
mediaLoaded: false,
|
||||||
|
@ -101,29 +102,24 @@ class FilePage extends React.PureComponent {
|
||||||
|
|
||||||
onComponentFocused = () => {
|
onComponentFocused = () => {
|
||||||
StatusBar.setHidden(false);
|
StatusBar.setHidden(false);
|
||||||
NativeModules.Firebase.setCurrentScreen('File');
|
NativeModules.Firebase.setCurrentScreen('File').then(result => {
|
||||||
|
DeviceEventEmitter.addListener('onStoragePermissionGranted', this.handleStoragePermissionGranted);
|
||||||
|
DeviceEventEmitter.addListener('onStoragePermissionRefused', this.handleStoragePermissionRefused);
|
||||||
|
|
||||||
DeviceEventEmitter.addListener('onDownloadStarted', this.handleDownloadStarted);
|
const { claim, fetchMyClaims, fileInfo, isResolvingUri, resolveUri, navigation } = this.props;
|
||||||
DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated);
|
|
||||||
DeviceEventEmitter.addListener('onDownloadCompleted', this.handleDownloadCompleted);
|
|
||||||
|
|
||||||
const { fetchMyClaims, fileInfo, isResolvingUri, resolveUri, navigation } = this.props;
|
|
||||||
const { uri, uriVars } = navigation.state.params;
|
const { uri, uriVars } = navigation.state.params;
|
||||||
this.setState({ uri, uriVars });
|
this.setState({ uri, uriVars });
|
||||||
|
|
||||||
if (!isResolvingUri) resolveUri(uri);
|
if (!isResolvingUri && !claim) resolveUri(uri);
|
||||||
|
|
||||||
this.fetchFileInfo(this.props);
|
this.fetchFileInfo(this.props);
|
||||||
this.fetchCostInfo(this.props);
|
this.fetchCostInfo(this.props);
|
||||||
|
|
||||||
fetchMyClaims();
|
fetchMyClaims();
|
||||||
|
|
||||||
if (NativeModules.Firebase) {
|
|
||||||
NativeModules.Firebase.track('open_file_page', { uri: uri });
|
NativeModules.Firebase.track('open_file_page', { uri: uri });
|
||||||
}
|
|
||||||
if (NativeModules.UtilityModule) {
|
|
||||||
NativeModules.UtilityModule.keepAwakeOn();
|
NativeModules.UtilityModule.keepAwakeOn();
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -151,6 +147,7 @@ class FilePage extends React.PureComponent {
|
||||||
navigation,
|
navigation,
|
||||||
contentType,
|
contentType,
|
||||||
notify,
|
notify,
|
||||||
|
recommendedContent: prevRecommendedContent,
|
||||||
drawerStack: prevDrawerStack,
|
drawerStack: prevDrawerStack,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { uri } = navigation.state.params;
|
const { uri } = navigation.state.params;
|
||||||
|
@ -162,6 +159,8 @@ class FilePage extends React.PureComponent {
|
||||||
purchaseUriErrorMessage,
|
purchaseUriErrorMessage,
|
||||||
streamingUrl,
|
streamingUrl,
|
||||||
drawerStack,
|
drawerStack,
|
||||||
|
recommendedContent,
|
||||||
|
resolveUris,
|
||||||
} = nextProps;
|
} = nextProps;
|
||||||
|
|
||||||
if (Constants.ROUTE_FILE === currentRoute && currentRoute !== prevRoute) {
|
if (Constants.ROUTE_FILE === currentRoute && currentRoute !== prevRoute) {
|
||||||
|
@ -177,11 +176,9 @@ class FilePage extends React.PureComponent {
|
||||||
|
|
||||||
const mediaType = Lbry.getMediaType(contentType);
|
const mediaType = Lbry.getMediaType(contentType);
|
||||||
const isPlayable = mediaType === 'video' || mediaType === 'audio';
|
const isPlayable = mediaType === 'video' || mediaType === 'audio';
|
||||||
if (
|
if (this.state.fileGetStarted || prevPurchasedUris.length !== purchasedUris.length) {
|
||||||
(this.state.fileGetStarted || prevPurchasedUris.length !== purchasedUris.length) &&
|
const { permanent_url: permanentUrl } = claim;
|
||||||
NativeModules.UtilityModule
|
if (purchasedUris.includes(uri) || purchasedUris.includes(permanentUrl)) {
|
||||||
) {
|
|
||||||
if (purchasedUris.includes(uri)) {
|
|
||||||
const { nout, txid } = claim;
|
const { nout, txid } = claim;
|
||||||
const outpoint = `${txid}:${nout}`;
|
const outpoint = `${txid}:${nout}`;
|
||||||
NativeModules.UtilityModule.queueDownload(outpoint);
|
NativeModules.UtilityModule.queueDownload(outpoint);
|
||||||
|
@ -216,9 +213,23 @@ class FilePage extends React.PureComponent {
|
||||||
if (claim && !this.state.viewCountFetched) {
|
if (claim && !this.state.viewCountFetched) {
|
||||||
this.setState({ viewCountFetched: true }, () => fetchViewCount(claim.claim_id));
|
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 {
|
const {
|
||||||
claim,
|
claim,
|
||||||
contentType,
|
contentType,
|
||||||
|
@ -228,7 +239,6 @@ class FilePage extends React.PureComponent {
|
||||||
resolveUri,
|
resolveUri,
|
||||||
navigation,
|
navigation,
|
||||||
purchaseUri,
|
purchaseUri,
|
||||||
searchRecommended,
|
|
||||||
title,
|
title,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { uri } = this.state;
|
const { uri } = this.state;
|
||||||
|
@ -236,10 +246,6 @@ class FilePage extends React.PureComponent {
|
||||||
resolveUri(uri);
|
resolveUri(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (title && !this.state.didSearchRecommended) {
|
|
||||||
this.setState({ didSearchRecommended: true }, () => searchRecommended(title));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returned to the page. If mediaLoaded, and currentMediaInfo is different, update
|
// Returned to the page. If mediaLoaded, and currentMediaInfo is different, update
|
||||||
if (this.state.mediaLoaded && window.currentMediaInfo && window.currentMediaInfo.uri !== this.state.uri) {
|
if (this.state.mediaLoaded && window.currentMediaInfo && window.currentMediaInfo.uri !== this.state.uri) {
|
||||||
const { metadata } = this.props;
|
const { metadata } = this.props;
|
||||||
|
@ -254,15 +260,7 @@ class FilePage extends React.PureComponent {
|
||||||
const mediaType = Lbry.getMediaType(contentType);
|
const mediaType = Lbry.getMediaType(contentType);
|
||||||
const isViewable = mediaType === 'image' || mediaType === 'text';
|
const isViewable = mediaType === 'image' || mediaType === 'text';
|
||||||
if (claim && costInfo && costInfo.cost === 0 && !this.state.autoGetAttempted && isViewable) {
|
if (claim && costInfo && costInfo.cost === 0 && !this.state.autoGetAttempted && isViewable) {
|
||||||
this.setState(
|
this.setState({ autoGetAttempted: true }, () => this.checkStoragePermissionForDownload());
|
||||||
{
|
|
||||||
autoGetAttempted: true,
|
|
||||||
downloadPressed: true,
|
|
||||||
autoPlayMedia: true,
|
|
||||||
stopDownloadConfirmed: false,
|
|
||||||
},
|
|
||||||
() => purchaseUri(claim.permanent_url, costInfo, true)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,27 +397,34 @@ class FilePage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
window.player = null;
|
window.player = null;
|
||||||
|
|
||||||
DeviceEventEmitter.removeListener('onDownloadStarted', this.handleDownloadStarted);
|
DeviceEventEmitter.removeListener('onStoragePermissionGranted', this.handleStoragePermissionGranted);
|
||||||
DeviceEventEmitter.removeListener('onDownloadUpdated', this.handleDownloadUpdated);
|
DeviceEventEmitter.removeListener('onStoragePermissionRefused', this.handleStoragePermissionRefused);
|
||||||
DeviceEventEmitter.removeListener('onDownloadCompleted', this.handleDownloadCompleted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDownloadStarted = evt => {
|
handleStoragePermissionGranted = () => {
|
||||||
const { startDownload } = this.props;
|
// permission was allowed. proceed to download
|
||||||
const { uri, outpoint, fileInfo } = evt;
|
const { notify } = this.props;
|
||||||
startDownload(uri, outpoint, fileInfo);
|
|
||||||
|
// update the configured download folder and then download
|
||||||
|
NativeModules.UtilityModule.getDownloadDirectory().then(downloadDirectory => {
|
||||||
|
Lbry.settings_set({
|
||||||
|
key: 'download_dir',
|
||||||
|
value: downloadDirectory,
|
||||||
|
})
|
||||||
|
.then(() => this.performDownload())
|
||||||
|
.catch(() => {
|
||||||
|
notify({ message: 'The file could not be downloaded to the default download directory.', isError: true });
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleDownloadUpdated = evt => {
|
handleStoragePermissionRefused = () => {
|
||||||
const { updateDownload } = this.props;
|
const { notify } = this.props;
|
||||||
const { uri, outpoint, fileInfo, progress } = evt;
|
this.setState({ downloadPressed: false });
|
||||||
updateDownload(uri, outpoint, fileInfo, progress);
|
notify({
|
||||||
};
|
message: __('The file could not be downloaded because the permission to write to storage was not granted.'),
|
||||||
|
isError: true,
|
||||||
handleDownloadCompleted = evt => {
|
});
|
||||||
const { completeDownload } = this.props;
|
|
||||||
const { uri, outpoint, fileInfo } = evt;
|
|
||||||
completeDownload(uri, outpoint, fileInfo);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
localUriForFileInfo = fileInfo => {
|
localUriForFileInfo = fileInfo => {
|
||||||
|
@ -519,6 +524,7 @@ class FilePage extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
onPlaybackStarted = () => {
|
onPlaybackStarted = () => {
|
||||||
|
const { searchRecommended, title } = this.props;
|
||||||
let timeToStartMillis, timeToStart;
|
let timeToStartMillis, timeToStart;
|
||||||
if (this.startTime) {
|
if (this.startTime) {
|
||||||
timeToStartMillis = Date.now() - this.startTime;
|
timeToStartMillis = Date.now() - this.startTime;
|
||||||
|
@ -536,6 +542,11 @@ class FilePage extends React.PureComponent {
|
||||||
payload['time_to_start_ms'] = timeToStartMillis;
|
payload['time_to_start_ms'] = timeToStartMillis;
|
||||||
}
|
}
|
||||||
NativeModules.Firebase.track('play', payload);
|
NativeModules.Firebase.track('play', payload);
|
||||||
|
|
||||||
|
// only fetch recommended content after playback has started
|
||||||
|
if (title) {
|
||||||
|
searchRecommended(title);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onPlaybackFinished = () => {
|
onPlaybackFinished = () => {
|
||||||
|
@ -589,14 +600,48 @@ class FilePage extends React.PureComponent {
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
onFileDownloadButtonPlayed = () => {
|
onFileDownloadButtonPressed = () => {
|
||||||
const { setPlayerVisible } = this.props;
|
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) {
|
||||||
|
this.checkStoragePermissionForDownload();
|
||||||
|
} else {
|
||||||
|
purchaseUri(uri, costInfo, !isPlayable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPlayable) {
|
||||||
this.startTime = Date.now();
|
this.startTime = Date.now();
|
||||||
this.setState({ downloadPressed: true, autoPlayMedia: true, stopDownloadConfirmed: false });
|
this.setState({ downloadPressed: true, autoPlayMedia: true, stopDownloadConfirmed: false });
|
||||||
setPlayerVisible();
|
setPlayerVisible();
|
||||||
|
}
|
||||||
|
if (isViewable) {
|
||||||
|
this.setState({ downloadPressed: true });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onDownloadPressed = () => {
|
onDownloadPressed = () => {
|
||||||
|
this.checkStoragePermissionForDownload();
|
||||||
|
};
|
||||||
|
|
||||||
|
checkStoragePermissionForDownload = () => {
|
||||||
|
// 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;
|
const { claim, costInfo, purchaseUri } = this.props;
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
|
@ -604,7 +649,10 @@ class FilePage extends React.PureComponent {
|
||||||
autoPlayMedia: false,
|
autoPlayMedia: false,
|
||||||
stopDownloadConfirmed: false,
|
stopDownloadConfirmed: false,
|
||||||
},
|
},
|
||||||
() => purchaseUri(claim.permanent_url, costInfo, true)
|
() => {
|
||||||
|
purchaseUri(claim.permanent_url, costInfo, true);
|
||||||
|
NativeModules.UtilityModule.checkDownloads();
|
||||||
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -621,14 +669,7 @@ class FilePage extends React.PureComponent {
|
||||||
// file already in library or URI already purchased, use fileGet directly
|
// file already in library or URI already purchased, use fileGet directly
|
||||||
this.setState({ fileGetStarted: true }, () => fileGet(uri, true));
|
this.setState({ fileGetStarted: true }, () => fileGet(uri, true));
|
||||||
} else {
|
} else {
|
||||||
this.setState(
|
this.checkStoragePermissionForDownload();
|
||||||
{
|
|
||||||
downloadPressed: true,
|
|
||||||
autoPlayMedia: false,
|
|
||||||
stopDownloadConfirmed: false,
|
|
||||||
},
|
|
||||||
() => purchaseUri(uri, costInfo, true)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -665,17 +706,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() {
|
render() {
|
||||||
const {
|
const {
|
||||||
balance,
|
balance,
|
||||||
|
@ -710,7 +740,7 @@ class FilePage extends React.PureComponent {
|
||||||
let innerContent = null;
|
let innerContent = null;
|
||||||
if ((isResolvingUri && !claim) || !claim) {
|
if ((isResolvingUri && !claim) || !claim) {
|
||||||
return (
|
return (
|
||||||
<View style={filePageStyle.container}>
|
<View style={filePageStyle.pageContainer}>
|
||||||
<UriBar value={uri} navigation={navigation} />
|
<UriBar value={uri} navigation={navigation} />
|
||||||
{isResolvingUri && (
|
{isResolvingUri && (
|
||||||
<View style={filePageStyle.busyContainer}>
|
<View style={filePageStyle.busyContainer}>
|
||||||
|
@ -748,13 +778,7 @@ class FilePage extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (claim) {
|
|
||||||
if (isChannel) {
|
|
||||||
return <ChannelPage uri={uri} navigation={navigation} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isClaimBlackListed = false;
|
let isClaimBlackListed = false;
|
||||||
|
|
||||||
if (blackListedOutpoints) {
|
if (blackListedOutpoints) {
|
||||||
for (let i = 0; i < blackListedOutpoints.length; i += 1) {
|
for (let i = 0; i < blackListedOutpoints.length; i += 1) {
|
||||||
const outpoint = blackListedOutpoints[i];
|
const outpoint = blackListedOutpoints[i];
|
||||||
|
@ -766,8 +790,7 @@ class FilePage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isClaimBlackListed) {
|
if (isClaimBlackListed) {
|
||||||
return (
|
innerContent = (
|
||||||
<View style={filePageStyle.pageContainer}>
|
|
||||||
<View style={filePageStyle.dmcaContainer}>
|
<View style={filePageStyle.dmcaContainer}>
|
||||||
<Text style={filePageStyle.dmcaText}>
|
<Text style={filePageStyle.dmcaText}>
|
||||||
{__(
|
{__(
|
||||||
|
@ -776,8 +799,6 @@ class FilePage extends React.PureComponent {
|
||||||
</Text>
|
</Text>
|
||||||
<Link style={filePageStyle.dmcaLink} href="https://lbry.com/faq/dmca" text={__('Read More')} />
|
<Link style={filePageStyle.dmcaLink} href="https://lbry.com/faq/dmca" text={__('Read More')} />
|
||||||
</View>
|
</View>
|
||||||
<UriBar value={uri} navigation={navigation} />
|
|
||||||
</View>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -833,12 +854,19 @@ class FilePage extends React.PureComponent {
|
||||||
const localFileUri = this.localUriForFileInfo(fileInfo);
|
const localFileUri = this.localUriForFileInfo(fileInfo);
|
||||||
const unsupported = !isPlayable && !canOpen;
|
const unsupported = !isPlayable && !canOpen;
|
||||||
|
|
||||||
if (fileInfo && !this.state.autoDownloadStarted && this.state.uriVars && this.state.uriVars.download === 'true') {
|
if (
|
||||||
|
!this.state.autoDownloadStarted &&
|
||||||
|
claim &&
|
||||||
|
costInfo &&
|
||||||
|
((isPlayable && costInfo.cost === 0) || (this.state.uriVars && this.state.uriVars.download === 'true'))
|
||||||
|
) {
|
||||||
this.setState({ autoDownloadStarted: true }, () => {
|
this.setState({ autoDownloadStarted: true }, () => {
|
||||||
purchaseUri(uri, costInfo, !isPlayable);
|
if (!isPlayable) {
|
||||||
if (NativeModules.UtilityModule) {
|
this.checkStoragePermissionForDownload();
|
||||||
NativeModules.UtilityModule.checkDownloads();
|
} else {
|
||||||
|
purchaseUri(claim.permanent_url, costInfo, !isPlayable);
|
||||||
}
|
}
|
||||||
|
NativeModules.UtilityModule.checkDownloads();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -847,13 +875,16 @@ class FilePage extends React.PureComponent {
|
||||||
this.setState({ autoOpened: true }, () => this.openFile(localFileUri, mediaType));
|
this.setState({ autoOpened: true }, () => this.openFile(localFileUri, mediaType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isChannel) {
|
||||||
|
return <ChannelPage uri={uri} navigation={navigation} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={filePageStyle.pageContainer}>
|
<View style={filePageStyle.pageContainer}>
|
||||||
{!this.state.fullscreenMode && <UriBar value={uri} navigation={navigation} />}
|
{!this.state.fullscreenMode && <UriBar value={uri} navigation={navigation} />}
|
||||||
{this.state.showWebView && isWebViewable && (
|
{this.state.showWebView && isWebViewable && (
|
||||||
<WebView allowFileAccess source={{ uri: localFileUri }} style={filePageStyle.viewer} />
|
<WebView allowFileAccess source={{ uri: localFileUri }} style={filePageStyle.viewer} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{this.state.showImageViewer && (
|
{this.state.showImageViewer && (
|
||||||
<ImageViewer
|
<ImageViewer
|
||||||
style={StyleSheet.flatten(filePageStyle.viewer)}
|
style={StyleSheet.flatten(filePageStyle.viewer)}
|
||||||
|
@ -861,7 +892,6 @@ class FilePage extends React.PureComponent {
|
||||||
renderIndicator={() => null}
|
renderIndicator={() => null}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!this.state.showWebView && (
|
{!this.state.showWebView && (
|
||||||
<View
|
<View
|
||||||
style={
|
style={
|
||||||
|
@ -872,7 +902,7 @@ class FilePage extends React.PureComponent {
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
activeOpacity={0.5}
|
activeOpacity={0.5}
|
||||||
style={filePageStyle.mediaContainer}
|
style={filePageStyle.mediaContainer}
|
||||||
onPress={this.onMediaContainerPressed}
|
onPress={this.onFileDownloadButtonPressed}
|
||||||
>
|
>
|
||||||
{(canOpen || (!fileInfo || (isPlayable && !canLoadMedia)) || (!canOpen && fileInfo)) && (
|
{(canOpen || (!fileInfo || (isPlayable && !canLoadMedia)) || (!canOpen && fileInfo)) && (
|
||||||
<FileItemMedia
|
<FileItemMedia
|
||||||
|
@ -908,25 +938,19 @@ class FilePage extends React.PureComponent {
|
||||||
|
|
||||||
{((isPlayable && !completed && !canLoadMedia) ||
|
{((isPlayable && !completed && !canLoadMedia) ||
|
||||||
canOpen ||
|
canOpen ||
|
||||||
(!completed && !this.state.streamingMode)) &&
|
(!completed && !this.state.streamingMode)) && (
|
||||||
!this.state.downloadPressed && (
|
|
||||||
<FileDownloadButton
|
<FileDownloadButton
|
||||||
uri={claim && claim.permanent_url ? claim.permanent_url : uri}
|
uri={claim && claim.permanent_url ? claim.permanent_url : uri}
|
||||||
style={filePageStyle.downloadButton}
|
style={filePageStyle.downloadButton}
|
||||||
openFile={() => this.openFile(localFileUri, mediaType)}
|
openFile={() => this.openFile(localFileUri, mediaType)}
|
||||||
isPlayable={isPlayable}
|
isPlayable={isPlayable}
|
||||||
isViewable={isViewable}
|
isViewable={isViewable}
|
||||||
onPlay={this.onFileDownloadButtonPlayed}
|
onFileActionPress={this.onFileDownloadButtonPressed}
|
||||||
onView={() => this.setState({ downloadPressed: true })}
|
|
||||||
onButtonLayout={() => this.setState({ downloadButtonShown: true })}
|
onButtonLayout={() => this.setState({ downloadButtonShown: true })}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!fileInfo && (
|
{!fileInfo && (
|
||||||
<FilePrice
|
<FilePrice uri={uri} style={filePageStyle.filePriceContainer} textStyle={filePageStyle.filePriceText} />
|
||||||
uri={uri}
|
|
||||||
style={filePageStyle.filePriceContainer}
|
|
||||||
textStyle={filePageStyle.filePriceText}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<TouchableOpacity style={filePageStyle.backButton} onPress={this.onBackButtonPressed}>
|
<TouchableOpacity style={filePageStyle.backButton} onPress={this.onBackButtonPressed}>
|
||||||
|
@ -958,7 +982,7 @@ class FilePage extends React.PureComponent {
|
||||||
uri={uri}
|
uri={uri}
|
||||||
source={this.playerUriForFileInfo(fileInfo)}
|
source={this.playerUriForFileInfo(fileInfo)}
|
||||||
style={playerStyle}
|
style={playerStyle}
|
||||||
autoPlay={autoplay || this.state.autoPlayMedia}
|
autoPlay
|
||||||
onFullscreenToggled={this.handleFullscreenToggle}
|
onFullscreenToggled={this.handleFullscreenToggle}
|
||||||
onLayout={evt => {
|
onLayout={evt => {
|
||||||
if (!this.state.playerHeight) {
|
if (!this.state.playerHeight) {
|
||||||
|
@ -1182,9 +1206,6 @@ class FilePage extends React.PureComponent {
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FilePage;
|
export default FilePage;
|
||||||
|
|
|
@ -228,7 +228,13 @@ class FirstRunScreen extends React.PureComponent {
|
||||||
handleContinuePressed = () => {
|
handleContinuePressed = () => {
|
||||||
const { notify, user, hasSyncedWallet } = this.props;
|
const { notify, user, hasSyncedWallet } = this.props;
|
||||||
const pageIndex = FirstRunScreen.pages.indexOf(this.state.currentPage);
|
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
|
// do apply sync to check if the password is valid
|
||||||
if (hasSyncedWallet) {
|
if (hasSyncedWallet) {
|
||||||
this.checkWalletPassword();
|
this.checkWalletPassword();
|
||||||
|
@ -256,7 +262,7 @@ class FirstRunScreen extends React.PureComponent {
|
||||||
} else {
|
} else {
|
||||||
this.showNextPage();
|
this.showNextPage();
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
};
|
};
|
||||||
|
|
||||||
handleEmailCollectPageContinue() {
|
handleEmailCollectPageContinue() {
|
||||||
|
@ -500,7 +506,12 @@ class FirstRunScreen extends React.PureComponent {
|
||||||
{Constants.FIRST_RUN_PAGE_SKIP_ACCOUNT !== this.state.currentPage &&
|
{Constants.FIRST_RUN_PAGE_SKIP_ACCOUNT !== this.state.currentPage &&
|
||||||
Constants.FIRST_RUN_PAGE_EMAIL_VERIFY !== this.state.currentPage && (
|
Constants.FIRST_RUN_PAGE_EMAIL_VERIFY !== this.state.currentPage && (
|
||||||
<Text style={firstRunStyle.buttonText}>
|
<Text style={firstRunStyle.buttonText}>
|
||||||
{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')}{' '}
|
||||||
|
»
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
|
@ -94,6 +94,11 @@ const fileListStyle = StyleSheet.create({
|
||||||
top: 8,
|
top: 8,
|
||||||
left: 8,
|
left: 8,
|
||||||
},
|
},
|
||||||
|
featuredDownloadedIcon: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: 16,
|
||||||
|
top: 16,
|
||||||
|
},
|
||||||
fileItem: {
|
fileItem: {
|
||||||
marginLeft: 24,
|
marginLeft: 24,
|
||||||
marginRight: 24,
|
marginRight: 24,
|
||||||
|
|
Loading…
Reference in a new issue