mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-27 09:35:56 -05:00
Merge pull request #7165 from aoneill01/feature/disable-cloud-vars-when-video-sensing
feat: Disable cloud variables when camera is active
This commit is contained in:
commit
8a5e0637c1
6 changed files with 366 additions and 17 deletions
|
@ -20,7 +20,8 @@ module.exports = {
|
|||
const stage = project.targets[0];
|
||||
return Object.values(stage.variables)
|
||||
.some(variable => variable.length === 3); // 3 entries if cloud var
|
||||
}
|
||||
},
|
||||
videoSensing: project => (project.extensions || []).includes('videoSensing')
|
||||
},
|
||||
2: {
|
||||
extensions: () => [], // Showing extension chip not implemented for scratch2 projects
|
||||
|
@ -30,6 +31,11 @@ module.exports = {
|
|||
// Block traversing is complicated in scratch2 projects...
|
||||
// This check should work even if you have sprites named getUserName, etc.
|
||||
JSON.stringify(project).indexOf('["getUserName"]') !== -1,
|
||||
cloudData: project => project.info.hasCloudData
|
||||
cloudData: project => project.info.hasCloudData,
|
||||
videoSensing: project => {
|
||||
const stringifiedProject = JSON.stringify(project);
|
||||
return ['senseVideoMotion', 'setVideoState', 'setVideoTransparency', 'whenSensorGreaterThan']
|
||||
.some(opcode => stringifiedProject.includes(`["${opcode}"`));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -47,5 +47,6 @@
|
|||
"project.cloudDataLink": "See Data",
|
||||
"project.usernameBlockAlert": "This project can detect who is using it, through the \"username\" block. To hide your identity, sign out before using the project.",
|
||||
"project.inappropriateUpdate": "Hmm...the bad word detector thinks there is a problem with your text. Please change it and remember to be respectful.",
|
||||
"project.mutedAddToStudio": "You will be able to add to studios again {inDuration}."
|
||||
"project.mutedAddToStudio": "You will be able to add to studios again {inDuration}.",
|
||||
"project.cloudDataAndVideoAlert": "For privacy reasons, cloud variables have been disabled in this project because it contains video sensing blocks."
|
||||
}
|
||||
|
|
|
@ -125,6 +125,7 @@ const PreviewPresentation = ({
|
|||
originalInfo,
|
||||
parentInfo,
|
||||
showCloudDataAlert,
|
||||
showCloudDataAndVideoAlert,
|
||||
showUsernameBlockAlert,
|
||||
projectHost,
|
||||
projectId,
|
||||
|
@ -335,16 +336,23 @@ const PreviewPresentation = ({
|
|||
{fullscreen: isFullScreen}
|
||||
)}
|
||||
>
|
||||
{showCloudDataAlert && (
|
||||
<FlexRow className="project-info-alert">
|
||||
<FormattedMessage id="project.cloudDataAlert" />
|
||||
</FlexRow>
|
||||
)}
|
||||
{showUsernameBlockAlert && (
|
||||
<FlexRow className="project-info-alert">
|
||||
<FormattedMessage id="project.usernameBlockAlert" />
|
||||
</FlexRow>
|
||||
)}
|
||||
<div className="project-info-alerts">
|
||||
{showCloudDataAlert && (
|
||||
<FlexRow className="project-info-alert">
|
||||
<FormattedMessage id="project.cloudDataAlert" />
|
||||
</FlexRow>
|
||||
)}
|
||||
{showCloudDataAndVideoAlert && (
|
||||
<FlexRow className="project-info-alert">
|
||||
<FormattedMessage id="project.cloudDataAndVideoAlert" />
|
||||
</FlexRow>
|
||||
)}
|
||||
{showUsernameBlockAlert && (
|
||||
<FlexRow className="project-info-alert">
|
||||
<FormattedMessage id="project.usernameBlockAlert" />
|
||||
</FlexRow>
|
||||
)}
|
||||
</div>
|
||||
<IntlGUI
|
||||
isPlayerOnly
|
||||
assetHost={assetHost}
|
||||
|
@ -785,6 +793,7 @@ PreviewPresentation.propTypes = {
|
|||
reportOpen: PropTypes.bool,
|
||||
showAdminPanel: PropTypes.bool,
|
||||
showCloudDataAlert: PropTypes.bool,
|
||||
showCloudDataAndVideoAlert: PropTypes.bool,
|
||||
showEmailConfirmationModal: PropTypes.bool,
|
||||
showEmailConfirmationBanner: PropTypes.bool,
|
||||
showModInfo: PropTypes.bool,
|
||||
|
|
|
@ -367,10 +367,17 @@ $stage-width: 480px;
|
|||
z-index: 1;
|
||||
|
||||
$alert-bg: rgba(255, 255, 255, .85);
|
||||
.project-info-alert {
|
||||
|
||||
.project-info-alerts {
|
||||
position: absolute;
|
||||
z-index: 8; // Below navbar
|
||||
margin: 60px 15px;
|
||||
margin: 60px 15px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.project-info-alert {
|
||||
border-radius: .25rem;
|
||||
background: $alert-bg;
|
||||
padding: .75rem;
|
||||
|
|
|
@ -379,9 +379,10 @@ class Preview extends React.Component {
|
|||
}
|
||||
|
||||
if (showAlerts) {
|
||||
// Check for username block only if user is logged in
|
||||
// Check for username and video blocks only if user is logged in
|
||||
if (this.props.isLoggedIn) {
|
||||
newState.showUsernameBlockAlert = helpers.usernameBlock(projectData[0]);
|
||||
newState.showCloudDataAndVideoAlert = hasCloudData && helpers.videoSensing(projectData[0]);
|
||||
} else { // Check for cloud vars only if user is logged out
|
||||
newState.showCloudDataAlert = hasCloudData;
|
||||
}
|
||||
|
@ -492,6 +493,7 @@ class Preview extends React.Component {
|
|||
this.setState({
|
||||
showUsernameBlockAlert: false,
|
||||
showCloudDataAlert: false,
|
||||
showCloudDataAndVideoAlert: false,
|
||||
greenFlagRecorded: true
|
||||
});
|
||||
}
|
||||
|
@ -607,7 +609,8 @@ class Preview extends React.Component {
|
|||
handleSeeInside () {
|
||||
this.setState({ // Remove any project alerts so they don't show up later
|
||||
showUsernameBlockAlert: false,
|
||||
showCloudDataAlert: false
|
||||
showCloudDataAlert: false,
|
||||
showCloudDataAndVideoAlert: false
|
||||
});
|
||||
this.props.setPlayer(false);
|
||||
if (this.state.justRemixed || this.state.justShared) {
|
||||
|
@ -794,6 +797,7 @@ class Preview extends React.Component {
|
|||
reportOpen={this.state.reportOpen}
|
||||
showAdminPanel={this.props.isAdmin}
|
||||
showCloudDataAlert={this.state.showCloudDataAlert}
|
||||
showCloudDataAndVideoAlert={this.state.showCloudDataAndVideoAlert}
|
||||
showModInfo={this.props.isAdmin}
|
||||
showEmailConfirmationModal={this.state.showEmailConfirmationModal}
|
||||
showEmailConfirmationBanner={this.props.showEmailConfirmationBanner}
|
||||
|
|
322
test/unit/lib/project-info.test.js
Normal file
322
test/unit/lib/project-info.test.js
Normal file
|
@ -0,0 +1,322 @@
|
|||
/* eslint-disable no-use-before-define */
|
||||
const projectInfo = require('../../../src/lib/project-info');
|
||||
|
||||
describe('unit test lib/project-info.js', () => {
|
||||
test('videoSensing returns true for a version 3 project with video', () => {
|
||||
const result = projectInfo[videoVersion3.projectVersion].videoSensing(videoVersion3);
|
||||
expect(result).toEqual(true);
|
||||
});
|
||||
|
||||
test('videoSensing returns false for a version 3 project with no video', () => {
|
||||
const result = projectInfo[noVideoVersion3.projectVersion].videoSensing(noVideoVersion3);
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
|
||||
test('videoSensing returns true for a version 2 project with video', () => {
|
||||
const result = projectInfo[videoVersion2.projectVersion].videoSensing(videoVersion2);
|
||||
expect(result).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
const videoVersion3 = {
|
||||
targets: [
|
||||
{
|
||||
isStage: true,
|
||||
name: 'Stage',
|
||||
variables: {
|
||||
'`jEk@4|i[#Fk?(8x)AV.-my variable': [
|
||||
'my variable',
|
||||
'0'
|
||||
]
|
||||
},
|
||||
lists: {},
|
||||
broadcasts: {},
|
||||
blocks: {
|
||||
'FJz[,QI8`P^5;FEjdBhc': {
|
||||
opcode: 'event_whenflagclicked',
|
||||
next: 'f8q%j#X8sU#C+E1z|-oF',
|
||||
parent: null,
|
||||
inputs: {},
|
||||
fields: {},
|
||||
shadow: false,
|
||||
topLevel: true,
|
||||
x: 255,
|
||||
y: 171
|
||||
},
|
||||
'f8q%j#X8sU#C+E1z|-oF': {
|
||||
opcode: 'videoSensing_videoToggle',
|
||||
next: null,
|
||||
parent: 'FJz[,QI8`P^5;FEjdBhc',
|
||||
inputs: {
|
||||
VIDEO_STATE: [
|
||||
1,
|
||||
'a2$KXEUlr`=IW!MX8(M7'
|
||||
]
|
||||
},
|
||||
fields: {},
|
||||
shadow: false,
|
||||
topLevel: false
|
||||
},
|
||||
'a2$KXEUlr`=IW!MX8(M7': {
|
||||
opcode: 'videoSensing_menu_VIDEO_STATE',
|
||||
next: null,
|
||||
parent: 'f8q%j#X8sU#C+E1z|-oF',
|
||||
inputs: {},
|
||||
fields: {
|
||||
VIDEO_STATE: [
|
||||
'on',
|
||||
null
|
||||
]
|
||||
},
|
||||
shadow: true,
|
||||
topLevel: false
|
||||
}
|
||||
},
|
||||
comments: {},
|
||||
currentCostume: 0,
|
||||
costumes: [
|
||||
{
|
||||
name: 'backdrop1',
|
||||
dataFormat: 'svg',
|
||||
assetId: 'cd21514d0531fdffb22204e0ec5ed84a',
|
||||
md5ext: 'cd21514d0531fdffb22204e0ec5ed84a.svg',
|
||||
rotationCenterX: 240,
|
||||
rotationCenterY: 180
|
||||
}
|
||||
],
|
||||
sounds: [
|
||||
{
|
||||
name: 'pop',
|
||||
assetId: '83a9787d4cb6f3b7632b4ddfebf74367',
|
||||
dataFormat: 'wav',
|
||||
format: '',
|
||||
rate: 48000,
|
||||
sampleCount: 1123,
|
||||
md5ext: '83a9787d4cb6f3b7632b4ddfebf74367.wav'
|
||||
}
|
||||
],
|
||||
volume: 100,
|
||||
layerOrder: 0,
|
||||
tempo: 60,
|
||||
videoTransparency: 50,
|
||||
videoState: 'on',
|
||||
textToSpeechLanguage: null
|
||||
}
|
||||
],
|
||||
monitors: [
|
||||
{
|
||||
id: '`jEk@4|i[#Fk?(8x)AV.-my variable',
|
||||
mode: 'default',
|
||||
opcode: 'data_variable',
|
||||
params: {
|
||||
VARIABLE: 'my variable'
|
||||
},
|
||||
spriteName: null,
|
||||
value: '0',
|
||||
width: 0,
|
||||
height: 0,
|
||||
x: 7,
|
||||
y: 17,
|
||||
visible: false,
|
||||
sliderMin: 0,
|
||||
sliderMax: 100,
|
||||
isDiscrete: true
|
||||
}
|
||||
],
|
||||
extensions: [
|
||||
'videoSensing'
|
||||
],
|
||||
meta: {
|
||||
semver: '3.0.0',
|
||||
vm: '1.2.48',
|
||||
// eslint-disable-next-line max-len
|
||||
agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'
|
||||
},
|
||||
projectVersion: 3
|
||||
};
|
||||
|
||||
const noVideoVersion3 = {
|
||||
targets: [
|
||||
{
|
||||
isStage: true,
|
||||
name: 'Stage',
|
||||
variables: {
|
||||
'`jEk@4|i[#Fk?(8x)AV.-my variable': [
|
||||
'my variable',
|
||||
'0'
|
||||
]
|
||||
},
|
||||
lists: {},
|
||||
broadcasts: {},
|
||||
blocks: {
|
||||
'FJz[,QI8`P^5;FEjdBhc': {
|
||||
opcode: 'event_whenflagclicked',
|
||||
next: '`CA90wtKfX0xa.mK80[|',
|
||||
parent: null,
|
||||
inputs: {},
|
||||
fields: {},
|
||||
shadow: false,
|
||||
topLevel: true,
|
||||
x: 255,
|
||||
y: 171
|
||||
},
|
||||
'`CA90wtKfX0xa.mK80[|': {
|
||||
opcode: 'data_setvariableto',
|
||||
next: null,
|
||||
parent: 'FJz[,QI8`P^5;FEjdBhc',
|
||||
inputs: {
|
||||
VALUE: [
|
||||
1,
|
||||
[
|
||||
10,
|
||||
'0'
|
||||
]
|
||||
]
|
||||
},
|
||||
fields: {
|
||||
VARIABLE: [
|
||||
'my variable',
|
||||
'`jEk@4|i[#Fk?(8x)AV.-my variable'
|
||||
]
|
||||
},
|
||||
shadow: false,
|
||||
topLevel: false
|
||||
}
|
||||
},
|
||||
comments: {},
|
||||
currentCostume: 0,
|
||||
costumes: [
|
||||
{
|
||||
name: 'backdrop1',
|
||||
dataFormat: 'svg',
|
||||
assetId: 'cd21514d0531fdffb22204e0ec5ed84a',
|
||||
md5ext: 'cd21514d0531fdffb22204e0ec5ed84a.svg',
|
||||
rotationCenterX: 240,
|
||||
rotationCenterY: 180
|
||||
}
|
||||
],
|
||||
sounds: [
|
||||
{
|
||||
name: 'pop',
|
||||
assetId: '83a9787d4cb6f3b7632b4ddfebf74367',
|
||||
dataFormat: 'wav',
|
||||
format: '',
|
||||
rate: 48000,
|
||||
sampleCount: 1123,
|
||||
md5ext: '83a9787d4cb6f3b7632b4ddfebf74367.wav'
|
||||
}
|
||||
],
|
||||
volume: 100,
|
||||
layerOrder: 0,
|
||||
tempo: 60,
|
||||
videoTransparency: 50,
|
||||
videoState: 'on',
|
||||
textToSpeechLanguage: null
|
||||
}
|
||||
],
|
||||
monitors: [
|
||||
{
|
||||
id: '`jEk@4|i[#Fk?(8x)AV.-my variable',
|
||||
mode: 'default',
|
||||
opcode: 'data_variable',
|
||||
params: {
|
||||
VARIABLE: 'my variable'
|
||||
},
|
||||
spriteName: null,
|
||||
value: '0',
|
||||
width: 0,
|
||||
height: 0,
|
||||
x: 7,
|
||||
y: 17,
|
||||
visible: false,
|
||||
sliderMin: 0,
|
||||
sliderMax: 100,
|
||||
isDiscrete: true
|
||||
}
|
||||
],
|
||||
extensions: [],
|
||||
meta: {
|
||||
semver: '3.0.0',
|
||||
vm: '1.2.48',
|
||||
// eslint-disable-next-line max-len
|
||||
agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'
|
||||
},
|
||||
projectVersion: 3
|
||||
};
|
||||
|
||||
const videoVersion2 = {
|
||||
objName: 'Stage',
|
||||
sounds: [{
|
||||
soundName: 'pop',
|
||||
soundID: 1,
|
||||
md5: '83a9787d4cb6f3b7632b4ddfebf74367.wav',
|
||||
sampleCount: 258,
|
||||
rate: 11025,
|
||||
format: ''
|
||||
}],
|
||||
costumes: [{
|
||||
costumeName: 'backdrop1',
|
||||
baseLayerID: 3,
|
||||
baseLayerMD5: '739b5e2a2435f6e1ec2993791b423146.png',
|
||||
bitmapResolution: 1,
|
||||
rotationCenterX: 240,
|
||||
rotationCenterY: 180
|
||||
}],
|
||||
currentCostumeIndex: 0,
|
||||
penLayerMD5: '5c81a336fab8be57adc039a8a2b33ca9.png',
|
||||
penLayerID: 0,
|
||||
tempoBPM: 60,
|
||||
videoAlpha: 0.5,
|
||||
children: [{
|
||||
objName: 'Sprite1',
|
||||
scripts: [[62,
|
||||
85,
|
||||
[['whenGreenFlag'], ['doForever', [['say:', ['senseVideoMotion', 'motion', 'this sprite']]]]]],
|
||||
[70, 216, [['setVideoState', 'on']]],
|
||||
[66, 281, [['setVideoTransparency', 50]]]],
|
||||
sounds: [{
|
||||
soundName: 'meow',
|
||||
soundID: 0,
|
||||
md5: '83c36d806dc92327b9e7049a565c6bff.wav',
|
||||
sampleCount: 18688,
|
||||
rate: 22050,
|
||||
format: ''
|
||||
}],
|
||||
costumes: [{
|
||||
costumeName: 'costume1',
|
||||
baseLayerID: 1,
|
||||
baseLayerMD5: 'f9a1c175dbe2e5dee472858dd30d16bb.svg',
|
||||
bitmapResolution: 1,
|
||||
rotationCenterX: 47,
|
||||
rotationCenterY: 55
|
||||
},
|
||||
{
|
||||
costumeName: 'costume2',
|
||||
baseLayerID: 2,
|
||||
baseLayerMD5: '6e8bd9ae68fdb02b7e1e3df656a75635.svg',
|
||||
bitmapResolution: 1,
|
||||
rotationCenterX: 47,
|
||||
rotationCenterY: 55
|
||||
}],
|
||||
currentCostumeIndex: 0,
|
||||
scratchX: 0,
|
||||
scratchY: 0,
|
||||
scale: 1,
|
||||
direction: 90,
|
||||
rotationStyle: 'normal',
|
||||
isDraggable: false,
|
||||
indexInLibrary: 1,
|
||||
visible: true,
|
||||
spriteInfo: {
|
||||
}
|
||||
}],
|
||||
info: {
|
||||
userAgent: 'Scratch 2.0 Offline Editor',
|
||||
flashVersion: 'WIN 33,1,1,743',
|
||||
spriteCount: 1,
|
||||
videoOn: false,
|
||||
scriptCount: 1,
|
||||
swfVersion: 'v461'
|
||||
},
|
||||
projectVersion: 2
|
||||
};
|
Loading…
Reference in a new issue