Spaces:
Runtime error
Runtime error
| import React from 'react'; | |
| import {defineMessages, FormattedMessage, intlShape, injectIntl} from 'react-intl'; | |
| import classNames from 'classnames'; | |
| import styles from './loader.css'; | |
| import PropTypes from 'prop-types'; | |
| import bindAll from 'lodash.bindall'; | |
| import topBlock from './top-block.svg'; | |
| import middleBlock from './middle-block.svg'; | |
| import bottomBlock from './bottom-block.svg'; | |
| import * as progressMonitor from './tw-progress-monitor'; | |
| import isScratchDesktop from '../../lib/isScratchDesktop'; | |
| // tw: | |
| // we make some rather large changes here: | |
| // - remove random message, replaced with message dependent on what is actually being loaded | |
| // - add a progress bar | |
| // - bring in intl so that we can translate everything | |
| // The way of doing this is extremely unusual and weird compared to how things are typically done for performance. | |
| // This is because react updates are too performance crippling to handle the progress bar rapidly updating. | |
| const mainMessages = { | |
| 'gui.loader.headline': ( | |
| <FormattedMessage | |
| defaultMessage="Loading Project" | |
| description="Main loading message" | |
| id="gui.loader.headline" | |
| /> | |
| ), | |
| 'gui.loader.creating': ( | |
| <FormattedMessage | |
| defaultMessage="Creating Project" | |
| description="Main creating message" | |
| id="gui.loader.creating" | |
| /> | |
| ), | |
| 'gui.loader.playground': ( | |
| <FormattedMessage | |
| defaultMessage="Loading Playground" | |
| description="Playground load message" | |
| id="gui.loader.playground" | |
| /> | |
| ) | |
| }; | |
| const messages = defineMessages({ | |
| generic: { | |
| defaultMessage: 'Loading project …', | |
| description: 'Initial generic loading message', | |
| id: 'tw.loader.generic' | |
| }, | |
| projectData: { | |
| defaultMessage: 'Downloading project data …', | |
| description: 'Appears when loading project data', | |
| id: 'tw.loader.data' | |
| }, | |
| assetsKnown: { | |
| defaultMessage: 'Downloading assets ({complete}/{total}) …', | |
| description: 'Appears when loading project assets and amount of assets is known', | |
| id: 'tw.loader.assets.known' | |
| }, | |
| assetsUnknown: { | |
| defaultMessage: 'Downloading assets …', | |
| description: 'Appears when loading project assets but amount of assets is unknown', | |
| id: 'tw.loader.assets.unknown' | |
| } | |
| }); | |
| class LoaderComponent extends React.Component { | |
| constructor (props) { | |
| super(props); | |
| this._state = 0; | |
| this.progress = 0; | |
| this.complete = 0; | |
| this.total = 0; | |
| bindAll(this, [ | |
| 'barInnerRef', | |
| 'handleProgressChange', | |
| 'messageRef' | |
| ]); | |
| } | |
| componentDidMount () { | |
| if (!isScratchDesktop()) { | |
| progressMonitor.setProgressHandler(this.handleProgressChange); | |
| } | |
| this.updateMessage(); | |
| } | |
| componentDidUpdate () { | |
| this.update(); | |
| } | |
| componentWillUnmount () { | |
| progressMonitor.setProgressHandler(() => {}); | |
| } | |
| handleProgressChange (state, progress, complete, total) { | |
| if (state !== this._state) { | |
| this._state = state; | |
| this.updateMessage(); | |
| } | |
| this.progress = progress; | |
| this.complete = complete; | |
| this.total = total; | |
| this.update(); | |
| } | |
| update () { | |
| if (this.barInner) { | |
| this.barInner.style.width = `${this.progress * 100}%`; | |
| } | |
| if (this._state === 2) { | |
| this.updateMessage(); | |
| } | |
| } | |
| updateMessage () { | |
| if (this._state === 0) { | |
| this.message.textContent = this.props.intl.formatMessage(messages.generic); | |
| } else if (this._state === 1) { | |
| this.message.textContent = this.props.intl.formatMessage(messages.projectData); | |
| } else if (this.total > 0) { | |
| this.message.textContent = this.props.intl.formatMessage(messages.assetsKnown, { | |
| complete: this.complete, | |
| total: this.total | |
| }); | |
| } else { | |
| this.message.textContent = this.props.intl.formatMessage(messages.assetsUnknown); | |
| } | |
| } | |
| barInnerRef (element) { | |
| this.barInner = element; | |
| } | |
| messageRef (element) { | |
| this.message = element; | |
| } | |
| render () { | |
| return ( | |
| <div | |
| className={classNames(styles.background, { | |
| [styles.fullscreen]: this.props.isFullScreen | |
| })} | |
| > | |
| <div className={styles.container}> | |
| <div className={styles.blockAnimation}> | |
| <img | |
| className={styles.topBlock} | |
| src={topBlock} | |
| /> | |
| <img | |
| className={styles.middleBlock} | |
| src={middleBlock} | |
| /> | |
| <img | |
| className={styles.bottomBlock} | |
| src={bottomBlock} | |
| /> | |
| </div> | |
| <div className={styles.title}> | |
| {mainMessages[this.props.messageId]} | |
| </div> | |
| <div className={styles.messageContainerOuter}> | |
| <div | |
| className={styles.messageContainerInner} | |
| ref={this.messageRef} | |
| /> | |
| </div> | |
| {!isScratchDesktop() && ( | |
| <div className={styles.twProgressOuter}> | |
| <div | |
| className={styles.twProgressInner} | |
| ref={this.barInnerRef} | |
| /> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |
| } | |
| LoaderComponent.propTypes = { | |
| isFullScreen: PropTypes.bool, | |
| intl: intlShape.isRequired, | |
| messageId: PropTypes.string | |
| }; | |
| LoaderComponent.defaultProps = { | |
| isFullScreen: false, | |
| messageId: 'gui.loader.headline' | |
| }; | |
| export default injectIntl(LoaderComponent); | |