/**
* Copyright (C) 2021 Thomas Weber
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import {connect} from 'react-redux';
import {compose} from 'redux';
import {FormattedMessage, defineMessages, injectIntl, intlShape} from 'react-intl';
import {getIsLoading} from '../reducers/project-state.js';
import AppStateHOC from '../lib/app-state-hoc.jsx';
import ErrorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
import TWProjectMetaFetcherHOC from '../lib/tw-project-meta-fetcher-hoc.jsx';
import TWStateManagerHOC from '../lib/tw-state-manager-hoc.jsx';
import SBFileUploaderHOC from '../lib/sb-file-uploader-hoc.jsx';
import TWPackagerIntegrationHOC from '../lib/tw-packager-integration-hoc.jsx';
import SettingsStore from '../addons/settings-store-singleton';
import '../lib/tw-fix-history-api';
import GUI from './render-gui.jsx';
import MenuBar from '../components/menu-bar/menu-bar.jsx';
import ProjectInput from '../components/tw-project-input/project-input.jsx';
import FeaturedProjects from '../components/tw-featured-projects/featured-projects.jsx';
import Description from '../components/tw-description/description.jsx';
import BrowserModal from '../components/browser-modal/browser-modal.jsx';
import CloudVariableBadge from '../containers/tw-cloud-variable-badge.jsx';
import {isBrowserSupported} from '../lib/tw-environment-support-prober';
import AddonChannels from '../addons/channels';
import {loadServiceWorker} from './load-service-worker';
import runAddons from '../addons/entry';
import InvalidEmbed from '../components/tw-invalid-embed/invalid-embed.jsx';
import {APP_NAME} from '../lib/brand.js';
import styles from './interface.css';
const isInvalidEmbed = window.parent !== window;
const handleClickAddonSettings = addonId => {
// addonId might be a string of the addon to focus on, undefined, or an event (treat like undefined)
const path = process.env.ROUTING_STYLE === 'wildcard' ? 'addons' : 'addons.html';
const url = `${process.env.ROOT}${path}${typeof addonId === 'string' ? `#${addonId}` : ''}`;
window.open(url);
};
const messages = defineMessages({
defaultTitle: {
defaultMessage: 'Run Scratch projects faster',
description: 'Title of homepage',
id: 'tw.guiDefaultTitle'
}
});
const WrappedMenuBar = compose(
SBFileUploaderHOC,
TWPackagerIntegrationHOC
)(MenuBar);
if (AddonChannels.reloadChannel) {
AddonChannels.reloadChannel.addEventListener('message', () => {
location.reload();
});
}
if (AddonChannels.changeChannel) {
AddonChannels.changeChannel.addEventListener('message', e => {
SettingsStore.setStoreWithVersionCheck(e.data);
});
}
runAddons();
const Footer = () => (
);
class Interface extends React.Component {
constructor (props) {
super(props);
this.handleUpdateProjectTitle = this.handleUpdateProjectTitle.bind(this);
}
componentDidUpdate (prevProps) {
if (prevProps.isLoading && !this.props.isLoading) {
loadServiceWorker();
}
}
handleUpdateProjectTitle (title, isDefault) {
if (isDefault || !title) {
document.title = `${APP_NAME} - ${this.props.intl.formatMessage(messages.defaultTitle)}`;
} else {
document.title = `${title} - ${APP_NAME}`;
}
}
render () {
if (isInvalidEmbed) {
return ;
}
const {
/* eslint-disable no-unused-vars */
intl,
hasCloudVariables,
description,
isFullScreen,
isLoading,
isPlayerOnly,
isRtl,
projectId,
/* eslint-enable no-unused-vars */
...props
} = this.props;
const isHomepage = isPlayerOnly && !isFullScreen;
const isEditor = !isPlayerOnly;
return (
{isHomepage ? (
) : null}
{isHomepage ? (
{isBrowserSupported() ? null : (
)}
{(
// eslint-disable-next-line max-len
description.instructions === 'unshared' || description.credits === 'unshared'
) && (
{'https://docs.turbowarp.org/unshared-projects'}
)
}}
/>
)}
{hasCloudVariables && projectId !== '0' && (
)}
{description.instructions || description.credits ? (
) : null}
) : null}
{isHomepage &&
}
);
}
}
Interface.propTypes = {
intl: intlShape,
hasCloudVariables: PropTypes.bool,
customStageSize: PropTypes.shape({
width: PropTypes.number,
height: PropTypes.number
}),
description: PropTypes.shape({
credits: PropTypes.string,
instructions: PropTypes.string
}),
isFullScreen: PropTypes.bool,
isLoading: PropTypes.bool,
isPlayerOnly: PropTypes.bool,
isRtl: PropTypes.bool,
projectId: PropTypes.string
};
const mapStateToProps = state => ({
hasCloudVariables: state.scratchGui.tw.hasCloudVariables,
customStageSize: state.scratchGui.customStageSize,
description: state.scratchGui.tw.description,
isFullScreen: state.scratchGui.mode.isFullScreen,
isLoading: getIsLoading(state.scratchGui.projectState.loadingState),
isPlayerOnly: state.scratchGui.mode.isPlayerOnly,
isRtl: state.locales.isRtl,
projectId: state.scratchGui.projectState.projectId
});
const mapDispatchToProps = () => ({});
const ConnectedInterface = injectIntl(connect(
mapStateToProps,
mapDispatchToProps
)(Interface));
const WrappedInterface = compose(
AppStateHOC,
ErrorBoundaryHOC('TW Interface'),
TWProjectMetaFetcherHOC,
TWStateManagerHOC,
TWPackagerIntegrationHOC
)(ConnectedInterface);
export default WrappedInterface;