Spaces:
Running
Running
import React from 'react'; | |
import PropTypes from 'prop-types'; | |
import {Provider} from 'react-redux'; | |
import {createStore, combineReducers, compose} from 'redux'; | |
import ConnectedIntlProvider from './connected-intl-provider.jsx'; | |
import AddonHooks from '../addons/hooks'; | |
import localesReducer, {initLocale, localesInitialState} from '../reducers/locales'; | |
import {setPlayer, setFullScreen} from '../reducers/mode.js'; | |
import locales from '@turbowarp/scratch-l10n'; | |
import {detectLocale} from './detect-locale'; | |
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; | |
/* | |
* Higher Order Component to provide redux state. If an `intl` prop is provided | |
* it will override the internal `intl` redux state | |
* @param {React.Component} WrappedComponent - component to provide state for | |
* @param {boolean} localesOnly - only provide the locale state, not everything | |
* required by the GUI. Used to exclude excess state when | |
only rendering modals, not the GUI. | |
* @returns {React.Component} component with redux and intl state provided | |
*/ | |
const AppStateHOC = function (WrappedComponent, localesOnly) { | |
class AppStateWrapper extends React.Component { | |
constructor (props) { | |
super(props); | |
let initialState = {}; | |
let reducers = {}; | |
let enhancer; | |
let initializedLocales = localesInitialState; | |
const locale = detectLocale(Object.keys(locales)); | |
if (locale !== 'en') { | |
initializedLocales = initLocale(initializedLocales, locale); | |
} | |
if (localesOnly) { | |
// Used for instantiating minimal state for the unsupported | |
// browser modal | |
reducers = {locales: localesReducer}; | |
initialState = {locales: initializedLocales}; | |
enhancer = composeEnhancers(); | |
} else { | |
// You are right, this is gross. But it's necessary to avoid | |
// importing unneeded code that will crash unsupported browsers. | |
const guiRedux = require('../reducers/gui'); | |
const guiReducer = guiRedux.default; | |
const { | |
guiInitialState, | |
guiMiddleware, | |
initFullScreen, | |
initPlayer, | |
initEmbedded, | |
initTelemetryModal | |
} = guiRedux; | |
const {ScratchPaintReducer} = require('./tw-scratch-paint'); | |
let initializedGui = guiInitialState; | |
if (props.isFullScreen || props.isPlayerOnly) { | |
if (props.isFullScreen) { | |
initializedGui = initFullScreen(initializedGui); | |
} | |
if (props.isPlayerOnly) { | |
initializedGui = initPlayer(initializedGui); | |
} | |
} else if (props.showTelemetryModal) { | |
initializedGui = initTelemetryModal(initializedGui); | |
} | |
if (props.isEmbedded) { | |
initializedGui = initEmbedded(initializedGui); | |
} | |
reducers = { | |
locales: localesReducer, | |
scratchGui: guiReducer, | |
scratchPaint: ScratchPaintReducer | |
}; | |
initialState = { | |
locales: initializedLocales, | |
scratchGui: initializedGui | |
}; | |
enhancer = composeEnhancers(guiMiddleware); | |
} | |
const reducer = combineReducers(reducers); | |
const reducer2 = (previousState, action) => { | |
const nextState = reducer(previousState, action); | |
AddonHooks.appStateReducer(action, previousState, nextState); | |
return nextState; | |
}; | |
this.store = createStore( | |
reducer2, | |
initialState, | |
enhancer | |
); | |
window.ReduxStore = this.store; | |
AddonHooks.appStateStore = this.store; | |
} | |
componentDidUpdate (prevProps) { | |
if (localesOnly) return; | |
if (prevProps.isPlayerOnly !== this.props.isPlayerOnly) { | |
this.store.dispatch(setPlayer(this.props.isPlayerOnly)); | |
} | |
if (prevProps.isFullScreen !== this.props.isFullScreen) { | |
this.store.dispatch(setFullScreen(this.props.isFullScreen)); | |
} | |
} | |
render () { | |
const { | |
isFullScreen, // eslint-disable-line no-unused-vars | |
isPlayerOnly, // eslint-disable-line no-unused-vars | |
showTelemetryModal, // eslint-disable-line no-unused-vars | |
...componentProps | |
} = this.props; | |
return ( | |
<Provider store={this.store}> | |
<ConnectedIntlProvider> | |
<WrappedComponent | |
{...componentProps} | |
/> | |
</ConnectedIntlProvider> | |
</Provider> | |
); | |
} | |
} | |
AppStateWrapper.propTypes = { | |
isFullScreen: PropTypes.bool, | |
isPlayerOnly: PropTypes.bool, | |
isTelemetryEnabled: PropTypes.bool, | |
showTelemetryModal: PropTypes.bool, | |
isEmbedded: PropTypes.bool | |
}; | |
return AppStateWrapper; | |
}; | |
export default AppStateHOC; | |