@@ -34,7 +34,8 @@ import TelemetryModal from '../telemetry-modal/telemetry-modal.jsx';
3434
3535import layout , { STAGE_SIZE_MODES } from '../../lib/layout-constants' ;
3636import { resolveStageSize } from '../../lib/screen-utils' ;
37- import { themeMap } from '../../lib/themes' ;
37+ import { colorModeMap } from '../../lib/settings/color-mode/index.js' ;
38+ import { DEFAULT_THEME , themeMap } from '../../lib/settings/theme/index.js' ;
3839import { AccountMenuOptionsPropTypes } from '../../lib/account-menu-options' ;
3940
4041import styles from './gui.css' ;
@@ -43,6 +44,7 @@ import costumesIcon from './icon--costumes.svg';
4344import soundsIcon from './icon--sounds.svg' ;
4445import DebugModal from '../debug-modal/debug-modal.jsx' ;
4546import { setPlatform } from '../../reducers/platform.js' ;
47+ import { setTheme } from '../../reducers/settings.js' ;
4648import { PLATFORM } from '../../lib/platform.js' ;
4749
4850// Cache this value to only retrieve it once the first time.
@@ -68,6 +70,7 @@ const GUIComponent = props => {
6870 blocksTabVisible,
6971 cardsVisible,
7072 canChangeLanguage,
73+ canChangeColorMode,
7174 canChangeTheme,
7275 canCreateNew,
7376 canEditTitle,
@@ -85,7 +88,9 @@ const GUIComponent = props => {
8588 onDebugModalClose,
8689 onTutorialSelect,
8790 enableCommunity,
91+ hasActiveMembership,
8892 isCreating,
93+ isFetchingUserData,
8994 isFullScreen,
9095 isPlayerOnly,
9196 isRtl,
@@ -130,6 +135,7 @@ const GUIComponent = props => {
130135 stageSizeMode,
131136 targetIsStage,
132137 telemetryModalVisible,
138+ colorMode,
133139 theme,
134140 tipsLibraryVisible,
135141 useExternalPeripheralList,
@@ -145,10 +151,23 @@ const GUIComponent = props => {
145151
146152 useEffect ( ( ) => {
147153 if ( props . platform ) {
154+ // TODO: This uses the imported `setPlatform` directly,
155+ // but it should probably use the dispatched version from props.
148156 setPlatform ( props . platform ) ;
149157 }
150158 } , [ props . platform ] ) ;
151159
160+ useEffect ( ( ) => {
161+ if (
162+ ! isFetchingUserData &&
163+ ! themeMap [ theme ] ?. isAvailable ?. ( { hasActiveMembership} )
164+ ) {
165+ // If the preferred theme is not available, fall back to default.
166+ // TODO: It would be cleaner to do this on redux init.
167+ props . setTheme ( DEFAULT_THEME ) ;
168+ }
169+ } , [ theme , hasActiveMembership , props . setTheme ] ) ;
170+
152171 const tabClassNames = {
153172 tabs : styles . tabs ,
154173 tab : classNames ( tabStyles . reactTabsTab , styles . tab ) ,
@@ -260,6 +279,7 @@ const GUIComponent = props => {
260279 authorUsername = { authorUsername }
261280 authorAvatarBadge = { authorAvatarBadge }
262281 canChangeLanguage = { canChangeLanguage }
282+ canChangeColorMode = { canChangeColorMode }
263283 canChangeTheme = { canChangeTheme }
264284 canCreateCopy = { canCreateCopy }
265285 canCreateNew = { canCreateNew }
@@ -270,6 +290,7 @@ const GUIComponent = props => {
270290 canShare = { canShare }
271291 className = { styles . menuBarPosition }
272292 enableCommunity = { enableCommunity }
293+ hasActiveMembership = { hasActiveMembership }
273294 isShared = { isShared }
274295 isTotallyNormal = { isTotallyNormal }
275296 logo = { logo }
@@ -364,15 +385,15 @@ const GUIComponent = props => {
364385 < TabPanel className = { tabClassNames . tabPanel } >
365386 < Box className = { styles . blocksWrapper } >
366387 < Blocks
367- key = { `${ blocksId } /${ theme } ` }
388+ key = { `${ blocksId } /${ colorMode } / ${ theme } ` }
368389 canUseCloud = { canUseCloud }
369390 grow = { 1 }
370391 isVisible = { blocksTabVisible }
371392 options = { {
372- media : `${ basePath } static/${ themeMap [ theme ] . blocksMediaFolder } /`
393+ media : `${ basePath } static/${ colorModeMap [ colorMode ] . blocksMediaFolder } /`
373394 } }
374395 stageSize = { stageSize }
375- theme = { theme }
396+ colorMode = { colorMode }
376397 vm = { vm }
377398 showNewFeatureCallouts = { showNewFeatureCallouts }
378399 username = { username }
@@ -445,6 +466,7 @@ GUIComponent.propTypes = {
445466 blocksTabVisible : PropTypes . bool ,
446467 blocksId : PropTypes . string ,
447468 canChangeLanguage : PropTypes . bool ,
469+ canChangeColorMode : PropTypes . bool ,
448470 canChangeTheme : PropTypes . bool ,
449471 canCreateCopy : PropTypes . bool ,
450472 canCreateNew : PropTypes . bool ,
@@ -459,10 +481,12 @@ GUIComponent.propTypes = {
459481 costumeLibraryVisible : PropTypes . bool ,
460482 costumesTabVisible : PropTypes . bool ,
461483 debugModalVisible : PropTypes . bool ,
484+ hasActiveMembership : PropTypes . bool ,
462485 onDebugModalClose : PropTypes . func ,
463486 onTutorialSelect : PropTypes . func ,
464487 enableCommunity : PropTypes . bool ,
465488 isCreating : PropTypes . bool ,
489+ isFetchingUserData : PropTypes . bool ,
466490 isFullScreen : PropTypes . bool ,
467491 isPlayerOnly : PropTypes . bool ,
468492 isRtl : PropTypes . bool ,
@@ -499,13 +523,15 @@ GUIComponent.propTypes = {
499523 onUpdateProjectThumbnail : PropTypes . func ,
500524 platform : PropTypes . oneOf ( Object . keys ( PLATFORM ) ) ,
501525 renderLogin : PropTypes . func ,
526+ setTheme : PropTypes . func . isRequired ,
502527 showComingSoon : PropTypes . bool ,
503528 showNewFeatureCallouts : PropTypes . bool ,
504529 soundsTabVisible : PropTypes . bool ,
505530 stageSizeMode : PropTypes . oneOf ( Object . keys ( STAGE_SIZE_MODES ) ) ,
506531 setPlatform : PropTypes . func ,
507532 targetIsStage : PropTypes . bool ,
508533 telemetryModalVisible : PropTypes . bool ,
534+ colorMode : PropTypes . string ,
509535 theme : PropTypes . string ,
510536 tipsLibraryVisible : PropTypes . bool ,
511537 useExternalPeripheralList : PropTypes . bool , // true for CDM, false for normal Scratch Link
@@ -520,7 +546,9 @@ GUIComponent.defaultProps = {
520546 backpackVisible : false ,
521547 basePath : './' ,
522548 blocksId : 'original' ,
549+ // TODO: Currently all of those are always true. Do we actually need them?
523550 canChangeLanguage : true ,
551+ canChangeColorMode : true ,
524552 canChangeTheme : true ,
525553 canCreateNew : false ,
526554 canEditTitle : false ,
@@ -546,11 +574,13 @@ const mapStateToProps = state => ({
546574 // This is the button's mode, as opposed to the actual current state
547575 blocksId : state . scratchGui . timeTravel . year . toString ( ) ,
548576 stageSizeMode : state . scratchGui . stageSize . stageSize ,
549- theme : state . scratchGui . theme . theme
577+ colorMode : state . scratchGui . settings . colorMode ,
578+ theme : state . scratchGui . settings . theme
550579} ) ;
551580
552581const mapDispatchToProps = dispatch => ( {
553- setPlatform : platform => dispatch ( setPlatform ( platform ) )
582+ setPlatform : platform => dispatch ( setPlatform ( platform ) ) ,
583+ setTheme : theme => dispatch ( setTheme ( theme ) )
554584} ) ;
555585
556586export default connect ( mapStateToProps ,
0 commit comments