Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a99b5fcbf9 | ||
|
|
a08bb42658 | ||
|
|
3e5f7e917a | ||
|
|
3014e56e24 | ||
|
|
a8cd6f9c69 | ||
|
|
c04acb513a | ||
|
|
8ce4322051 | ||
|
|
f0637a40c5 | ||
|
|
a6cd49d400 |
No files matched your search
Generated
+71
-432
File diff suppressed because it is too large.
Load diff
+2
-2
@@ -108,10 +108,10 @@
|
||||
"redux-throttle": "0.1.1",
|
||||
"rimraf": "^2.6.1",
|
||||
"scratch-audio": "0.1.0-prerelease.20190925183642",
|
||||
"scratch-blocks": "0.1.0-prerelease.1584453125",
|
||||
"scratch-blocks": "0.1.0-prerelease.1585185354",
|
||||
"scratch-l10n": "3.7.20200317213230",
|
||||
"scratch-paint": "0.2.0-prerelease.20200213174123",
|
||||
"scratch-render": "0.1.0-prerelease.20200228152431",
|
||||
"scratch-render": "0.1.0-prerelease.20200324022200",
|
||||
"scratch-storage": "1.3.2",
|
||||
"scratch-svg-renderer": "0.2.0-prerelease.20200205003400",
|
||||
"scratch-vm": "0.2.0-prerelease.20200319175700",
|
||||
|
||||
@@ -18,6 +18,7 @@ import StageWrapper from '../../containers/stage-wrapper.jsx';
|
||||
import Loader from '../loader/loader.jsx';
|
||||
import Box from '../box/box.jsx';
|
||||
import MenuBar from '../menu-bar/menu-bar.jsx';
|
||||
import MysteryMode from '../mystery-mode/mystery-mode.jsx';
|
||||
import CostumeLibrary from '../../containers/costume-library.jsx';
|
||||
import BackdropLibrary from '../../containers/backdrop-library.jsx';
|
||||
import Watermark from '../../containers/watermark.jsx';
|
||||
@@ -156,6 +157,7 @@ const GUIComponent = props => {
|
||||
dir={isRtl ? 'rtl' : 'ltr'}
|
||||
{...componentProps}
|
||||
>
|
||||
<MysteryMode />
|
||||
{telemetryModalVisible ? (
|
||||
<TelemetryModal
|
||||
onCancel={onTelemetryModalCancel}
|
||||
|
||||
@@ -32,6 +32,7 @@ import MenuBarHOC from '../../containers/menu-bar-hoc.jsx';
|
||||
|
||||
import {openTipsLibrary} from '../../reducers/modals';
|
||||
import {setPlayer} from '../../reducers/mode';
|
||||
import {toggleMysteryMode} from '../../reducers/mystery-mode';
|
||||
import {
|
||||
autoUpdateProject,
|
||||
getIsUpdating,
|
||||
@@ -469,6 +470,21 @@ class MenuBar extends React.Component {
|
||||
)}
|
||||
</MenuItem>
|
||||
)}</TurboMode>
|
||||
<MenuItem onClick={this.props.onClickToggleMysteryMode}>
|
||||
{this.props.mysteryMode ? (
|
||||
<FormattedMessage
|
||||
defaultMessage="Turn off Mystery Mode"
|
||||
description="Menu bar item for turning off dark mode"
|
||||
id="gui.menuBar.mysteryModeOff"
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
defaultMessage="Turn on Mystery Mode"
|
||||
description="Menu bar item for turning on dark mode"
|
||||
id="gui.menuBar.mysteryModeOn"
|
||||
/>
|
||||
)}
|
||||
</MenuItem>
|
||||
</MenuSection>
|
||||
</MenuBarMenu>
|
||||
</div>
|
||||
@@ -722,6 +738,7 @@ MenuBar.propTypes = {
|
||||
locale: PropTypes.string.isRequired,
|
||||
loginMenuOpen: PropTypes.bool,
|
||||
logo: PropTypes.string,
|
||||
mysteryMode: PropTypes.bool,
|
||||
onClickAccount: PropTypes.func,
|
||||
onClickEdit: PropTypes.func,
|
||||
onClickFile: PropTypes.func,
|
||||
@@ -732,6 +749,7 @@ MenuBar.propTypes = {
|
||||
onClickRemix: PropTypes.func,
|
||||
onClickSave: PropTypes.func,
|
||||
onClickSaveAsCopy: PropTypes.func,
|
||||
onClickToggleMysteryMode: PropTypes.func,
|
||||
onLogOut: PropTypes.func,
|
||||
onOpenRegistration: PropTypes.func,
|
||||
onOpenTipLibrary: PropTypes.func,
|
||||
@@ -772,6 +790,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
languageMenuOpen: languageMenuOpen(state),
|
||||
locale: state.locales.locale,
|
||||
loginMenuOpen: loginMenuOpen(state),
|
||||
mysteryMode: state.scratchGui.mysteryMode,
|
||||
projectTitle: state.scratchGui.projectTitle,
|
||||
sessionExists: state.session && typeof state.session.session !== 'undefined',
|
||||
username: user ? user.username : null,
|
||||
@@ -798,6 +817,7 @@ const mapDispatchToProps = dispatch => ({
|
||||
onClickRemix: () => dispatch(remixProject()),
|
||||
onClickSave: () => dispatch(manualUpdateProject()),
|
||||
onClickSaveAsCopy: () => dispatch(saveProjectAsCopy()),
|
||||
onClickToggleMysteryMode: () => dispatch(toggleMysteryMode()),
|
||||
onSeeCommunity: () => dispatch(setPlayer(true))
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
.mystery-mode {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.9;
|
||||
background: transparent url('./mystery.png') center center;
|
||||
z-index: 50;
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import bindAll from 'lodash.bindall';
|
||||
import styles from './mystery-mode.css';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
class MysteryMode extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
bindAll(this, [
|
||||
'handleMouseMove'
|
||||
]);
|
||||
this.state = {
|
||||
x: window.innerWidth / 2,
|
||||
y: window.innerHeight / 2
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
document.addEventListener('mousemove', this.handleMouseMove);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
document.removeEventListener('mousemove', this.handleMouseMove);
|
||||
}
|
||||
|
||||
handleMouseMove (event) {
|
||||
this.setState({x: event.clientX, y: event.clientY});
|
||||
}
|
||||
|
||||
render () {
|
||||
if (!this.props.show) return null;
|
||||
return (
|
||||
<div
|
||||
className={styles.mysteryMode}
|
||||
style={{
|
||||
backgroundPosition: `${this.state.x + 2000}px ${this.state.y + 2000}px`
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MysteryMode.propTypes = {
|
||||
show: PropTypes.bool
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
// This is the button's mode, as opposed to the actual current state
|
||||
show: state.scratchGui.mysteryMode
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps
|
||||
)(MysteryMode);
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
@@ -0,0 +1,60 @@
|
||||
import bindAll from 'lodash.bindall';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
/**
|
||||
* Turbo Mode component passes toggleTurboMode function to its child.
|
||||
* It also includes `turboMode` in the props passed to the children.
|
||||
* It expects this child to be a function with the signature
|
||||
* function (toggleTurboMode, {turboMode, ...props}) {}
|
||||
* The component can then be used to attach turbo mode setting functionality
|
||||
* to any other component:
|
||||
*
|
||||
* <TurboMode>{(toggleTurboMode, props) => (
|
||||
* <MyCoolComponent
|
||||
* turboEnabled={props.turboMode}
|
||||
* onClick={toggleTurboMode}
|
||||
* {...props}
|
||||
* />
|
||||
* )}</TurboMode>
|
||||
*/
|
||||
class TurboMode extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
bindAll(this, [
|
||||
'toggleTurboMode'
|
||||
]);
|
||||
}
|
||||
toggleTurboMode () {
|
||||
this.props.vm.setTurboMode(!this.props.turboMode);
|
||||
}
|
||||
render () {
|
||||
const {
|
||||
/* eslint-disable no-unused-vars */
|
||||
children,
|
||||
vm,
|
||||
/* eslint-enable no-unused-vars */
|
||||
...props
|
||||
} = this.props;
|
||||
return this.props.children(this.toggleTurboMode, props);
|
||||
}
|
||||
}
|
||||
|
||||
TurboMode.propTypes = {
|
||||
children: PropTypes.func,
|
||||
turboMode: PropTypes.bool,
|
||||
vm: PropTypes.shape({
|
||||
setTurboMode: PropTypes.func
|
||||
})
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
vm: state.scratchGui.vm,
|
||||
turboMode: state.scratchGui.vmStatus.turbo
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
() => ({}) // omit dispatch prop
|
||||
)(TurboMode);
|
||||
@@ -77,6 +77,13 @@ class Stage extends React.Component {
|
||||
this.attachMouseEvents(this.canvas);
|
||||
this.updateRect();
|
||||
this.props.vm.runtime.addListener('QUESTION', this.questionListener);
|
||||
|
||||
// The GUI component seems to be recreated when entering/exiting editor mode.
|
||||
// If we only update mystery mode in componentDidUpdate, it won't
|
||||
// update when switching between editor and player mode.
|
||||
if (this.props.mysteryMode !== this.renderer._mystery.modeActive) {
|
||||
this.renderer.setMysteryMode(this.props.mysteryMode);
|
||||
}
|
||||
}
|
||||
shouldComponentUpdate (nextProps, nextState) {
|
||||
return this.props.stageSize !== nextProps.stageSize ||
|
||||
@@ -85,7 +92,8 @@ class Stage extends React.Component {
|
||||
this.props.isFullScreen !== nextProps.isFullScreen ||
|
||||
this.state.question !== nextState.question ||
|
||||
this.props.micIndicator !== nextProps.micIndicator ||
|
||||
this.props.isStarted !== nextProps.isStarted;
|
||||
this.props.isStarted !== nextProps.isStarted ||
|
||||
this.props.mysteryMode !== nextProps.mysteryMode;
|
||||
}
|
||||
componentDidUpdate (prevProps) {
|
||||
if (this.props.isColorPicking && !prevProps.isColorPicking) {
|
||||
@@ -93,6 +101,9 @@ class Stage extends React.Component {
|
||||
} else if (!this.props.isColorPicking && prevProps.isColorPicking) {
|
||||
this.stopColorPickingLoop();
|
||||
}
|
||||
if (this.props.mysteryMode !== prevProps.mysteryMode) {
|
||||
this.renderer.setMysteryMode(this.props.mysteryMode);
|
||||
}
|
||||
this.updateRect();
|
||||
this.renderer.resize(this.rect.width, this.rect.height);
|
||||
}
|
||||
@@ -429,7 +440,8 @@ Stage.propTypes = {
|
||||
onDeactivateColorPicker: PropTypes.func,
|
||||
stageSize: PropTypes.oneOf(Object.keys(STAGE_DISPLAY_SIZES)).isRequired,
|
||||
useEditorDragStyle: PropTypes.bool,
|
||||
vm: PropTypes.instanceOf(VM).isRequired
|
||||
vm: PropTypes.instanceOf(VM).isRequired,
|
||||
mysteryMode: PropTypes.bool
|
||||
};
|
||||
|
||||
Stage.defaultProps = {
|
||||
@@ -442,7 +454,9 @@ const mapStateToProps = state => ({
|
||||
isStarted: state.scratchGui.vmStatus.started,
|
||||
micIndicator: state.scratchGui.micIndicator,
|
||||
// Do not use editor drag style in fullscreen or player mode.
|
||||
useEditorDragStyle: !(state.scratchGui.mode.isFullScreen || state.scratchGui.mode.isPlayerOnly)
|
||||
useEditorDragStyle: !(state.scratchGui.mode.isFullScreen || state.scratchGui.mode.isPlayerOnly),
|
||||
mysteryMode: state.scratchGui.mysteryMode && !(
|
||||
state.scratchGui.mode.isFullScreen || state.scratchGui.mode.isPlayerOnly)
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
@@ -51,6 +51,9 @@ import libraryCodeCartoon from './thumbnails/code-a-cartoon.jpg';
|
||||
// Talking Tales
|
||||
import libraryTalking from './thumbnails/talking.png';
|
||||
|
||||
// Sprite Mystery
|
||||
import librarySpriteMystery from './thumbnails/sprite-mystery.png';
|
||||
|
||||
// Videos
|
||||
import recordASound from './thumbnails/record-a-sound.jpg';
|
||||
import glideAroundThumb from './thumbnails/glide-around.jpg';
|
||||
@@ -497,6 +500,21 @@ export default {
|
||||
urlId: 'animations-that-talk'
|
||||
},
|
||||
|
||||
'sprite-mystery': {
|
||||
name: 'How to Find a Sprite',
|
||||
img: librarySpriteMystery,
|
||||
steps: [{
|
||||
video: 'sprite-mystery'
|
||||
}, {
|
||||
deckIds: [
|
||||
'intro-move-sayhello',
|
||||
'add-sprite'
|
||||
]
|
||||
}
|
||||
],
|
||||
urlId: 'sprite-mystery'
|
||||
},
|
||||
|
||||
'talking': {
|
||||
name: (
|
||||
<FormattedMessage
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
@@ -129,6 +129,9 @@ const videos = {
|
||||
},
|
||||
'talking': {
|
||||
en: 'j0208mq4qi'
|
||||
},
|
||||
'sprite-mystery': {
|
||||
en: 's69h0y6cs4'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import modalReducer, {modalsInitialState} from './modals';
|
||||
import modeReducer, {modeInitialState} from './mode';
|
||||
import monitorReducer, {monitorsInitialState} from './monitors';
|
||||
import monitorLayoutReducer, {monitorLayoutInitialState} from './monitor-layout';
|
||||
import mysteryModeReducer, {mysteryModeInitialState} from './mystery-mode';
|
||||
import projectChangedReducer, {projectChangedInitialState} from './project-changed';
|
||||
import projectStateReducer, {projectStateInitialState} from './project-state';
|
||||
import projectTitleReducer, {projectTitleInitialState} from './project-title';
|
||||
@@ -48,6 +49,7 @@ const guiInitialState = {
|
||||
modals: modalsInitialState,
|
||||
monitors: monitorsInitialState,
|
||||
monitorLayout: monitorLayoutInitialState,
|
||||
mysteryMode: mysteryModeInitialState,
|
||||
projectChanged: projectChangedInitialState,
|
||||
projectState: projectStateInitialState,
|
||||
projectTitle: projectTitleInitialState,
|
||||
@@ -146,6 +148,7 @@ const guiReducer = combineReducers({
|
||||
modals: modalReducer,
|
||||
monitors: monitorReducer,
|
||||
monitorLayout: monitorLayoutReducer,
|
||||
mysteryMode: mysteryModeReducer,
|
||||
projectChanged: projectChangedReducer,
|
||||
projectState: projectStateReducer,
|
||||
projectTitle: projectTitleReducer,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
const TOGGLE_MYSTERY_MODE = 'scratch-gui/mystery-mode/TOGGLE_MYSTERY_MODE';
|
||||
|
||||
const initialState = false;
|
||||
|
||||
const reducer = function (state, action) {
|
||||
if (typeof state === 'undefined') state = initialState;
|
||||
|
||||
switch (action.type) {
|
||||
case TOGGLE_MYSTERY_MODE:
|
||||
return !state;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const toggleMysteryMode = function () {
|
||||
return {
|
||||
type: TOGGLE_MYSTERY_MODE
|
||||
};
|
||||
};
|
||||
|
||||
export {
|
||||
reducer as default,
|
||||
initialState as mysteryModeInitialState,
|
||||
toggleMysteryMode
|
||||
};
|
||||
Reference in new issue
Block a user