mirror of
https://github.com/LBRYFoundation/lbry-android.git
synced 2025-08-30 08:41:26 +00:00
302 lines
9.3 KiB
JavaScript
302 lines
9.3 KiB
JavaScript
import React from 'react';
|
|
import { Lbry } from 'lbry-redux';
|
|
import {
|
|
ActivityIndicator,
|
|
Linking,
|
|
NativeModules,
|
|
Platform,
|
|
ProgressBarAndroid,
|
|
Text,
|
|
View
|
|
} from 'react-native';
|
|
import { NavigationActions, StackActions } from 'react-navigation';
|
|
import { decode as atob } from 'base-64';
|
|
import { navigateToUri } from 'utils/helper';
|
|
import AsyncStorage from '@react-native-community/async-storage';
|
|
import PropTypes from 'prop-types';
|
|
import Colors from 'styles/colors';
|
|
import Constants from 'constants';
|
|
import splashStyle from 'styles/splash';
|
|
|
|
const BLOCK_HEIGHT_INTERVAL = 1000 * 60 * 2.5; // every 2.5 minutes
|
|
|
|
class SplashScreen extends React.PureComponent {
|
|
static navigationOptions = {
|
|
title: 'Splash'
|
|
};
|
|
|
|
componentWillMount() {
|
|
this.setState({
|
|
daemonReady: false,
|
|
details: 'Starting daemon',
|
|
message: 'Connecting',
|
|
isRunning: false,
|
|
isLagging: false,
|
|
launchUrl: null,
|
|
isDownloadingHeaders: false,
|
|
headersDownloadProgress: 0,
|
|
shouldAuthenticate: false,
|
|
subscriptionsFetched: false
|
|
});
|
|
|
|
if (NativeModules.DaemonServiceControl) {
|
|
NativeModules.DaemonServiceControl.startService();
|
|
}
|
|
}
|
|
|
|
componentDidMount() {
|
|
// Start measuring the first launch time from the splash screen (time from daemon start to user interaction)
|
|
AsyncStorage.getItem('hasLaunched').then(value => {
|
|
if (value == null || value !== 'true') {
|
|
AsyncStorage.setItem('hasLaunched', 'true');
|
|
// only set firstLaunchTime since we've determined that this is the first app launch ever
|
|
AsyncStorage.setItem('firstLaunchTime', String(moment().unix()));
|
|
}
|
|
});
|
|
|
|
this.props.fetchRewardedContent();
|
|
}
|
|
|
|
updateStatus() {
|
|
Lbry.status().then(status => {
|
|
this._updateStatusCallback(status);
|
|
});
|
|
}
|
|
|
|
navigateToMain = () => {
|
|
const { navigation } = this.props;
|
|
const resetAction = StackActions.reset({
|
|
index: 0,
|
|
actions: [
|
|
NavigationActions.navigate({ routeName: 'Main'})
|
|
]
|
|
});
|
|
navigation.dispatch(resetAction);
|
|
|
|
const launchUrl = navigation.state.params.launchUrl || this.state.launchUrl;
|
|
if (launchUrl) {
|
|
if (launchUrl.startsWith('lbry://?verify=')) {
|
|
let verification = {};
|
|
try {
|
|
verification = JSON.parse(atob(launchUrl.substring(15)));
|
|
} catch (error) {
|
|
console.log(error);
|
|
}
|
|
if (verification.token && verification.recaptcha) {
|
|
AsyncStorage.setItem(Constants.KEY_SHOULD_VERIFY_EMAIL, 'true');
|
|
try {
|
|
verifyUserEmail(verification.token, verification.recaptcha);
|
|
} catch (error) {
|
|
const message = 'Invalid Verification Token';
|
|
verifyUserEmailFailure(message);
|
|
notify({ message });
|
|
}
|
|
} else {
|
|
notify({
|
|
message: 'Invalid Verification URI',
|
|
});
|
|
}
|
|
} else {
|
|
navigateToUri(navigation, launchUrl);
|
|
}
|
|
}
|
|
}
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
const {
|
|
emailToVerify,
|
|
getSync,
|
|
setEmailToVerify,
|
|
verifyUserEmail,
|
|
verifyUserEmailFailure
|
|
} = this.props;
|
|
const { user } = nextProps;
|
|
|
|
if (this.state.daemonReady && this.state.shouldAuthenticate && user && user.id) {
|
|
this.setState({ shouldAuthenticate: false }, () => {
|
|
AsyncStorage.getItem(Constants.KEY_FIRST_RUN_EMAIL).then(email => {
|
|
if (email) {
|
|
setEmailToVerify(email);
|
|
}
|
|
|
|
// user is authenticated, navigate to the main view
|
|
if (user.has_verified_email) {
|
|
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(walletPassword => {
|
|
getSync(walletPassword);
|
|
this.navigateToMain();
|
|
});
|
|
return;
|
|
}
|
|
|
|
this.navigateToMain();
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
finishSplashScreen = () => {
|
|
const {
|
|
authenticate,
|
|
balanceSubscribe,
|
|
blacklistedOutpointsSubscribe,
|
|
checkSubscriptionsInit,
|
|
updateBlockHeight,
|
|
navigation,
|
|
notify
|
|
} = this.props;
|
|
|
|
Lbry.resolve({ urls: 'lbry://one' }).then(() => {
|
|
// Leave the splash screen
|
|
balanceSubscribe();
|
|
blacklistedOutpointsSubscribe();
|
|
checkSubscriptionsInit();
|
|
updateBlockHeight();
|
|
setInterval(() => { updateBlockHeight(); }, BLOCK_HEIGHT_INTERVAL);
|
|
NativeModules.VersionInfo.getAppVersion().then(appVersion => {
|
|
this.setState({ shouldAuthenticate: true });
|
|
authenticate(appVersion, Platform.OS);
|
|
});
|
|
});
|
|
}
|
|
|
|
_updateStatusCallback(status) {
|
|
const { deleteCompleteBlobs, fetchSubscriptions } = this.props;
|
|
const startupStatus = status.startup_status;
|
|
// At the minimum, wallet should be started and blocks_behind equal to 0 before calling resolve
|
|
const hasStarted = startupStatus.stream_manager && startupStatus.wallet && status.wallet.blocks_behind <= 0;
|
|
if (hasStarted) {
|
|
deleteCompleteBlobs();
|
|
|
|
// Wait until we are able to resolve a name before declaring
|
|
// that we are done.
|
|
// TODO: This is a hack, and the logic should live in the daemon
|
|
// to give us a better sense of when we are actually started
|
|
this.setState({
|
|
daemonReady: true,
|
|
message: 'Testing Network',
|
|
details: 'Waiting for name resolution',
|
|
isLagging: false,
|
|
isRunning: true,
|
|
});
|
|
|
|
AsyncStorage.getItem(Constants.KEY_FIRST_RUN_PASSWORD).then(passwordSet => {
|
|
if ("true" === passwordSet) {
|
|
// encrypt the wallet
|
|
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(password => {
|
|
if (!password || password.trim().length === 0) {
|
|
this.finishSplashScreen();
|
|
return;
|
|
}
|
|
|
|
Lbry.account_encrypt({ new_password: password }).then((result) => {
|
|
AsyncStorage.removeItem(Constants.KEY_FIRST_RUN_PASSWORD);
|
|
Lbry.account_unlock({ password }).then(() => this.finishSplashScreen());
|
|
});
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
// For now, automatically unlock the wallet if a password is set so that downloads work
|
|
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(password => {
|
|
if (password && password.trim().length > 0) {
|
|
// unlock the wallet and then finish the splash screen
|
|
Lbry.account_unlock({ password }).then(() => this.finishSplashScreen());
|
|
return;
|
|
}
|
|
|
|
this.finishSplashScreen();
|
|
});
|
|
});
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
const blockchainHeaders = status.blockchain_headers;
|
|
const walletStatus = status.wallet;
|
|
|
|
if (blockchainHeaders) {
|
|
this.setState({
|
|
isDownloadingHeaders: blockchainHeaders.downloading_headers,
|
|
headersDownloadProgress: blockchainHeaders.download_progress
|
|
});
|
|
} else {
|
|
// set downloading flag to false if blockchain_headers isn't in the status response
|
|
this.setState({
|
|
isDownloadingHeaders: false,
|
|
});
|
|
}
|
|
|
|
if (blockchainHeaders && blockchainHeaders.downloading_headers) {
|
|
const downloadProgress = blockchainHeaders.download_progress ? blockchainHeaders.download_progress : 0;
|
|
this.setState({
|
|
message: 'Blockchain Sync',
|
|
details: `Catching up with the blockchain (${downloadProgress}%)`,
|
|
});
|
|
} else if (walletStatus && walletStatus.blocks_behind > 0) {
|
|
const behind = walletStatus.blocks_behind;
|
|
const behindText = behind + ' block' + (behind == 1 ? '' : 's') + ' behind';
|
|
this.setState({
|
|
message: 'Blockchain Sync',
|
|
details: behindText,
|
|
});
|
|
} else {
|
|
this.setState({
|
|
message: 'Network Loading',
|
|
details: 'Initializing LBRY service...'
|
|
});
|
|
}
|
|
|
|
setTimeout(() => {
|
|
this.updateStatus();
|
|
}, 500);
|
|
}
|
|
|
|
componentDidMount() {
|
|
if (NativeModules.Firebase) {
|
|
NativeModules.Firebase.track('app_launch', null);
|
|
}
|
|
|
|
Linking.getInitialURL().then((url) => {
|
|
if (url) {
|
|
this.setState({ launchUrl: url });
|
|
}
|
|
});
|
|
|
|
Lbry
|
|
.connect()
|
|
.then(() => {
|
|
this.updateStatus();
|
|
})
|
|
.catch((e) => {
|
|
this.setState({
|
|
isLagging: true,
|
|
message: 'Connection Failure',
|
|
details:
|
|
'We could not establish a connection to the daemon. Your data connection may be preventing LBRY from connecting. Contact hello@lbry.com if you think this is a software bug.'
|
|
});
|
|
});
|
|
}
|
|
|
|
render() {
|
|
const { message, details, isLagging, isRunning } = this.state;
|
|
|
|
return (
|
|
<View style={splashStyle.container}>
|
|
<Text style={splashStyle.title}>LBRY</Text>
|
|
{'android' === Platform.OS && this.state.isDownloadingHeaders &&
|
|
<ProgressBarAndroid color={Colors.White}
|
|
indeterminate={false}
|
|
styleAttr={"Horizontal"}
|
|
style={splashStyle.progress}
|
|
progress={this.state.headersDownloadProgress/100.0} />}
|
|
{!this.state.isDownloadingHeaders && <ActivityIndicator color={Colors.White} style={splashStyle.loading} size={"small"} />}
|
|
<Text style={splashStyle.message}>{message}</Text>
|
|
<Text style={splashStyle.details}>{details}</Text>
|
|
</View>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default SplashScreen;
|