2018-08-13 12:23:01 -04:00
// @flow
2018-10-29 13:23:53 -04:00
import * as MODALS from 'constants/modal_types' ;
2019-08-08 16:30:03 -04:00
import * as SETTINGS from 'constants/settings' ;
2019-05-29 15:48:44 -04:00
import React from 'react' ;
2018-10-29 13:23:53 -04:00
import { Lbry } from 'lbry-redux' ;
2019-05-29 15:48:44 -04:00
import Button from 'component/button' ;
2018-07-18 15:48:30 -04:00
import ModalWalletUnlock from 'modal/modalWalletUnlock' ;
2017-12-21 18:08:54 -03:00
import ModalIncompatibleDaemon from 'modal/modalIncompatibleDaemon' ;
import ModalUpgrade from 'modal/modalUpgrade' ;
import ModalDownloading from 'modal/modalDownloading' ;
2019-11-22 16:13:00 -05:00
import Card from 'component/common/card' ;
import I18nMessage from 'component/i18nMessage' ;
2019-05-29 15:48:44 -04:00
import 'css-doodle' ;
2016-11-22 14:19:08 -06:00
2019-05-29 15:48:44 -04:00
const FORTY _FIVE _SECONDS = 45 * 1000 ;
2019-12-11 15:09:27 -05:00
const UPDATE _INTERVAL = 500 ; // .5 seconds
2020-01-13 15:02:05 -05:00
const MAX _WALLET _WAIT = 20 ; // 10 seconds for wallet to be started, but servers to be unavailable
2018-11-08 14:48:38 -05:00
2018-03-26 14:32:43 -07:00
type Props = {
checkDaemonVersion : ( ) => Promise < any > ,
2019-10-21 20:12:43 -04:00
notifyUnlockWallet : ( ? boolean ) => Promise < any > ,
2018-08-13 12:23:01 -04:00
daemonVersionMatched : boolean ,
onReadyToLaunch : ( ) => void ,
2019-01-09 20:38:26 -05:00
hideModal : ( ) => void ,
2018-10-29 13:23:53 -04:00
modal : ? {
2018-04-23 14:02:06 -04:00
id : string ,
} ,
2019-08-08 16:30:03 -04:00
animationHidden : boolean ,
2019-08-09 13:12:28 -04:00
setClientSetting : ( string , boolean ) => void ,
2019-12-11 15:09:27 -05:00
clearWalletServers : ( ) => void ,
doShowSnackBar : string => void ,
2018-03-26 14:32:43 -07:00
} ;
2017-05-17 04:10:25 -04:00
2018-03-26 14:32:43 -07:00
type State = {
details : string ,
message : string ,
2018-07-18 15:48:30 -04:00
launchedModal : boolean ,
2018-11-08 14:48:38 -05:00
error : boolean ,
2019-01-09 20:38:26 -05:00
isRunning : boolean ,
launchWithIncompatibleDaemon : boolean ,
2019-12-11 15:09:27 -05:00
waitingForWallet : number ,
2018-03-26 14:32:43 -07:00
} ;
2019-01-09 20:38:26 -05:00
export default class SplashScreen extends React . PureComponent < Props , State > {
2018-03-26 14:32:43 -07:00
constructor ( props : Props ) {
2017-05-17 04:10:25 -04:00
super ( props ) ;
this . state = {
2019-08-08 16:30:03 -04:00
details : _ _ ( 'Starting...' ) ,
2017-12-21 18:08:54 -03:00
message : _ _ ( 'Connecting' ) ,
2018-07-18 15:48:30 -04:00
launchedModal : false ,
2019-03-08 14:20:17 -05:00
error : false ,
2020-02-05 13:01:07 -05:00
launchWithIncompatibleDaemon : ! process . env . NODE _ENV === 'production' ,
2019-01-09 20:38:26 -05:00
isRunning : false ,
2019-12-11 15:09:27 -05:00
waitingForWallet : 0 ,
2017-05-17 04:10:25 -04:00
} ;
2018-08-20 12:33:36 -04:00
2018-11-12 13:22:51 -05:00
( this : any ) . renderModals = this . renderModals . bind ( this ) ;
2019-01-09 20:38:26 -05:00
( this : any ) . runWithIncompatibleDaemon = this . runWithIncompatibleDaemon . bind ( this ) ;
2018-11-08 14:48:38 -05:00
this . timeout = undefined ;
2017-05-17 04:10:25 -04:00
}
2018-08-13 12:23:01 -04:00
componentDidMount ( ) {
const { checkDaemonVersion } = this . props ;
2018-11-08 14:48:38 -05:00
this . adjustErrorTimeout ( ) ;
2019-07-22 00:31:25 -04:00
2018-08-13 12:23:01 -04:00
Lbry . connect ( )
2018-12-05 16:09:11 -05:00
. then ( checkDaemonVersion )
2018-08-13 12:23:01 -04:00
. then ( ( ) => {
this . updateStatus ( ) ;
} )
. catch ( ( ) => {
this . setState ( {
message : _ _ ( 'Connection Failure' ) ,
details : _ _ (
2019-03-20 17:43:00 -04:00
'Try closing all LBRY processes and starting again. If this still happens, your anti-virus software or firewall may be preventing LBRY from connecting. Contact hello@lbry.com if you think this is a software bug.'
2018-08-13 12:23:01 -04:00
) ,
} ) ;
} ) ;
}
2018-11-08 14:48:38 -05:00
componentDidUpdate ( ) {
this . adjustErrorTimeout ( ) ;
}
componentWillUnmount ( ) {
if ( this . timeout ) {
clearTimeout ( this . timeout ) ;
}
}
adjustErrorTimeout ( ) {
if ( this . timeout ) {
clearTimeout ( this . timeout ) ;
}
// Every time we make it to a new step in the daemon startup process, reset the timer
// If nothing changes after 1 minute, show the error message.
this . timeout = setTimeout ( ( ) => {
this . setState ( { error : true } ) ;
2019-05-29 15:48:44 -04:00
} , FORTY _FIVE _SECONDS ) ;
2018-11-08 14:48:38 -05:00
}
2017-05-17 04:10:25 -04:00
updateStatus ( ) {
2019-12-11 15:09:27 -05:00
const { modal , notifyUnlockWallet , clearWalletServers , doShowSnackBar } = this . props ;
2019-10-17 14:32:36 -04:00
const { launchedModal } = this . state ;
2018-12-05 16:09:11 -05:00
Lbry . status ( ) . then ( status => {
2019-12-19 08:53:15 -05:00
const { wallet } = status ;
if ( status . is _running && wallet && wallet . available _servers ) {
2019-10-17 14:32:36 -04:00
Lbry . wallet _status ( ) . then ( walletStatus => {
2019-11-05 15:16:41 -05:00
if ( walletStatus . is _locked ) {
2019-10-17 14:32:36 -04:00
// Clear the error timeout, it might sit on this step for a while until someone enters their password
if ( this . timeout ) {
clearTimeout ( this . timeout ) ;
}
// Make sure there isn't another active modal (like INCOMPATIBLE_DAEMON)
2019-10-17 14:54:33 -04:00
this . updateStatusCallback ( status , true ) ;
2019-10-17 14:32:36 -04:00
if ( launchedModal === false && ! modal ) {
this . setState ( { launchedModal : true } , ( ) => notifyUnlockWallet ( ) ) ;
}
} else {
this . updateStatusCallback ( status ) ;
}
} ) ;
2019-12-11 15:09:27 -05:00
} else if ( this . state . waitingForWallet > MAX _WALLET _WAIT && launchedModal === false && ! modal ) {
clearWalletServers ( ) ;
2019-12-13 14:47:50 -05:00
doShowSnackBar (
_ _ (
'The wallet server took a bit too long. Resetting defaults just in case. Shutdown (Cmd/Ctrl+Q) LBRY and restart if this continues.'
)
) ;
this . setState ( { waitingForWallet : 0 } ) ;
2019-12-11 15:27:03 -05:00
this . updateStatusCallback ( status ) ;
2019-10-17 14:32:36 -04:00
} else {
this . updateStatusCallback ( status ) ;
}
2018-12-05 16:09:11 -05:00
} ) ;
2017-05-17 04:10:25 -04:00
}
2019-10-17 14:32:36 -04:00
updateStatusCallback ( status : StatusResponse , waitingForUnlock : boolean = false ) {
2019-04-24 10:02:08 -04:00
if ( status . connection _status . code !== 'connected' ) {
2019-03-04 23:46:57 -05:00
this . setState ( { error : true } ) ;
2018-11-08 14:48:38 -05:00
return ;
}
2019-12-13 14:47:50 -05:00
const { wallet , startup _status : startupStatus } = status ;
2018-11-08 14:48:38 -05:00
// If the wallet is locked, stop doing anything and make the user input their password
2019-12-19 08:53:15 -05:00
if ( startupStatus && wallet && wallet . available _servers < 1 ) {
this . setState ( { waitingForWallet : this . state . waitingForWallet + UPDATE _INTERVAL / 1000 } ) ;
} else if ( status . is _running && ! waitingForUnlock ) {
2019-10-17 14:32:36 -04:00
Lbry . resolve ( { urls : 'lbry://one' } ) . then ( ( ) => {
this . setState ( { isRunning : true } , ( ) => this . continueAppLaunch ( ) ) ;
2016-04-14 02:27:06 -04:00
} ) ;
2019-10-17 14:32:36 -04:00
return ;
2019-12-11 15:09:27 -05:00
} else if ( wallet && wallet . blocks _behind > 0 ) {
2019-10-17 13:49:00 -04:00
this . setState ( {
message : _ _ ( 'Blockchain Sync' ) ,
2019-12-03 13:47:03 -05:00
details : ` ${ _ _ ( 'Catching up...' ) } ( ${ wallet . headers _synchronization _progress } %) ` ,
2019-10-17 13:49:00 -04:00
} ) ;
} else if ( wallet && wallet . blocks _behind === 0 && ! status . is _running && startupStatus . database ) {
this . setState ( {
message : 'Finalizing' ,
details : 'Almost ready...' ,
} ) ;
2019-10-17 11:37:57 -04:00
}
2019-10-17 13:49:00 -04:00
setTimeout ( ( ) => {
this . updateStatus ( ) ;
2019-12-11 15:09:27 -05:00
} , UPDATE _INTERVAL ) ;
2017-05-17 04:10:25 -04:00
}
2019-01-09 20:38:26 -05:00
runWithIncompatibleDaemon ( ) {
const { hideModal } = this . props ;
hideModal ( ) ;
this . setState ( { launchWithIncompatibleDaemon : true } , ( ) => this . continueAppLaunch ( ) ) ;
}
continueAppLaunch ( ) {
const { daemonVersionMatched , onReadyToLaunch } = this . props ;
const { isRunning , launchWithIncompatibleDaemon } = this . state ;
2019-05-29 15:48:44 -04:00
if ( daemonVersionMatched ) {
onReadyToLaunch ( ) ;
} else if ( launchWithIncompatibleDaemon && isRunning ) {
// The user may have decided to run the app with mismatched daemons
// They could make this decision before the daemon is finished starting up
// If it isn't running, this function will be called after the daemon is started
onReadyToLaunch ( ) ;
}
2019-01-09 20:38:26 -05:00
}
2018-11-08 14:48:38 -05:00
timeout : ? TimeoutID ;
2018-08-20 12:33:36 -04:00
2018-11-12 13:22:51 -05:00
renderModals ( ) {
2018-10-29 13:23:53 -04:00
const { modal } = this . props ;
const modalId = modal && modal . id ;
2018-04-23 14:02:06 -04:00
2018-11-12 13:22:51 -05:00
if ( ! modalId ) {
return null ;
}
switch ( modalId ) {
case MODALS . INCOMPATIBLE _DAEMON :
2019-01-09 20:38:26 -05:00
return < ModalIncompatibleDaemon onContinueAnyway = { this . runWithIncompatibleDaemon } / > ;
2018-11-12 13:22:51 -05:00
case MODALS . WALLET _UNLOCK :
return < ModalWalletUnlock / > ;
case MODALS . UPGRADE :
return < ModalUpgrade / > ;
case MODALS . DOWNLOADING :
return < ModalDownloading / > ;
default :
return null ;
}
}
render ( ) {
2019-08-08 16:30:03 -04:00
const { error , details } = this . state ;
const { animationHidden , setClientSetting } = this . props ;
2018-11-12 13:22:51 -05:00
2017-06-06 17:19:12 -04:00
return (
2019-05-29 15:48:44 -04:00
< div className = "splash" >
2019-08-08 16:30:03 -04:00
< h1 className = "splash__title" > LBRY < / h1 >
< div className = "splash__details" > { details } < / div >
2020-03-02 09:42:43 -05:00
{ ! animationHidden && ! error && (
2019-08-08 16:30:03 -04:00
< css - doodle class = "doodle" >
{ `
2019-11-22 16:13:00 -05:00
-- color : @ p ( var ( -- color - primary ) , var ( -- color - secondary ) , var ( -- color - focus ) , var ( -- color - nothing ) ) ;
2019-06-05 00:14:15 -04:00
: doodle {
@ grid : 30 x1 / 18 vmin ;
-- deg : @ p ( - 180 deg , 180 deg ) ;
}
: container {
perspective : 30 vmin ;
}
2019-07-17 20:04:17 -04:00
2019-06-05 00:14:15 -04:00
@ place - cell : center ;
@ size : 100 % ;
2019-07-17 20:04:17 -04:00
box - shadow : @ m2 ( 0 0 50 px var ( -- color ) ) ;
2019-06-05 00:14:15 -04:00
will - change : transform , opacity ;
animation : scale - up 12 s linear infinite ;
animation - delay : calc ( - 12 s / @ size ( ) * @ i ( ) ) ;
@ keyframes scale - up {
0 % , 95.01 % , 100 % {
transform : translateZ ( 0 ) rotate ( 0 ) ;
opacity : 0 ;
}
2019-07-17 20:04:17 -04:00
10 % {
opacity : 1 ;
2019-06-05 00:14:15 -04:00
}
95 % {
2019-07-17 20:04:17 -04:00
transform :
2019-06-05 00:14:15 -04:00
translateZ ( 35 vmin ) rotateZ ( @ var ( -- deg ) ) ;
}
}
)
` }
2019-08-08 16:30:03 -04:00
< / c s s - d o o d l e >
) }
2020-03-02 09:42:43 -05:00
{ ! error && (
< Button
className = "splash__animation-toggle"
label = { ! animationHidden ? _ _ ( 'I feel woosy! Stop spinning!' ) : _ _ ( 'Spin Spin Sugar' ) }
onClick = { ( ) => setClientSetting ( SETTINGS . HIDE _SPLASH _ANIMATION , ! animationHidden ) }
/ >
) }
2019-05-29 15:48:44 -04:00
{ error && (
2019-11-22 16:13:00 -05:00
< Card
title = { _ _ ( 'Error Starting Up' ) }
subtitle = {
< React.Fragment >
< p >
2020-03-02 09:42:43 -05:00
{ _ _ (
'You can try refreshing to fix it. If you still have issues, your anti-virus software or firewall may be preventing startup.'
) }
< / p >
< p >
< I18nMessage
tokens = { {
help _link : (
< Button button = "link" href = "https://lbry.com/faq/startup-troubleshooting" label = "this link" / >
) ,
} }
>
Reach out to hello @ lbry . com for help , or check out % help _link % .
< / I18nMessage >
2019-11-22 16:13:00 -05:00
< / p >
< / React.Fragment >
}
actions = { < Button button = "primary" label = { _ _ ( 'Refresh' ) } onClick = { ( ) => window . location . reload ( ) } / > }
/ >
2019-05-29 15:48:44 -04:00
) }
2017-07-19 17:05:08 -04:00
{ / * T e m p h a c k : d o n ' t s h o w a n y m o d a l s o n s p l a s h s c r e e n d a e m o n i s r u n n i n g ;
daemon doesn ' t let you quit during startup , so the "Quit" buttons
2019-05-29 15:48:44 -04:00
in the modals won ' t work . * / }
2018-12-05 16:09:11 -05:00
{ this . renderModals ( ) }
2019-05-29 15:48:44 -04:00
< / div >
2017-06-06 17:19:12 -04:00
) ;
2016-04-09 20:00:56 -04:00
}
2017-05-17 04:10:25 -04:00
}