Compare commits

..
Author SHA1 Message Date
DD Liu 731f3bbf5d Merge pull request #5519 from LLK/greenkeeper/scratch-vm-0.2.0-prerelease.20200317155559
Update scratch-vm to the latest version 🚀
2020-03-17 16:08:27 -04:00
greenkeeper[bot] 715e46fe1c chore(package): update lockfile package-lock.json 2020-03-17 16:18:25 +00:00
greenkeeper[bot] cc68eef196 chore(package): update scratch-vm to version 0.2.0-prerelease.20200317155559 2020-03-17 16:18:22 +00:00
picklesrus d20b68c939 Merge pull request #5504 from picklesrus/update-scratch-blocks
Updates scratch-blocks manually
2020-03-11 15:50:55 -04:00
picklesrus 6af3fda54a Updates scratch-blocks manually because https://github.com/LLK/scratch-gui/pull/5501 had package-lock conflicts with the l10n PR 2020-03-11 15:46:32 -04:00
picklesrus 43191504ff Merge pull request #5503 from LLK/greenkeeper/scratch-l10n-3.7.20200310213125
Update scratch-l10n to the latest version 🚀
2020-03-11 15:31:09 -04:00
greenkeeper[bot] 3008feb1de chore(package): update lockfile package-lock.json 2020-03-10 21:33:39 +00:00
greenkeeper[bot] 78c2aea407 chore(package): update scratch-l10n to version 3.7.20200310213125 2020-03-10 21:33:36 +00:00
DD Liu b41b1c11bb Merge pull request #5502 from LLK/greenkeeper/scratch-vm-0.2.0-prerelease.20200310202129
Update scratch-vm to the latest version 🚀
2020-03-10 16:59:00 -04:00
greenkeeper[bot] 8e82c2d1e3 chore(package): update lockfile package-lock.json 2020-03-10 20:29:16 +00:00
greenkeeper[bot] a75e2b0ecf chore(package): update scratch-vm to version 0.2.0-prerelease.20200310202129 2020-03-10 20:29:12 +00:00
Benjamin Wheeler a731370478 Merge pull request #5491 from benjiwheeler/unflakify-blocks-tests
unflakify four blocks integration tests
2020-03-05 22:26:24 -05:00
Ray Schamp f3ced9c9ea Merge pull request #5492 from rschamp/bump-dependencies
Bump scratch-blocks and scratch-l10n versions for release
2020-03-04 16:54:56 -05:00
rschamp dee0320164 Bump scratch-blocks and scratch-l10n 2020-03-04 16:53:51 -05:00
Ray Schamp 942b8d6e6a Merge pull request #5487 from LLK/greenkeeper/initial
Update dependencies to enable Greenkeeper 🌴
2020-03-04 16:48:24 -05:00
rschamp c296732753 Revert "chore(package): update lockfile package-lock.json"
This reverts commit 63bdc80388.
2020-03-04 16:44:20 -05:00
rschamp 212ffb42d3 Revert "chore(package): update dependencies"
This reverts commit a27ddaf4ad.
2020-03-04 16:44:20 -05:00
Ben Wheeler af0088df88 add findByXpath to wait for updated or new items to appear 2020-03-02 13:01:45 -05:00
greenkeeper[bot] 63bdc80388 chore(package): update lockfile package-lock.json 2020-02-28 19:25:19 +00:00
greenkeeper[bot] a27ddaf4ad chore(package): update dependencies 2020-02-28 19:25:15 +00:00
DD Liu 5ee641e70f Merge pull request #5484 from fsih/updateRender
Update render to roll back pen line drawing change
2020-02-28 13:01:11 -05:00
DD Liu e9d16dcd2a Update render to roll back pen line drawing change 2020-02-28 13:00:20 -05:00
DD Liu d156a3d995 Merge pull request #5479 from LLK/updateVm022720
Update vm
2020-02-27 16:58:35 -05:00
DD Liu 1019726bcf Update vm 2020-02-27 16:27:21 -05:00
DD Liu 3fbb7fe8d4 Merge pull request #5478 from fsih/updateRender
Update render
2020-02-27 16:06:06 -05:00
DD Liu 124a6496f5 Update render 2020-02-27 16:05:10 -05:00
chrisgarrity 53bdab3425 Merge pull request #5476 from chrisgarrity/l10n-update-02-25
Update to latest l10n for translations
2020-02-26 16:06:43 -05:00
Chris Garrity 058fd000fa Update to latest l10n for translations 2020-02-26 15:53:25 -05:00
Eric Rosenbaum dc727f1b57 Merge pull request #5469 from ericrosenbaum/bugfix/revert-backdrops
Use 2.0 versions of some svg backdrops
2020-02-20 14:34:04 -05:00
Eric Rosenbaum bab503addb use 2.0 versions of some svg backdrops 2020-02-20 14:21:09 -05:00
Eric Rosenbaum 662726fa52 Merge pull request #5464 from LLK/greenkeeper/scratch-blocks-0.1.0-prerelease.1582033791
Update scratch-blocks to the latest version 🚀
2020-02-19 16:39:27 -05:00
Eric Rosenbaum a0b4aea8a1 Merge branch 'develop' into greenkeeper/scratch-blocks-0.1.0-prerelease.1582033791 2020-02-19 16:39:15 -05:00
Eric Rosenbaum b180dd4c0d Merge pull request #5465 from LLK/greenkeeper/scratch-l10n-3.7.20200218213016
Update scratch-l10n to the latest version 🚀
2020-02-19 16:10:09 -05:00
greenkeeper[bot] 02cdbf68cd chore(package): update lockfile package-lock.json 2020-02-18 22:28:15 +00:00
greenkeeper[bot] f1f1f54ec6 chore(package): update scratch-l10n to version 3.7.20200218213016 2020-02-18 22:28:10 +00:00
greenkeeper[bot] 256bb87858 chore(package): update lockfile package-lock.json 2020-02-18 13:52:38 +00:00
greenkeeper[bot] bdbf99f606 chore(package): update scratch-blocks to version 0.1.0-prerelease.1582033791 2020-02-18 13:52:34 +00:00
Eric Rosenbaum 8e3603aa8b Merge pull request #5395 from ericrosenbaum/feature/full-library-update
Asset library update
2020-02-14 14:02:42 -05:00
Eric Rosenbaum a5baf0cf5f Remove omega symbols from letter names 2020-02-13 15:50:00 -05:00
Ray Schamp 7912e4306c Merge pull request #5459 from LLK/ci-skip-gh-pages
Ignore commits on the gh-pages branch for CI
2020-02-13 15:33:52 -05:00
Ray Schamp 5fa8beb230 Ignore commits on the gh-pages branch for CI
Commits to gh-pages "fail" on CircleCI since there's no config on the branch. Skip these commits using a tag I can't write here because I do want CI to run on this commit :)
2020-02-13 13:14:34 -05:00
Karishma Chadha 9b4b47367b Merge pull request #5457 from LLK/greenkeeper/scratch-paint-0.2.0-prerelease.20200213174123
Update scratch-paint to the latest version 🚀
2020-02-13 12:55:41 -05:00
greenkeeper[bot] f69f4bfe2b chore(package): update lockfile package-lock.json 2020-02-13 17:49:16 +00:00
greenkeeper[bot] 306497c095 chore(package): update scratch-paint to version 0.2.0-prerelease.20200213174123 2020-02-13 17:49:12 +00:00
Karishma Chadha 17cff4775c Merge pull request #5449 from LLK/greenkeeper/scratch-blocks-0.1.0-prerelease.1581428931
Update scratch-blocks to the latest version 🚀
2020-02-12 18:01:33 -05:00
Karishma Chadha 2ee25bcc0f Merge branch 'develop' into greenkeeper/scratch-blocks-0.1.0-prerelease.1581428931 2020-02-12 18:00:54 -05:00
Karishma Chadha 7ed3a6b7c8 Merge pull request #5453 from LLK/greenkeeper/scratch-l10n-3.7.20200212141356
Update scratch-l10n to the latest version 🚀
2020-02-12 17:55:33 -05:00
Eric Rosenbaum 73fad0b7f5 Use title case for all sprite names 2020-02-12 14:34:51 -05:00
Eric Rosenbaum 147a4ed586 fix sprite position randomizer 2020-02-12 14:26:46 -05:00
Eric Rosenbaum b1a3c4b446 update libraries with more 3.0 style properties 2020-02-12 14:23:25 -05:00
DD Liu 4563b41429 Merge pull request #5455 from fsih/updatePaint
Update paint
2020-02-12 13:41:06 -05:00
DD Liu 0c8b982479 Update paint 2020-02-12 13:40:16 -05:00
greenkeeper[bot] e5811f15be chore(package): update lockfile package-lock.json 2020-02-12 14:17:55 +00:00
greenkeeper[bot] a4624da5f2 chore(package): update scratch-l10n to version 3.7.20200212141356 2020-02-12 14:17:51 +00:00
greenkeeper[bot] 5cccd63f6c chore(package): update lockfile package-lock.json 2020-02-11 13:51:34 +00:00
greenkeeper[bot] 33e01c1bdd chore(package): update scratch-blocks to version 0.1.0-prerelease.1581428931 2020-02-11 13:51:30 +00:00
DD Liu 93406fbef7 Merge pull request #5447 from LLK/greenkeeper/scratch-paint-0.2.0-prerelease.20200210174730
Update scratch-paint to the latest version 🚀
2020-02-10 13:21:31 -05:00
greenkeeper[bot] d7cb0126ad chore(package): update lockfile package-lock.json 2020-02-10 17:49:31 +00:00
greenkeeper[bot] 41831eede7 chore(package): update scratch-paint to version 0.2.0-prerelease.20200210174730 2020-02-10 17:49:26 +00:00
Benjamin Wheeler 923b931d90 Merge pull request #5411 from glenpike/glenpike-readme-patch-1
Add note about cloning to README
2020-02-10 10:05:07 -05:00
Bryce Taylor 600172f8fb Merge pull request #5443 from BryceLTaylor/skip-flakey-test
Skip blocks “renaming costume wtih special character” test
2020-02-07 16:50:50 -05:00
BryceLTaylor 41a50b87ab Skip blocks “renaming costume wtih special character” test 2020-02-07 14:05:22 -05:00
DD Liu d99360e021 Merge pull request #5441 from fsih/updateSvgRend
Add back rounded gradient strokes for 2.0 projects
2020-02-07 13:56:01 -05:00
DD Liu 4e4d359d18 Add back rounded gradient strokes for 2.0 projects 2020-02-06 18:08:08 -05:00
DD Liu 92f05792f9 Merge pull request #5439 from fsih/updatePaint
Update paint to roll back centering tool
2020-02-06 12:57:20 -05:00
DD Liu cd9d25ad48 Update paint to roll back centering tool 2020-02-06 12:56:09 -05:00
Benjamin Wheeler e34d5ed67e Merge pull request #5437 from LLK/revert-4809-refactor-file-uploader
Revert "refactor SB* file uploader into top-level HOC"
2020-02-06 11:38:58 -05:00
Benjamin Wheeler af4ad81811 Revert "refactor SB* file uploader into top-level HOC" 2020-02-06 11:33:03 -05:00
Paul Kaplan c368de81fa Merge pull request #5435 from paulkaplan/resync-paint-lock
Resync package-lock for scratch-paint
2020-02-05 19:25:34 -05:00
greenkeeper[bot] 0104f5bec8 chore(package): update lockfile package-lock.json 2020-02-05 19:23:20 -05:00
DD Liu ae8624e7e7 Merge pull request #5433 from fsih/updatePaint
update paint'
2020-02-05 17:42:54 -05:00
DD Liu 7f8b84829e update paint' 2020-02-05 17:42:12 -05:00
DD Liu d4078a795f Merge pull request #5432 from fsih/updateDeps
Update blocks and l10n
2020-02-05 16:41:42 -05:00
DD Liu f381a6a0d8 Update blocks and l10n 2020-02-05 16:40:00 -05:00
Benjamin Wheeler 962ce680c9 Merge pull request #5430 from benjiwheeler/reduce-project-state-file-size
reduce project state machine example image file size
2020-02-05 16:27:40 -05:00
Ben Wheeler 630ba84350 reduce project state image file size 2020-02-05 16:26:21 -05:00
Benjamin Wheeler 51843d6bef Merge pull request #5416 from benjiwheeler/project-state-diagram
Project state diagram
2020-02-05 16:22:04 -05:00
DD Liu 02be2155d9 Merge pull request #5428 from fsih/unUpdateDeps
Revert "Update dependencies"
2020-02-05 15:32:30 -05:00
DD Liu cca695b54e Revert "Update dependencies"
This is to remove the latest svg-renderer change, "add rounded edges to gradient strokes", because we would like to come up with a more comprehensive testing plan before adding it.
2020-02-05 15:13:31 -05:00
Ben Wheeler 4e633cb596 clearer project state example 2020-02-05 13:38:01 -05:00
DD Liu 8dc343c90d Merge pull request #5427 from LLK/greenkeeper/mkdirp-1.0.3
Greenkeeper/mkdirp 1.0.3
2020-02-05 13:03:56 -05:00
DD Liu 369eb8c3cf Merge pull request #5426 from LLK/greenkeeper/chromedriver-80.0.0
Greenkeeper/chromedriver 80.0.0
2020-02-05 11:02:41 -05:00
Eric Rosenbaum a7021e32a4 Default to first costume using sb3 property currentCostume
and remove the sb2 property currentCostumeIndex
2020-02-05 10:10:46 -05:00
Eric Rosenbaum 863276e75d Ballerina costume fixes 2020-02-05 09:44:12 -05:00
DD Liu de9dbe08f4 Merge pull request #5424 from fsih/updateDeps
Update dependencies
2020-02-04 21:38:46 -05:00
DD Liu c050829a75 Update dependencies 2020-02-04 21:28:20 -05:00
greenkeeper[bot] 6e57ea1c91 chore(package): update lockfile package-lock.json 2020-02-05 00:10:26 +00:00
greenkeeper[bot] 53d09e2162 chore(package): update chromedriver to version 80.0.0
Closes #5335
2020-02-05 00:10:22 +00:00
Benjamin Wheeler 5d9afb008a Merge pull request #4809 from benjiwheeler/refactor-file-uploader
refactor SB* file uploader into top-level HOC
2020-02-04 17:32:04 -05:00
Ben Wheeler d19cf91205 removed stale comments 2020-02-04 17:30:33 -05:00
DD Liu 4f70b0f924 Merge pull request #5417 from LLK/greenkeeper/scratch-paint-0.2.0-prerelease.20200204155336
Greenkeeper/scratch paint 0.2.0 prerelease.20200204155336
2020-02-04 16:41:51 -05:00
Ben Wheeler f8a0f46959 added project state example 2020-02-04 13:11:48 -05:00
Ben Wheeler faf0dd2f13 added project state diagram 2020-02-04 13:00:52 -05:00
Ben Wheeler cbb908831d Fixed typo 2020-02-04 11:30:57 -05:00
greenkeeper[bot] b44c0c355a chore(package): update lockfile package-lock.json 2020-02-04 16:09:21 +00:00
greenkeeper[bot] ffa364ed64 chore(package): update scratch-paint to version 0.2.0-prerelease.20200204155336
Closes #5405
2020-02-04 16:09:16 +00:00
Benjamin Wheeler 017de39c3b Added period 2020-02-03 18:04:41 -05:00
Glen Pike 01c7da1965 Add note about cloning to README
Because there are some very large files in the repository history
2020-02-03 21:02:14 +00:00
Ben Wheeler 59f428900c update menu-bar test per refactor 2020-02-03 11:16:42 -05:00
Ben Wheeler 48245be395 reverted project state changes in f2291d96 2020-01-30 14:18:13 -05:00
Eric Rosenbaum ca38789e3f Fix asset names and tags, remove duplicates 2020-01-30 12:34:15 -05:00
Ben Wheeler efed4d3721 file input is dynamically added to DOM, not rendered 2020-01-29 19:38:47 -05:00
DD Liu 95532e147d Merge pull request #5402 from LLK/greenkeeper/scratch-paint-0.2.0-prerelease.20200129174741
Greenkeeper/scratch paint 0.2.0 prerelease.20200129174741
2020-01-29 13:43:31 -05:00
DD Liu 3a56e609a5 Merge branch 'develop' into greenkeeper/scratch-paint-0.2.0-prerelease.20200129174741 2020-01-29 13:05:08 -05:00
Paul Kaplan e63842a336 Merge pull request #5400 from LLK/greenkeeper/scratch-blocks-0.1.0-prerelease.1580309823
Update scratch-blocks to the latest version 🚀
2020-01-29 13:00:34 -05:00
greenkeeper[bot] c9173427b9 chore(package): update lockfile package-lock.json 2020-01-29 17:49:28 +00:00
greenkeeper[bot] 3e5b65072c chore(package): update scratch-paint to version 0.2.0-prerelease.20200129174741
Closes #5401
2020-01-29 17:49:24 +00:00
greenkeeper[bot] 74828b3b09 chore(package): update lockfile package-lock.json 2020-01-29 15:03:07 +00:00
greenkeeper[bot] e77162791f chore(package): update scratch-blocks to version 0.1.0-prerelease.1580309823 2020-01-29 15:03:02 +00:00
Paul Kaplan 0c17cd956d Merge pull request #5399 from LLK/greenkeeper/scratch-l10n-3.7.20200128224436
Update scratch-l10n to the latest version 🚀
2020-01-29 08:46:15 -05:00
Paul Kaplan 287b29019a Merge pull request #5398 from LLK/greenkeeper/scratch-render-0.1.0-prerelease.20200128205403
Update scratch-render to the latest version 🚀
2020-01-29 06:02:37 -05:00
greenkeeper[bot] ed3b58bfb5 chore(package): update lockfile package-lock.json 2020-01-28 22:46:51 +00:00
greenkeeper[bot] c2cd6f21da chore(package): update scratch-l10n to version 3.7.20200128224436 2020-01-28 22:46:47 +00:00
greenkeeper[bot] 066e9dd6bd chore(package): update lockfile package-lock.json 2020-01-28 21:10:45 +00:00
greenkeeper[bot] 5a0860228e chore(package): update scratch-render to version 0.1.0-prerelease.20200128205403 2020-01-28 21:10:41 +00:00
Ben Wheeler f2291d963c continuing sb file uploader refactor into hoc
draft of refactor to make custom confirm modal work for upload; need to further edit sb-file-uploader

Add support for custom confirm modal to sb-file-uploader

Show custom confirm modal when confirming project upload

got custom upload refactor of file upload working, and tested failure case

cleaned up debug code, make project file upload work

simplified logic around canceling file upload

removed old sb-file-uploader.jsx; fixed linter errors

reverted two components to use old strings, not shared

(can do that refactor another time)

removed unnecessary confirm container

removed stray comment

moved, updated sb file uploader tests, related project state tests

removed custom modal, to reduce scope of changes

sb file uploader test uses intl
2020-01-28 14:57:09 -05:00
Benjamin Wheeler 97885c7518 Merge pull request #5198 from benjiwheeler/block-cloud-on-embed
simplify props of cloud-manager-hoc
2020-01-28 14:13:40 -05:00
Ben Wheeler a23dd3e349 shouldNotModifyCloudData into prop canModifyCloudData ; add defaultProps 2020-01-27 14:29:56 -05:00
Paul Kaplan 79f3f6f3f8 Merge pull request #5333 from LLK/paulkaplan-patch-2
Do not show unsupported browser modal for googlebot
2020-01-27 11:47:32 -05:00
greenkeeper[bot] 175395cce3 chore(package): update lockfile package-lock.json 2020-01-24 21:10:12 +00:00
greenkeeper[bot] ee67ddf56f chore(package): update mkdirp to version 1.0.3
Closes #5396
2020-01-24 21:10:09 +00:00
Eric Rosenbaum 5c259b70db add tag to marian sprite, fix name of basketball 1 backdrop 2020-01-23 11:46:06 -05:00
Eric Rosenbaum 3dd86c28f9 update costume rotation test 2020-01-23 11:42:59 -05:00
Ray Schamp 4b75bc8f9d Merge pull request #5388 from LLK/greenkeeper/scratch-l10n-3.7.20200114224412
Update scratch-l10n to the latest version 🚀
2020-01-22 16:51:33 -05:00
Eric Rosenbaum 85cd56307d update asset libraries 2020-01-22 15:17:04 -05:00
greenkeeper[bot] 8a4adccae5 chore(package): update lockfile package-lock.json 2020-01-16 00:35:15 +00:00
greenkeeper[bot] 9908d44d81 chore(package): update scratch-l10n to version 3.7.20200114224412 2020-01-16 00:35:10 +00:00
Paul Kaplan d2c74c5198 Merge pull request #5385 from paulkaplan/libraries-3-format
Update library-item to handle 3.0 or 2.0 library formats
2020-01-15 15:32:29 -05:00
Paul Kaplan 80e91a3c5e Update library-item to handle 3.0 or 2.0 library formats 2020-01-14 10:54:30 -05:00
DD Liu 797ce1894b Merge pull request #5384 from fsih/updateRender
Update with render hotfix
2020-01-13 15:37:55 -05:00
DD Liu f41e1c829a Update with render hotfix 2020-01-13 14:59:24 -05:00
Paul Kaplan fa5994abbd Merge pull request #5377 from paulkaplan/fix-long-sound
[fixup] Implement sound downsampler to try to allow more sounds to be edited
2020-01-09 12:19:22 -05:00
Paul Kaplan 76f5cfe1cf Correctly return the sampleRate from the sample dropper 2020-01-09 12:12:41 -05:00
Paul Kaplan fcbf1b051b Make submitNewSamples async and use promises 2020-01-09 12:12:41 -05:00
Paul Kaplan 1dcba6ecd5 Merge pull request #5376 from LLK/revert-5338-fix-long-sound
Revert "Implement sound downsampler to try to allow more sounds to be edited"
2020-01-09 11:47:45 -05:00
Paul Kaplan 79277a1227 Revert "Implement sound downsampler to try to allow more sounds to be edited" 2020-01-09 11:47:08 -05:00
DD Liu e476548c64 Trigger rebuild because my build flaked? 2020-01-09 03:18:32 -05:00
DD Liu 8adb097cd1 Merge pull request #5374 from fsih/updateEmptyPaintBug
Fix empty paint bug
2020-01-09 02:52:28 -05:00
DD Liu 403a7a5883 Update package lock 2020-01-09 02:43:24 -05:00
DD Liu dd5562323e Update svgrenderer deps and renderer 2020-01-09 02:42:34 -05:00
Benjamin Wheeler f261f4614a Merge pull request #5370 from LLK/greenkeeper/scratch-l10n-3.7.20200108141814
Greenkeeper/scratch l10n 3.7.20200108141814
2020-01-08 21:59:19 -05:00
greenkeeper[bot] a93248df31 chore(package): update scratch-l10n to version 3.7.20200108141814
Closes #5354
2020-01-08 21:58:42 -05:00
Benjamin Wheeler 1fa8742dec Merge pull request #5360 from LLK/greenkeeper/scratch-blocks-0.1.0-prerelease.1578322100
Update scratch-blocks to the latest version 🚀
2020-01-08 21:53:40 -05:00
Ben Wheeler 8b0f2c16bc updated package-lock 2020-01-08 21:34:23 -05:00
greenkeeper[bot] 57988d63c2 chore(package): update lockfile package-lock.json 2020-01-08 21:34:23 -05:00
greenkeeper[bot] c3d3a7a464 chore(package): update scratch-blocks to version 0.1.0-prerelease.1578322100 2020-01-08 21:34:23 -05:00
Paul Kaplan e1102f91ef Merge pull request #5369 from LLK/greenkeeper/scratch-paint-0.2.0-prerelease.20200107211248
Update scratch-paint to the latest version 🚀
2020-01-08 10:03:50 -05:00
greenkeeper[bot] e10a3f282f chore(package): update lockfile package-lock.json 2020-01-07 21:59:34 +00:00
greenkeeper[bot] 0ef59001f1 chore(package): update scratch-paint to version 0.2.0-prerelease.20200107211248 2020-01-07 21:59:30 +00:00
DD Liu ad96f2eb30 Merge pull request #5368 from fsih/updateSvgRend
Update SVG Renderer
2020-01-07 16:22:38 -05:00
DD Liu 5fac48acc9 updateSvgRend 2020-01-07 16:04:33 -05:00
DD Liu b19139696b Merge pull request #5367 from LLK/greenkeeper/scratch-paint-0.2.0-prerelease.20200107165446
Update scratch-paint to the latest version 🚀
2020-01-07 14:13:09 -05:00
DD Liu a5ccbfb8b9 Merge branch 'develop' into greenkeeper/scratch-paint-0.2.0-prerelease.20200107165446 2020-01-07 14:12:50 -05:00
DD Liu 7960eed191 Merge pull request #5366 from LLK/greenkeeper/scratch-render-0.1.0-prerelease.20200107165342
Update scratch-render to the latest version 🚀
2020-01-07 14:11:58 -05:00
greenkeeper[bot] cb0e24b5be chore(package): update lockfile package-lock.json 2020-01-07 17:01:55 +00:00
greenkeeper[bot] ccc12a02c3 chore(package): update scratch-paint to version 0.2.0-prerelease.20200107165446 2020-01-07 17:01:50 +00:00
greenkeeper[bot] d505af579a chore(package): update lockfile package-lock.json 2020-01-07 17:01:23 +00:00
greenkeeper[bot] 504097b495 chore(package): update scratch-render to version 0.1.0-prerelease.20200107165342 2020-01-07 17:01:19 +00:00
DD Liu 484eb6bc9f Merge pull request #5358 from LLK/greenkeeper/scratch-svg-renderer-0.2.0-prerelease.20200103191258
Update scratch-svg-renderer to the latest version 🚀
2020-01-07 11:48:59 -05:00
Benjamin Wheeler 96392659fd Merge pull request #5291 from benjiwheeler/standalone-new-project-title-fix
reset title on transitioning to isShowingWithoutId
2020-01-06 15:27:38 -05:00
greenkeeper[bot] 2c16a16da5 chore(package): update lockfile package-lock.json 2020-01-03 19:18:55 +00:00
greenkeeper[bot] ed0db53f36 chore(package): update scratch-svg-renderer to version 0.2.0-prerelease.20200103191258 2020-01-03 19:18:50 +00:00
Ben Wheeler f244da7705 added project-state integration test for new title 2020-01-02 14:29:04 -05:00
Benjamin Wheeler 3d1205e453 Merge pull request #5357 from LLK/greenkeeper/papaparse-5.1.1
Greenkeeper/papaparse 5.1.1
2019-12-30 23:18:50 -05:00
Ben Wheeler 3b1889b941 updated package lock 2019-12-30 23:17:43 -05:00
Paul Kaplan a908345491 Merge pull request #5338 from paulkaplan/fix-long-sound
Implement sound downsampler to try to allow more sounds to be edited
2019-12-30 14:22:34 -05:00
Karishma Chadha 50de01086a Merge pull request #5355 from LLK/greenkeeper/scratch-vm-0.2.0-prerelease.20191227164934
Update scratch-vm to the latest version 🚀
2019-12-27 14:34:16 -05:00
greenkeeper[bot] 57863d99a1 chore(package): update lockfile package-lock.json 2019-12-27 16:52:17 +00:00
greenkeeper[bot] 3e93db7c0b chore(package): update scratch-vm to version 0.2.0-prerelease.20191227164934 2019-12-27 16:52:13 +00:00
Benjamin Wheeler 28f4cc737d Merge pull request #5343 from taybenlor/develop
Fix `doneUpdatingProject` call signature
2019-12-24 21:45:26 -05:00
chrisgarrity fa5cfb495f Merge pull request #5352 from LLK/greenkeeper/scratch-blocks-0.1.0-prerelease.1576850350
Update scratch-blocks to the latest version 🚀
2019-12-20 11:28:06 -05:00
greenkeeper[bot] 5b2e8a29e3 chore(package): update lockfile package-lock.json 2019-12-20 14:01:43 +00:00
greenkeeper[bot] a7fce92b18 chore(package): update scratch-blocks to version 0.1.0-prerelease.1576850350 2019-12-20 14:01:39 +00:00
chrisgarrity 12b8cfbb43 Merge pull request #5349 from LLK/greenkeeper/scratch-l10n-3.7.20191219145348
Update scratch-l10n to the latest version 🚀
2019-12-20 08:06:10 -05:00
Paul Kaplan d1d98337c8 Update docs and tests 2019-12-19 16:01:21 -05:00
greenkeeper[bot] 480f17d872 chore(package): update lockfile package-lock.json 2019-12-19 14:56:10 +00:00
greenkeeper[bot] 274cbbd356 chore(package): update scratch-l10n to version 3.7.20191219145348 2019-12-19 14:56:05 +00:00
Eric Rosenbaum bb80fa49ac Move backupDownSampler into util and add tests 2019-12-18 15:19:47 -05:00
greenkeeper[bot] 38e4c5bbfa chore(package): update lockfile package-lock.json 2019-12-18 11:54:33 +00:00
greenkeeper[bot] b3e5dd88fb chore(package): update papaparse to version 5.1.1
Closes #5018
2019-12-18 11:54:30 +00:00
Ben Taylor 6027bb9011 Fix doneUpdatingProject call signature
ProjectSaverHOC has been using the wrong call signature for `doneUpdatingProject` and `onUpdatedProject`.
2019-12-18 09:59:07 +11:00
picklesrus d62ede33e5 Merge pull request #5346 from LLK/greenkeeper/scratch-paint-0.2.0-prerelease.20191217213717
Update scratch-paint to the latest version 🚀
2019-12-17 17:05:33 -05:00
greenkeeper[bot] 1a479c61b4 chore(package): update lockfile package-lock.json 2019-12-17 21:38:57 +00:00
greenkeeper[bot] 2e8adc7ac7 chore(package): update scratch-paint to version 0.2.0-prerelease.20191217213717 2019-12-17 21:38:53 +00:00
picklesrus 5c377e70c9 Merge pull request #5345 from LLK/greenkeeper/scratch-render-0.1.0-prerelease.20191217212645
Update scratch-render to the latest version 🚀
2019-12-17 16:29:30 -05:00
greenkeeper[bot] 67fdd9bb51 chore(package): update lockfile package-lock.json 2019-12-17 21:28:34 +00:00
greenkeeper[bot] c68ec4ad16 chore(package): update scratch-render to version 0.1.0-prerelease.20191217212645 2019-12-17 21:28:30 +00:00
picklesrus 91e87f7d16 Merge pull request #5344 from LLK/greenkeeper/scratch-svg-renderer-0.2.0-prerelease.20191217211338
Update scratch-svg-renderer to the latest version 🚀
2019-12-17 16:19:48 -05:00
greenkeeper[bot] 762ffe53f0 chore(package): update lockfile package-lock.json 2019-12-17 21:15:45 +00:00
greenkeeper[bot] d63c8b1dbb chore(package): update scratch-svg-renderer to version 0.2.0-prerelease.20191217211338 2019-12-17 21:15:41 +00:00
Eric Rosenbaum e799708707 Use for loop instead of filter (20x faster) 2019-12-16 17:05:29 -05:00
Eric Rosenbaum b699e76972 Use backup down sampler when 22kHz not supported 2019-12-16 13:49:39 -05:00
Paul Kaplan 914ba4910b Use vendor prefixed offline audio context for safari 2019-12-12 15:57:25 -05:00
Paul Kaplan 748f8559e4 Remove the 11khz option because it doesnt work on safari 2019-12-12 15:56:59 -05:00
Paul Kaplan 8fae109811 Add downsampler 2019-12-12 12:30:12 -05:00
Paul Kaplan 7980c23ecc Make submitNewSamples async and use promises 2019-12-12 11:44:15 -05:00
DD Liu 5e4a2b788c Merge pull request #5337 from LLK/greenkeeper/scratch-render-0.1.0-prerelease.20191211203739
Update scratch-render to the latest version 🚀
2019-12-11 15:59:48 -05:00
greenkeeper[bot] 8caff78e08 chore(package): update lockfile package-lock.json 2019-12-11 20:51:43 +00:00
greenkeeper[bot] e1c3bb6d96 chore(package): update scratch-render to version 0.1.0-prerelease.20191211203739 2019-12-11 20:51:39 +00:00
Paul Kaplan aebdcc855c Merge pull request #5336 from LLK/greenkeeper/scratch-l10n-3.6.20191210224141
Update scratch-l10n to the latest version 🚀
2019-12-11 11:17:10 -05:00
greenkeeper[bot] 86fd6ec8bf chore(package): update lockfile package-lock.json 2019-12-10 22:44:02 +00:00
greenkeeper[bot] b351cc599d chore(package): update scratch-l10n to version 3.6.20191210224141 2019-12-10 22:43:57 +00:00
Paul Kaplan 0230546a20 Merge pull request #5332 from LLK/greenkeeper/scratch-paint-0.2.0-prerelease.20191210104711
Update scratch-paint to the latest version 🚀
2019-12-10 10:36:05 -05:00
Paul Kaplan 9638444a49 Do not show unsupported browser modal for googlebot
This modal may be preventing the crawler from correctly indexing pages, because it takes over the whole screen.
2019-12-10 06:47:41 -05:00
greenkeeper[bot] 984b87ead5 chore(package): update lockfile package-lock.json 2019-12-10 10:57:58 +00:00
greenkeeper[bot] 59c4f36b90 chore(package): update scratch-paint to version 0.2.0-prerelease.20191210104711 2019-12-10 10:57:54 +00:00
Paul Kaplan 21a6fe3a27 Merge pull request #5331 from LLK/greenkeeper/scratch-paint-0.2.0-prerelease.20191209210523
Update scratch-paint to the latest version 🚀
2019-12-10 05:40:44 -05:00
greenkeeper[bot] 02f806fc9d chore(package): update lockfile package-lock.json 2019-12-09 21:40:37 +00:00
greenkeeper[bot] d9003c9d56 chore(package): update scratch-paint to version 0.2.0-prerelease.20191209210523 2019-12-09 21:40:33 +00:00
Paul Kaplan c944295140 Merge pull request #5329 from LLK/revert-5328-revert-5319-greenkeeper/scratch-render-0.1.0-prerelease.20191126210304
Bring back in renderer update with mipmap change
2019-12-05 10:29:15 -05:00
Paul Kaplan 2c64a62f23 Revert "Revert "Update scratch-render to the latest version 🚀"" 2019-12-05 10:26:15 -05:00
Paul Kaplan 8639f1838c Merge pull request #5328 from LLK/revert-5319-greenkeeper/scratch-render-0.1.0-prerelease.20191126210304
Revert "Update scratch-render to the latest version 🚀"
2019-12-05 09:33:36 -05:00
Paul Kaplan 4e80510b98 Revert "Update scratch-render to the latest version 🚀" 2019-12-05 09:30:15 -05:00
Paul Kaplan 9f58bd9ee3 Merge pull request #5323 from zoebentley/tutorial-images-es-419
Make Spanish tutorial images also load for Latinamerican Spanish
2019-12-04 09:46:37 -05:00
Paul Kaplan 236cc6f872 Merge pull request #5325 from LLK/greenkeeper/scratch-l10n-3.6.20191204142956
Update scratch-l10n to the latest version 🚀
2019-12-04 09:36:58 -05:00
greenkeeper[bot] b3d336a08f chore(package): update lockfile package-lock.json 2019-12-04 14:35:28 +00:00
greenkeeper[bot] 97fcbf85fc chore(package): update scratch-l10n to version 3.6.20191204142956 2019-12-04 14:35:20 +00:00
DD Liu e3b3bcc963 Merge pull request #5319 from LLK/greenkeeper/scratch-render-0.1.0-prerelease.20191126210304
Update scratch-render to the latest version 🚀
2019-12-04 09:33:20 -05:00
Zoë Bentley 775b805e56 Make Spanish tutorial images also load for Latinamerican Spanish 2019-12-02 15:04:35 -05:00
greenkeeper[bot] a1124807ca chore(package): update lockfile package-lock.json 2019-11-26 21:04:55 +00:00
greenkeeper[bot] b1674c1b0c chore(package): update scratch-render to version 0.1.0-prerelease.20191126210304 2019-11-26 21:04:51 +00:00
Ben Wheeler 21d6ce111e added comments 2019-11-12 15:25:07 -05:00
Ben Wheeler fcb6de39f3 more precise case for resetting project title to default 2019-11-12 15:22:40 -05:00
Ben Wheeler 3c6e9723e3 reset title on transitioning to isShowingWithoutId 2019-11-12 15:04:55 -05:00
31 changed files with 16039 additions and 12150 deletions

No files matched your search

+1 -1
View File
@@ -14,6 +14,6 @@ npm-*
/dist
/.opt-in
# generated translation files
# Generated translation files
/translations
/locale
+58 -1
View File
@@ -18,6 +18,8 @@ cd scratch-gui
npm install
```
**You may want to add `--depth=1` to the `git clone` command because there are some [large files in the git repository history](https://github.com/LLK/scratch-gui/issues/5140).**
## Getting started
Running the project requires Node.js to be installed.
@@ -74,7 +76,7 @@ See [jest cli docs](https://facebook.github.io/jest/docs/en/cli.html#content) fo
*NOTE: If you're a windows user, please run these scripts in Windows `cmd.exe` instead of Git Bash/MINGW64.*
Before running any test, make sure you have run `npm install` from this (scratch-gui) repository's top level.
Before running any tests, make sure you have run `npm install` from this (scratch-gui) repository's top level.
#### Main testing command
@@ -194,5 +196,60 @@ Further reading: [Stack Overflow](https://stackoverflow.com/questions/46602286/n
You can publish the GUI to github.io so that others on the Internet can view it.
[Read the wiki for a step-by-step guide.](https://github.com/LLK/scratch-gui/wiki/Publishing-to-GitHub-Pages)
## Understanding the project state machine
Since so much code throughout scratch-gui depends on the state of the project, which goes through many different phases of loading, displaying and saving, we created a "finite state machine" to make it clear which state it is in at any moment. This is contained in the file src/reducers/project-state.js .
It can be hard to understand the code in src/reducers/project-state.js . There are several types of data and functions used, which relate to each other:
### Loading states
These include state constant strings like:
* `NOT_LOADED` (the default state),
* `ERROR`,
* `FETCHING_WITH_ID`,
* `LOADING_VM_WITH_ID`,
* `REMIXING`,
* `SHOWING_WITH_ID`,
* `SHOWING_WITHOUT_ID`,
* etc.
### Transitions
These are names for the action which causes a state change. Some examples are:
* `START_FETCHING_NEW`,
* `DONE_FETCHING_WITH_ID`,
* `DONE_LOADING_VM_WITH_ID`,
* `SET_PROJECT_ID`,
* `START_AUTO_UPDATING`,
### How transitions relate to loading states
As this diagram of the project state machine shows, various transition actions can move us from one loading state to another:
![Project state diagram](docs/project_state_diagram.svg)
_Note: for clarity, the diagram above excludes states and transitions relating to error handling._
#### Example
Here's an example of how states transition.
Suppose a user clicks on a project, and the page starts to load with url https://scratch.mit.edu/projects/123456 .
Here's what will happen in the project state machine:
![Project state example](docs/project_state_example.png)
1. When the app first mounts, the project state is `NOT_LOADED`.
2. The `SET_PROJECT_ID` redux action is dispatched (from src/lib/project-fetcher-hoc.jsx), with `projectId` set to `123456`. This transitions the state from `NOT_LOADED` to `FETCHING_WITH_ID`.
3. The `FETCHING_WITH_ID` state. In src/lib/project-fetcher-hoc.jsx, the `projectId` value `123456` is used to request the data for that project from the server.
4. When the server responds with the data, src/lib/project-fetcher-hoc.jsx dispatches the `DONE_FETCHING_WITH_ID` action, with `projectData` set. This transitions the state from `FETCHING_WITH_ID` to `LOADING_VM_WITH_ID`.
5. The `LOADING_VM_WITH_ID` state. In src/lib/vm-manager-hoc.jsx, we load the `projectData` into Scratch's virtual machine ("the vm").
6. When loading is done, src/lib/vm-manager-hoc.jsx dispatches the `DONE_LOADING_VM_WITH_ID` action. This transitions the state from `LOADING_VM_WITH_ID` to `SHOWING_WITH_ID`
7. The `SHOWING_WITH_ID` state. Now the project appears normally and is playable and editable.
## Donate
We provide [Scratch](https://scratch.mit.edu) free of charge, and want to keep it that way! Please consider making a [donation](https://secure.donationpay.org/scratchfoundation/) to support our continued engineering, design, community, and resource development efforts. Donations of any size are appreciated. Thank you!
+3
View File
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1381px" height="1012px" viewBox="-0.5 -0.5 1381 1012" content="&lt;mxfile host=&quot;www.draw.io&quot; modified=&quot;2020-02-04T16:31:44.889Z&quot; agent=&quot;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36&quot; etag=&quot;8a2X5Jj65jOGG04xBBh1&quot; version=&quot;12.6.4&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;Page-1&quot; id=&quot;58cdce13-f638-feb5-8d6f-7d28b1aa9fa0&quot;&gt;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 truncated

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

+288 -336
View File
File diff suppressed because it is too large. Load diff
+10 -11
View File
@@ -6,7 +6,7 @@
"scripts": {
"build": "npm run clean && webpack --progress --colors --bail",
"clean": "rimraf ./build && mkdirp build && rimraf ./dist && mkdirp dist",
"deploy": "touch build/.nojekyll && gh-pages -t -d build -m \"Build for $(git log --pretty=format:%H -n1)\"",
"deploy": "touch build/.nojekyll && gh-pages -t -d build -m \"Build for $(git log --pretty=format:%H -n1) [skip ci]\"",
"prune": "./prune-gh-pages.sh",
"i18n:push": "tx-push-src scratch-editor interface translations/en.json",
"i18n:src": "rimraf ./translations/messages/src && babel src > tmp.js && rimraf tmp.js && build-i18n-src ./translations/messages/src ./translations/ && npm run i18n:push",
@@ -44,7 +44,7 @@
"babel-loader": "^8.0.4",
"base64-loader": "1.0.0",
"bowser": "1.9.4",
"chromedriver": "78.0.1",
"chromedriver": "80.0.0",
"classnames": "2.2.6",
"computed-style-to-inline-style": "3.0.0",
"copy-webpack-plugin": "^4.5.1",
@@ -78,9 +78,9 @@
"lodash.pick": "4.4.0",
"lodash.throttle": "4.0.1",
"minilog": "3.1.0",
"mkdirp": "^0.5.1",
"mkdirp": "^1.0.3",
"omggif": "1.0.9",
"papaparse": "4.6.2",
"papaparse": "5.1.1",
"postcss-import": "^12.0.0",
"postcss-loader": "^3.0.0",
"postcss-simple-vars": "^5.0.1",
@@ -103,19 +103,18 @@
"react-test-renderer": "16.2.0",
"react-tooltip": "3.8.0",
"react-virtualized": "9.20.1",
"react-visibility-sensor": "5.0.2",
"redux": "3.7.2",
"redux-mock-store": "^1.2.3",
"redux-throttle": "0.1.1",
"rimraf": "^2.6.1",
"scratch-audio": "0.1.0-prerelease.20190925183642",
"scratch-l10n": "3.6.20191120161253",
"scratch-blocks": "0.1.0-prerelease.1574180945",
"scratch-paint": "0.2.0-prerelease.20191114200704",
"scratch-render": "0.1.0-prerelease.20191106204814",
"scratch-blocks": "0.1.0-prerelease.1583868812",
"scratch-l10n": "3.7.20200310213125",
"scratch-paint": "0.2.0-prerelease.20200213174123",
"scratch-render": "0.1.0-prerelease.20200228152431",
"scratch-storage": "1.3.2",
"scratch-svg-renderer": "0.2.0-prerelease.20191104164753",
"scratch-vm": "0.2.0-prerelease.20191119203901",
"scratch-svg-renderer": "0.2.0-prerelease.20200205003400",
"scratch-vm": "0.2.0-prerelease.20200317155559",
"selenium-webdriver": "3.6.0",
"startaudiocontext": "1.2.1",
"style-loader": "^0.23.0",
+7 -10
View File
@@ -4,7 +4,6 @@ import React from 'react';
import Box from '../box/box.jsx';
import PlayButton from '../../containers/play-button.jsx';
import ScratchImage from '../scratch-image/scratch-image.jsx';
import styles from './library-item.css';
import classNames from 'classnames';
@@ -37,12 +36,10 @@ class LibraryItemComponent extends React.PureComponent {
/>
</div>
) : null}
{this.props.iconSource ? (
<ScratchImage
className={styles.featuredImage}
imageSource={this.props.iconSource}
/>
) : null}
<img
className={styles.featuredImage}
src={this.props.iconURL}
/>
</div>
{this.props.insetIconURL ? (
<div className={styles.libraryItemInsetImageContainer}>
@@ -130,9 +127,9 @@ class LibraryItemComponent extends React.PureComponent {
onMouseEnter={this.props.showPlayButton ? this.props.onMouseEnter : null}
onMouseLeave={this.props.showPlayButton ? this.props.onMouseLeave : null}
>
<ScratchImage
<img
className={styles.libraryItemImage}
imageSource={this.props.iconSource}
src={this.props.iconURL}
/>
</Box>
</Box>
@@ -162,7 +159,7 @@ LibraryItemComponent.propTypes = {
extensionId: PropTypes.string,
featured: PropTypes.bool,
hidden: PropTypes.bool,
iconSource: ScratchImage.ImageSourcePropType,
iconURL: PropTypes.string,
insetIconURL: PropTypes.string,
internetConnectionRequired: PropTypes.bool,
isPlaying: PropTypes.bool,
+7 -50
View File
@@ -10,7 +10,6 @@ import Divider from '../divider/divider.jsx';
import Filter from '../filter/filter.jsx';
import TagButton from '../../containers/tag-button.jsx';
import Spinner from '../spinner/spinner.jsx';
import storage from '../../lib/storage';
import styles from './library.css';
@@ -30,47 +29,6 @@ const messages = defineMessages({
const ALL_TAG = {tag: 'all', intlLabel: messages.allTag};
const tagListPrefix = [ALL_TAG];
/**
* Find the AssetType which corresponds to a particular file extension. For example, 'png' => AssetType.ImageBitmap.
* @param {string} fileExtension - the file extension to look up.
* @returns {AssetType} - the AssetType corresponding to the extension, if any.
*/
const getAssetTypeForFileExtension = function (fileExtension) {
const compareOptions = {
sensitivity: 'accent',
usage: 'search'
};
for (const assetTypeId in storage.AssetType) {
const assetType = storage.AssetType[assetTypeId];
if (fileExtension.localeCompare(assetType.runtimeFormat, compareOptions) === 0) {
return assetType;
}
}
};
/**
* Figure out an `imageSource` (URI or asset ID & type) for a library item's icon.
* @param {object} item - either a library item or one of a library item's costumes.
* @returns {object} - an `imageSource` ready to be passed to a `ScratchImage`.
*/
const getItemImageSource = function (item) {
if (item.rawURL) {
return {
uri: item.rawURL
};
}
// TODO: adjust libraries to be more storage-friendly; don't use split() here.
const md5 = item.md5 || item.baseLayerMD5;
if (md5) {
const [assetId, fileExtension] = md5.split('.');
return {
assetId: assetId,
assetType: getAssetTypeForFileExtension(fileExtension)
};
}
};
class LibraryComponent extends React.Component {
constructor (props) {
super(props);
@@ -250,10 +208,8 @@ class LibraryComponent extends React.Component {
})}
ref={this.setFilteredDataRef}
>
{this.state.loaded ? this.getFilteredData().map((dataItem, index) => {
const iconSource = getItemImageSource(dataItem);
const icons = dataItem.json && dataItem.json.costumes.map(getItemImageSource);
return (<LibraryItem
{this.state.loaded ? this.getFilteredData().map((dataItem, index) => (
<LibraryItem
bluetoothRequired={dataItem.bluetoothRequired}
collaborator={dataItem.collaborator}
description={dataItem.description}
@@ -261,8 +217,9 @@ class LibraryComponent extends React.Component {
extensionId={dataItem.extensionId}
featured={dataItem.featured}
hidden={dataItem.hidden}
iconSource={iconSource}
icons={icons}
iconMd5={dataItem.md5}
iconRawURL={dataItem.rawURL}
icons={dataItem.json && dataItem.json.costumes}
id={index}
insetIconURL={dataItem.insetIconURL}
internetConnectionRequired={dataItem.internetConnectionRequired}
@@ -273,8 +230,8 @@ class LibraryComponent extends React.Component {
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
onSelect={this.handleSelect}
/>);
}) : (
/>
)) : (
<div className={styles.spinnerWrapper}>
<Spinner
large
@@ -1,139 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import VisibilitySensor from 'react-visibility-sensor';
import storage from '../../lib/storage';
class ScratchImage extends React.PureComponent {
static init () {
this._maxParallelism = 6;
this._currentJobs = 0;
this._pendingImages = new Set();
}
static loadPendingImages () {
if (this._currentJobs >= this._maxParallelism) {
// already busy
return;
}
// Find the first visible image. If there aren't any, find the first non-visible image.
let nextImage;
for (const image of this._pendingImages) {
if (image.isVisible) {
nextImage = image;
break;
} else {
nextImage = nextImage || image;
}
}
// If we found an image to load:
// 1) Remove it from the queue
// 2) Load the image
// 3) Pump the queue again
if (nextImage) {
this._pendingImages.delete(nextImage);
const imageSource = nextImage.props.imageSource;
++this._currentJobs;
storage
.load(imageSource.assetType, imageSource.assetId)
.then(asset => {
if (!nextImage.wasUnmounted) {
const dataURI = asset.encodeDataURI();
nextImage.setState({
imageURI: dataURI
});
}
--this._currentJobs;
this.loadPendingImages();
});
}
}
constructor (props) {
super(props);
this.state = {};
Object.assign(this.state, this._loadImageSource(props.imageSource));
}
componentWillReceiveProps (nextProps) {
const newState = this._loadImageSource(nextProps.imageSource);
this.setState(newState);
}
componentWillUnmount () {
this.wasUnmounted = true;
ScratchImage._pendingImages.delete(this);
}
/**
* Calculate the state changes necessary to load the image specified in the provided source info. If the component
* is mounted, call setState() with the return value of this function. If the component has not yet mounted, use
* the return value of this function as initial state for the component.
*
* @param {object} imageSource - the new source for the image, including either assetId or URI
* @returns {object} - the new state values, if any.
*/
_loadImageSource (imageSource) {
if (imageSource) {
if (imageSource.uri) {
ScratchImage._pendingImages.delete(this);
return {
imageURI: imageSource.uri,
lastRequestedAsset: null
};
}
if (this.state.lastRequestedAsset !== imageSource.assetId) {
ScratchImage._pendingImages.add(this);
return {
lastRequestedAsset: imageSource.assetId
};
}
}
// Nothing to do - don't change any state.
return {};
}
render () {
const {
src: _src,
imageSource: _imageSource,
...imgProps
} = this.props;
return (
<VisibilitySensor
intervalCheck
scrollCheck
>
{
({isVisible}) => {
this.isVisible = isVisible;
ScratchImage.loadPendingImages();
return (
<img
src={this.state.imageURI}
{...imgProps}
/>
);
}
}
</VisibilitySensor>
);
}
}
ScratchImage.ImageSourcePropType = PropTypes.oneOfType([
PropTypes.shape({
assetId: PropTypes.string.isRequired,
assetType: PropTypes.oneOf(Object.values(storage.AssetType)).isRequired
}),
PropTypes.shape({
uri: PropTypes.string.isRequired
})
]);
ScratchImage.propTypes = {
imageSource: ScratchImage.ImageSourcePropType.isRequired
};
ScratchImage.init();
export default ScratchImage;
+22 -9
View File
@@ -91,17 +91,23 @@ class LibraryItem extends React.PureComponent {
const nextIconIndex = (this.state.iconIndex + 1) % this.props.icons.length;
this.setState({iconIndex: nextIconIndex});
}
curIconSource () {
curIconMd5 () {
const iconMd5Prop = this.props.iconMd5;
if (this.props.icons &&
this.state.isRotatingIcon &&
this.state.iconIndex < this.props.icons.length &&
this.props.icons[this.state.iconIndex]) {
return this.props.icons[this.state.iconIndex];
this.state.iconIndex < this.props.icons.length) {
const icon = this.props.icons[this.state.iconIndex] || {};
return icon.md5ext || // 3.0 library format
icon.baseLayerMD5 || // 2.0 library format, TODO GH-5084
iconMd5Prop;
}
return this.props.iconSource;
return iconMd5Prop;
}
render () {
const iconSource = this.curIconSource();
const iconMd5 = this.curIconMd5();
const iconURL = iconMd5 ?
`https://cdn.assets.scratch.mit.edu/internalapi/asset/${iconMd5}/get/` :
this.props.iconRawURL;
return (
<LibraryItemComponent
bluetoothRequired={this.props.bluetoothRequired}
@@ -111,7 +117,8 @@ class LibraryItem extends React.PureComponent {
extensionId={this.props.extensionId}
featured={this.props.featured}
hidden={this.props.hidden}
iconSource={iconSource}
iconURL={iconURL}
icons={this.props.icons}
id={this.props.id}
insetIconURL={this.props.insetIconURL}
internetConnectionRequired={this.props.internetConnectionRequired}
@@ -142,8 +149,14 @@ LibraryItem.propTypes = {
extensionId: PropTypes.string,
featured: PropTypes.bool,
hidden: PropTypes.bool,
iconSource: LibraryItemComponent.propTypes.iconSource, // single icon
icons: PropTypes.arrayOf(LibraryItemComponent.propTypes.iconSource), // rotating icons
iconMd5: PropTypes.string,
iconRawURL: PropTypes.string,
icons: PropTypes.arrayOf(
PropTypes.shape({
baseLayerMD5: PropTypes.string, // 2.0 library format, TODO GH-5084
md5ext: PropTypes.string // 3.0 library format
})
),
id: PropTypes.number.isRequired,
insetIconURL: PropTypes.string,
internetConnectionRequired: PropTypes.bool,
+109 -84
View File
@@ -6,7 +6,12 @@ import VM from 'scratch-vm';
import {connect} from 'react-redux';
import {computeChunkedRMS, encodeAndAddSoundToVM, SOUND_BYTE_LIMIT} from '../lib/audio/audio-util.js';
import {
computeChunkedRMS,
encodeAndAddSoundToVM,
downsampleIfNeeded,
dropEveryOtherSample
} from '../lib/audio/audio-util.js';
import AudioEffects from '../lib/audio/audio-effects.js';
import SoundEditorComponent from '../components/sound-editor/sound-editor.jsx';
import AudioBufferPlayer from '../lib/audio/audio-buffer-player.js';
@@ -39,7 +44,8 @@ class SoundEditor extends React.Component {
'paste',
'handleKeyPress',
'handleContainerClick',
'setRef'
'setRef',
'resampleBufferToRate'
]);
this.state = {
copyBuffer: null,
@@ -132,45 +138,32 @@ class SoundEditor extends React.Component {
});
}
submitNewSamples (samples, sampleRate, skipUndo) {
// Encode the new sound into a wav so that it can be stored
let wavBuffer = null;
try {
wavBuffer = WavEncoder.encode.sync({
sampleRate: sampleRate,
channelData: [samples]
return downsampleIfNeeded({samples, sampleRate}, this.resampleBufferToRate)
.then(({samples: newSamples, sampleRate: newSampleRate}) =>
WavEncoder.encode({
sampleRate: newSampleRate,
channelData: [newSamples]
}).then(wavBuffer => {
if (!skipUndo) {
this.redoStack = [];
if (this.undoStack.length >= UNDO_STACK_SIZE) {
this.undoStack.shift(); // Drop the first element off the array
}
this.undoStack.push(this.getUndoItem());
}
this.resetState(newSamples, newSampleRate);
this.props.vm.updateSoundBuffer(
this.props.soundIndex,
this.audioBufferPlayer.buffer,
new Uint8Array(wavBuffer));
return true; // Edit was successful
})
)
.catch(e => {
// Encoding failed, or the sound was too large to save so edit is rejected
log.error(`Encountered error while trying to encode sound update: ${e}`);
return false; // Edit was not applied
});
if (wavBuffer.byteLength > SOUND_BYTE_LIMIT) {
// Cancel the sound update by setting to null
wavBuffer = null;
log.error(`Refusing to encode sound larger than ${SOUND_BYTE_LIMIT} bytes`);
}
} catch (e) {
// This error state is mostly for the mock sounds used during testing.
// Any incorrect sound buffer trying to get interpretd as a Wav file
// should yield this error.
// This can also happen if the sound is too be allocated in memory.
log.error(`Encountered error while trying to encode sound update: ${e}`);
}
// Do not submit sound if it could not be encoded (i.e. if too large)
if (wavBuffer) {
if (!skipUndo) {
this.redoStack = [];
if (this.undoStack.length >= UNDO_STACK_SIZE) {
this.undoStack.shift(); // Drop the first element off the array
}
this.undoStack.push(this.getUndoItem());
}
this.resetState(samples, sampleRate);
this.props.vm.updateSoundBuffer(
this.props.soundIndex,
this.audioBufferPlayer.buffer,
new Uint8Array(wavBuffer));
return true; // Update succeeded
}
return false; // Update failed
}
handlePlay () {
this.audioBufferPlayer.stop();
@@ -209,13 +202,15 @@ class SoundEditor extends React.Component {
newSamples.set(firstPart, 0);
newSamples.set(secondPart, firstPart.length);
}
this.submitNewSamples(newSamples, sampleRate);
this.setState({
trimStart: null,
trimEnd: null
this.submitNewSamples(newSamples, sampleRate).then(() => {
this.setState({
trimStart: null,
trimEnd: null
});
});
}
handleDeleteInverse () {
// Delete everything outside of the trimmers
const {samples, sampleRate} = this.copyCurrentBuffer();
const sampleCount = samples.length;
const startIndex = Math.floor(this.state.trimStart * sampleCount);
@@ -224,10 +219,13 @@ class SoundEditor extends React.Component {
if (clippedSamples.length === 0) {
clippedSamples = new Float32Array(1);
}
this.submitNewSamples(clippedSamples, sampleRate);
this.setState({
trimStart: null,
trimEnd: null
this.submitNewSamples(clippedSamples, sampleRate).then(success => {
if (success) {
this.setState({
trimStart: null,
trimEnd: null
});
}
});
}
handleUpdateTrim (trimStart, trimEnd) {
@@ -257,14 +255,15 @@ class SoundEditor extends React.Component {
effects.process((renderedBuffer, adjustedTrimStart, adjustedTrimEnd) => {
const samples = renderedBuffer.getChannelData(0);
const sampleRate = renderedBuffer.sampleRate;
const success = this.submitNewSamples(samples, sampleRate);
if (success) {
if (this.state.trimStart === null) {
this.handlePlay();
} else {
this.setState({trimStart: adjustedTrimStart, trimEnd: adjustedTrimEnd}, this.handlePlay);
this.submitNewSamples(samples, sampleRate).then(success => {
if (success) {
if (this.state.trimStart === null) {
this.handlePlay();
} else {
this.setState({trimStart: adjustedTrimStart, trimEnd: adjustedTrimEnd}, this.handlePlay);
}
}
}
});
});
}
tooLoud () {
@@ -287,16 +286,22 @@ class SoundEditor extends React.Component {
this.redoStack.push(this.getUndoItem());
const {samples, sampleRate, trimStart, trimEnd} = this.undoStack.pop();
if (samples) {
this.submitNewSamples(samples, sampleRate, true);
this.setState({trimStart: trimStart, trimEnd: trimEnd}, this.handlePlay);
return this.submitNewSamples(samples, sampleRate, true).then(success => {
if (success) {
this.setState({trimStart: trimStart, trimEnd: trimEnd}, this.handlePlay);
}
});
}
}
handleRedo () {
const {samples, sampleRate, trimStart, trimEnd} = this.redoStack.pop();
if (samples) {
this.undoStack.push(this.getUndoItem());
this.submitNewSamples(samples, sampleRate, true);
this.setState({trimStart: trimStart, trimEnd: trimEnd}, this.handlePlay);
return this.submitNewSamples(samples, sampleRate, true).then(success => {
if (success) {
this.setState({trimStart: trimStart, trimEnd: trimEnd}, this.handlePlay);
}
});
}
}
handleCopy () {
@@ -322,25 +327,39 @@ class SoundEditor extends React.Component {
});
}
resampleBufferToRate (buffer, newRate) {
return new Promise(resolve => {
if (window.OfflineAudioContext) {
const sampleRateRatio = newRate / buffer.sampleRate;
const newLength = sampleRateRatio * buffer.samples.length;
const offlineContext = new window.OfflineAudioContext(1, newLength, newRate);
const source = offlineContext.createBufferSource();
const audioBuffer = offlineContext.createBuffer(1, buffer.samples.length, buffer.sampleRate);
audioBuffer.getChannelData(0).set(buffer.samples);
source.buffer = audioBuffer;
source.connect(offlineContext.destination);
source.start();
offlineContext.startRendering();
offlineContext.oncomplete = ({renderedBuffer}) => {
resolve({
samples: renderedBuffer.getChannelData(0),
sampleRate: newRate
});
};
return new Promise((resolve, reject) => {
const sampleRateRatio = newRate / buffer.sampleRate;
const newLength = sampleRateRatio * buffer.samples.length;
let offlineContext;
// Try to use either OfflineAudioContext or webkitOfflineAudioContext to resample
// The constructors will throw if trying to resample at an unsupported rate
// (e.g. Safari/webkitOAC does not support lower than 44khz).
try {
if (window.OfflineAudioContext) {
offlineContext = new window.OfflineAudioContext(1, newLength, newRate);
} else if (window.webkitOfflineAudioContext) {
offlineContext = new window.webkitOfflineAudioContext(1, newLength, newRate);
}
} catch {
// If no OAC available and downsampling by 2, downsample by dropping every other sample.
if (newRate === buffer.sampleRate / 2) {
return resolve(dropEveryOtherSample(buffer));
}
return reject('Could not resample');
}
const source = offlineContext.createBufferSource();
const audioBuffer = offlineContext.createBuffer(1, buffer.samples.length, buffer.sampleRate);
audioBuffer.getChannelData(0).set(buffer.samples);
source.buffer = audioBuffer;
source.connect(offlineContext.destination);
source.start();
offlineContext.startRendering();
offlineContext.oncomplete = ({renderedBuffer}) => {
resolve({
samples: renderedBuffer.getChannelData(0),
sampleRate: newRate
});
};
});
}
paste () {
@@ -351,8 +370,11 @@ class SoundEditor extends React.Component {
const newSamples = new Float32Array(newLength);
newSamples.set(samples, 0);
newSamples.set(this.state.copyBuffer.samples, samples.length);
this.submitNewSamples(newSamples, this.props.sampleRate, false);
this.handlePlay();
this.submitNewSamples(newSamples, this.props.sampleRate, false).then(success => {
if (success) {
this.handlePlay();
}
});
} else {
// else replace the selection with the pasted sound
const trimStartSamples = this.state.trimStart * samples.length;
@@ -371,11 +393,14 @@ class SoundEditor extends React.Component {
const newDurationSeconds = newSamples.length / this.state.copyBuffer.sampleRate;
const adjustedTrimStart = trimStartSeconds / newDurationSeconds;
const adjustedTrimEnd = trimEndSeconds / newDurationSeconds;
this.submitNewSamples(newSamples, this.props.sampleRate, false);
this.setState({
trimStart: adjustedTrimStart,
trimEnd: adjustedTrimEnd
}, this.handlePlay);
this.submitNewSamples(newSamples, this.props.sampleRate, false).then(success => {
if (success) {
this.setState({
trimStart: adjustedTrimStart,
trimEnd: adjustedTrimEnd
}, this.handlePlay);
}
});
}
}
handlePaste () {
-2
View File
@@ -1,6 +1,5 @@
import GUI from './containers/gui.jsx';
import AppStateHOC from './lib/app-state-hoc.jsx';
import TitledHOC from './lib/titled-hoc.jsx';
import GuiReducer, {guiInitialState, guiMiddleware, initEmbedded, initFullScreen, initPlayer} from './reducers/gui';
import LocalesReducer, {localesInitialState, initLocale} from './reducers/locales';
import {ScratchPaintReducer} from 'scratch-paint';
@@ -17,7 +16,6 @@ const guiReducers = {
export {
GUI as default,
AppStateHOC,
TitledHOC,
setAppElement,
guiReducers,
guiInitialState,
+49 -1
View File
@@ -59,9 +59,57 @@ const encodeAndAddSoundToVM = function (vm, samples, sampleRate, name, callback)
});
};
/**
@typedef SoundBuffer
@type {Object}
@property {Float32Array} samples Array of audio samples
@property {number} sampleRate Audio sample rate
*/
/**
* Downsample the given buffer to try to reduce file size below SOUND_BYTE_LIMIT
* @param {SoundBuffer} buffer - Buffer to resample
* @param {function(SoundBuffer):Promise<SoundBuffer>} resampler - resampler function
* @returns {SoundBuffer} Downsampled buffer with half the sample rate
*/
const downsampleIfNeeded = (buffer, resampler) => {
const {samples, sampleRate} = buffer;
const duration = samples.length / sampleRate;
const encodedByteLength = samples.length * 2; /* bitDepth 16 bit */
// Resolve immediately if already within byte limit
if (encodedByteLength < SOUND_BYTE_LIMIT) {
return Promise.resolve({samples, sampleRate});
}
// If encodeable at 22khz, resample and call submitNewSamples again
if (duration * 22050 * 2 < SOUND_BYTE_LIMIT) {
return resampler({samples, sampleRate}, 22050);
}
// Cannot save this sound at 22khz, refuse to edit
// In the future we could introduce further compression here
return Promise.reject('Sound too large to save, refusing to edit');
};
/**
* Drop every other sample of an audio buffer as a last-resort way of downsampling.
* @param {SoundBuffer} buffer - Buffer to resample
* @returns {SoundBuffer} Downsampled buffer with half the sample rate
*/
const dropEveryOtherSample = buffer => {
const newLength = Math.floor(buffer.samples.length / 2);
const newSamples = new Float32Array(newLength);
for (let i = 0; i < newLength; i++) {
newSamples[i] = buffer.samples[i * 2];
}
return {
samples: newSamples,
sampleRate: buffer.sampleRate / 2
};
};
export {
computeRMS,
computeChunkedRMS,
encodeAndAddSoundToVM,
SOUND_BYTE_LIMIT
downsampleIfNeeded,
dropEveryOtherSample
};
+16 -12
View File
@@ -54,13 +54,10 @@ const cloudManagerHOC = function (WrappedComponent) {
canUseCloud (props) {
return !!(props.cloudHost && props.username && props.vm && props.projectId && props.hasCloudPermission);
}
shouldNotModifyCloudData (props) {
return (props.hasEverEnteredEditor && !props.canSave);
}
shouldConnect (props) {
return !this.isConnected() && this.canUseCloud(props) &&
props.isShowingWithId && props.vm.runtime.hasCloudData() &&
!this.shouldNotModifyCloudData(props);
props.canModifyCloudData;
}
shouldDisconnect (props, prevProps) {
return this.isConnected() &&
@@ -70,7 +67,7 @@ const cloudManagerHOC = function (WrappedComponent) {
(props.projectId !== prevProps.projectId) ||
(props.username !== prevProps.username) ||
// Editing someone else's project
this.shouldNotModifyCloudData(props)
!props.canModifyCloudData
);
}
isConnected () {
@@ -102,11 +99,11 @@ const cloudManagerHOC = function (WrappedComponent) {
render () {
const {
/* eslint-disable no-unused-vars */
canModifyCloudData,
cloudHost,
projectId,
username,
hasCloudPermission,
hasEverEnteredEditor,
isShowingWithId,
onShowCloudInfo,
/* eslint-enable no-unused-vars */
@@ -124,23 +121,30 @@ const cloudManagerHOC = function (WrappedComponent) {
}
CloudManager.propTypes = {
canSave: PropTypes.bool.isRequired,
canModifyCloudData: PropTypes.bool.isRequired,
cloudHost: PropTypes.string,
hasCloudPermission: PropTypes.bool,
hasEverEnteredEditor: PropTypes.bool,
isShowingWithId: PropTypes.bool,
isShowingWithId: PropTypes.bool.isRequired,
onShowCloudInfo: PropTypes.func,
projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
username: PropTypes.string,
vm: PropTypes.instanceOf(VM).isRequired
};
const mapStateToProps = state => {
CloudManager.defaultProps = {
cloudHost: null,
hasCloudPermission: false,
onShowCloudInfo: () => {},
username: null
};
const mapStateToProps = (state, ownProps) => {
const loadingState = state.scratchGui.projectState.loadingState;
return {
hasEverEnteredEditor: state.scratchGui.mode.hasEverEnteredEditor,
isShowingWithId: getIsShowingWithId(loadingState),
projectId: state.scratchGui.projectState.projectId
projectId: state.scratchGui.projectState.projectId,
// if you're editing someone else's project, you can't modify cloud data
canModifyCloudData: (!state.scratchGui.mode.hasEverEnteredEditor || ownProps.canSave)
};
};
+6 -6
View File
@@ -178,7 +178,7 @@
},
{
"name": "Blue Sky 2 ",
"md5": "5a906c2f272b77f59f0ef207857a8b3a.svg",
"md5": "8eb8790be5507fdccf73e7c1570bbbab.svg",
"type": "backdrop",
"tags": [
"outdoors",
@@ -286,7 +286,7 @@
},
{
"name": "Circles",
"md5": "4e29033ec2b891a8f1ca21242811d403.svg",
"md5": "c9847be305920807c5597d81576dd0c4.svg",
"type": "backdrop",
"tags": [
"patterns"
@@ -491,7 +491,7 @@
},
{
"name": "Hearts",
"md5": "26d3418b2fbc1af2c5fea82e1c3df1db.svg",
"md5": "f98526ccb0eec3ac7d6c8f8ab502825e.svg",
"type": "backdrop",
"tags": [
"patterns"
@@ -1050,7 +1050,7 @@
},
{
"name": "Underwater 1",
"md5": "fb907f72b310acc8b95cbf2d2cccabc9.svg",
"md5": "d3344650f594bcecdf46aa4a9441badd.svg",
"type": "backdrop",
"tags": [
"ocean",
@@ -1175,7 +1175,7 @@
},
{
"name": "Witch House",
"md5": "597b9a9813fe5d8d387283138a0b8f2b.svg",
"md5": "30085b2d27beb5acdbe895d8b3e64b04.svg",
"type": "backdrop",
"tags": [
"fantasy",
@@ -1190,7 +1190,7 @@
},
{
"name": "Woods",
"md5": "d26cfd278999c9e37d6af75c296a58df.svg",
"md5": "f3eb165d6f3fd23370f97079f2e631bf.svg",
"type": "backdrop",
"tags": [
"fantasy",
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -13,7 +13,8 @@ const loadSpanish = () =>
.then(({esImages: imageData}) => imageData);
const translations = {
es: () => loadSpanish()
'es': () => loadSpanish(),
'es-419': () => loadSpanish()
};
const loadImageData = locale => {
File diff suppressed because it is too large. Load diff
+13973 -10065
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -433,7 +433,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
onShowCreatingRemixAlert: () => showAlertWithTimeout(dispatch, 'creatingRemix'),
onShowSaveSuccessAlert: () => showAlertWithTimeout(dispatch, 'saveSuccess'),
onShowSavingAlert: () => showAlertWithTimeout(dispatch, 'saving'),
onUpdatedProject: (projectId, loadingState) => dispatch(doneUpdatingProject(projectId, loadingState)),
onUpdatedProject: loadingState => dispatch(doneUpdatingProject(loadingState)),
setAutoSaveTimeoutId: id => dispatch(setAutoSaveTimeoutId(id))
});
// Allow incoming props to override redux-provided props. Used to mock in tests.
+2 -2
View File
@@ -4,8 +4,8 @@ const randomizeSpritePosition = spriteObject => {
const randomY = Math.floor((100 * Math.random()) - 50);
if (spriteObject.hasOwnProperty('json')) {
// Library sprite object
spriteObject.json.scratchX = randomX;
spriteObject.json.scratchY = randomY;
spriteObject.json.x = randomX;
spriteObject.json.y = randomY;
} else if (spriteObject.hasOwnProperty('x') && spriteObject.hasOwnProperty('y')) {
// Scratch 3 sprite object
spriteObject.x = randomX;
+3 -1
View File
@@ -26,7 +26,9 @@ const supportedBrowser = () => {
* always returns false
*/
const recommendedBrowser = () => !bowser.isUnsupportedBrowser(minVersions, true);
const recommendedBrowser = () =>
!bowser.isUnsupportedBrowser(minVersions, true) ||
window.navigator.userAgent.toLowerCase().indexOf('googlebot') !== -1;
export {
supportedBrowser as default,
+14 -1
View File
@@ -3,7 +3,10 @@ import React from 'react';
import {connect} from 'react-redux';
import {defineMessages, injectIntl, intlShape} from 'react-intl';
import {getIsShowingWithoutId} from '../reducers/project-state';
import {
getIsAnyCreatingNewState,
getIsShowingWithoutId
} from '../reducers/project-state';
import {setProjectTitle} from '../reducers/project-title';
const messages = defineMessages({
@@ -27,6 +30,12 @@ const TitledHOC = function (WrappedComponent) {
if (this.props.projectTitle !== prevProps.projectTitle) {
this.handleReceivedProjectTitle(this.props.projectTitle);
}
// if project is a new default project, and has loaded,
if (this.props.isShowingWithoutId && prevProps.isAnyCreatingNewState) {
// reset title to default
const defaultProjectTitle = this.handleReceivedProjectTitle();
this.props.onUpdateProjectTitle(defaultProjectTitle);
}
// if the projectTitle hasn't changed, but the reduxProjectTitle
// HAS changed, we need to report that change to the projectTitle's owner
if (this.props.reduxProjectTitle !== prevProps.reduxProjectTitle &&
@@ -40,11 +49,13 @@ const TitledHOC = function (WrappedComponent) {
newTitle = this.props.intl.formatMessage(messages.defaultProjectTitle);
}
this.props.onChangedProjectTitle(newTitle);
return newTitle;
}
render () {
const {
/* eslint-disable no-unused-vars */
intl,
isAnyCreatingNewState,
isShowingWithoutId,
onChangedProjectTitle,
// for children, we replace onUpdateProjectTitle with our own
@@ -66,6 +77,7 @@ const TitledHOC = function (WrappedComponent) {
TitledComponent.propTypes = {
intl: intlShape,
isAnyCreatingNewState: PropTypes.bool,
isShowingWithoutId: PropTypes.bool,
onChangedProjectTitle: PropTypes.func,
onUpdateProjectTitle: PropTypes.func,
@@ -80,6 +92,7 @@ const TitledHOC = function (WrappedComponent) {
const mapStateToProps = state => {
const loadingState = state.scratchGui.projectState.loadingState;
return {
isAnyCreatingNewState: getIsAnyCreatingNewState(loadingState),
isShowingWithoutId: getIsShowingWithoutId(loadingState),
reduxProjectTitle: state.scratchGui.projectTitle
};
+4 -1
View File
@@ -14,7 +14,10 @@ export default class MockAudioEffects {
this.buffer = buffer;
this.name = name;
this.process = jest.fn(done => {
this._finishProcessing = renderedBuffer => done(renderedBuffer, 0, 1);
this._finishProcessing = renderedBuffer => {
done(renderedBuffer, 0, 1);
return new Promise(resolve => setTimeout(resolve));
};
});
MockAudioEffects.instance = this;
}
+2
View File
@@ -28,6 +28,8 @@ class SeleniumHelper {
'loadUri',
'rightClickText'
]);
this.Key = webdriver.Key; // map Key constants, for sending special keys
}
elementIsVisible (element, timeoutMessage = 'elementIsVisible timed out') {
+16 -1
View File
@@ -9,6 +9,7 @@ const {
findByXpath,
getDriver,
getLogs,
Key,
loadUri,
rightClickText,
scope
@@ -185,6 +186,10 @@ describe('Working with the blocks', () => {
await clickText('costume2', scope.costumesTab);
const el = await findByXpath("//input[@value='costume2']");
await el.sendKeys('newname');
await el.sendKeys(Key.ENTER);
// wait until the updated costume appears in costume item list panel
await findByXpath("//div[contains(@class,'sprite-selector-item_is-selected_')]" +
"//div[contains(text(), 'newname')]");
// Make sure it is updated in the block menu
await clickText('Code');
@@ -201,6 +206,10 @@ describe('Working with the blocks', () => {
await clickText('costume2', scope.costumesTab);
const el = await findByXpath("//input[@value='costume2']");
await el.sendKeys('<NewCostume>');
await el.sendKeys(Key.ENTER);
// wait until the updated costume appears in costume item list panel
await findByXpath("//div[contains(@class,'sprite-selector-item_is-selected_')]" +
"//div[contains(text(), '<NewCostume>')]");
// Make sure it is updated in the block menu
await clickText('Code');
@@ -226,6 +235,9 @@ describe('Working with the blocks', () => {
.perform();
await driver.sleep(500); // Wait for thermometer menu to come up
await clickXpath('//button[@aria-label="Paint"]');
// wait until the new costume appears in costume item list panel
await findByXpath("//div[contains(@class,'sprite-selector-item_is-selected_')]" +
"//div[contains(text(), 'costume3')]");
await clickText('costume3', scope.costumesTab);
// Check that the menu has been updated
await clickText('Code');
@@ -233,11 +245,14 @@ describe('Working with the blocks', () => {
});
// Skipped because it was flakey on travis, but seems to run locally ok
test.skip('Adding a sound DOES update the default sound name in the toolbox', async () => {
test('Adding a sound DOES update the default sound name in the toolbox', async () => {
await loadUri(uri);
await clickText('Sounds');
await clickXpath('//button[@aria-label="Choose a Sound"]');
await clickText('A Bass', scope.modal); // Should close the modal
// wait until the selected sound appears in sounds item list panel
await findByXpath("//div[contains(@class,'sprite-selector-item_is-selected_')]" +
"//div[contains(text(), 'A Bass')]");
await clickText('Code');
await clickText('Sound', scope.blocksTab);
await driver.sleep(500); // Wait for scroll to finish
+1 -5
View File
@@ -193,11 +193,7 @@ describe('Working with costumes', () => {
.mouseMove(abbyElement)
.perform();
// wait for one of Abby's alternate costumes to appear
const src1 = await abbyElement.findElement({css: 'img'}).getAttribute('src');
await driver.sleep(300);
const src2 = await abbyElement.findElement({css: 'img'}).getAttribute('src');
const sourcesMatch = (src1 === src2);
await expect(sourcesMatch).toBeFalsy(); // 'src' attribute should have changed by now
await findByXpath('//img[@src="https://cdn.assets.scratch.mit.edu/internalapi/asset/45de34b47a2ce22f6f5d28bb35a44ff5.svg/get/"]');
const logs = await getLogs();
await expect(logs).toEqual([]);
});
+45
View File
@@ -0,0 +1,45 @@
import path from 'path';
import SeleniumHelper from '../helpers/selenium-helper';
const {
clickText,
clickXpath,
findByXpath,
getDriver,
Key,
loadUri
} = new SeleniumHelper();
const uri = path.resolve(__dirname, '../../build/index.html');
let driver;
describe('Project state', () => {
beforeAll(() => {
driver = getDriver();
});
afterAll(async () => {
await driver.quit();
});
test('File->New resets project title', async () => {
const defaultProjectTitle = 'Scratch Project';
await loadUri(uri);
const inputEl = await findByXpath(`//input[@value="${defaultProjectTitle}"]`);
for (let i = 0; i < defaultProjectTitle.length; i++) {
inputEl.sendKeys(Key.BACK_SPACE);
}
inputEl.sendKeys('Changed title of project');
await clickText('Costumes'); // just to blur the input
// verify that project title has changed
await clickXpath('//input[@value="Changed title of project"]');
await clickXpath(
'//div[contains(@class, "menu-bar_menu-bar-item") and ' +
'contains(@class, "menu-bar_hoverable")][span[text()="File"]]'
);
await clickXpath('//li[span[text()="New"]]');
// project title should be default again
await clickXpath(`//input[@value="${defaultProjectTitle}"]`);
});
});
+12 -12
View File
@@ -97,7 +97,7 @@ describe('Sound Editor Container', () => {
expect(vm.renameSound).toHaveBeenCalledWith(soundIndex, 'hello');
});
test('it handles an effect by submitting the result and playing', () => {
test('it handles an effect by submitting the result and playing', async () => {
const wrapper = mountWithIntl(
<SoundEditor
soundIndex={soundIndex}
@@ -106,7 +106,7 @@ describe('Sound Editor Container', () => {
);
const component = wrapper.find(SoundEditorComponent);
component.props().onReverse(); // Could be any of the effects, just testing the end result
mockAudioEffects.instance._finishProcessing(soundBuffer);
await mockAudioEffects.instance._finishProcessing(soundBuffer);
expect(mockAudioBufferPlayer.instance.play).toHaveBeenCalled();
expect(vm.updateSoundBuffer).toHaveBeenCalled();
});
@@ -202,7 +202,7 @@ describe('Sound Editor Container', () => {
expect(mockAudioEffects.instance.process).toHaveBeenCalled();
});
test('undo/redo stack state', () => {
test('undo/redo stack state', async () => {
const wrapper = mountWithIntl(
<SoundEditor
soundIndex={soundIndex}
@@ -216,40 +216,40 @@ describe('Sound Editor Container', () => {
// Submitting new samples should make it possible to undo
component.props().onFaster();
mockAudioEffects.instance._finishProcessing(soundBuffer);
await mockAudioEffects.instance._finishProcessing(soundBuffer);
wrapper.update();
component = wrapper.find(SoundEditorComponent);
expect(component.prop('canUndo')).toEqual(true);
expect(component.prop('canRedo')).toEqual(false);
// Undoing should make it possible to redo and not possible to undo again
component.props().onUndo();
await component.props().onUndo();
wrapper.update();
component = wrapper.find(SoundEditorComponent);
expect(component.prop('canUndo')).toEqual(false);
expect(component.prop('canRedo')).toEqual(true);
// Redoing should make it possible to undo and not possible to redo again
component.props().onRedo();
await component.props().onRedo();
wrapper.update();
component = wrapper.find(SoundEditorComponent);
expect(component.prop('canUndo')).toEqual(true);
expect(component.prop('canRedo')).toEqual(false);
// New submission should clear the redo stack
component.props().onUndo(); // Undo to go back to a state where redo is enabled
await component.props().onUndo(); // Undo to go back to a state where redo is enabled
wrapper.update();
component = wrapper.find(SoundEditorComponent);
expect(component.prop('canRedo')).toEqual(true);
component.props().onFaster();
mockAudioEffects.instance._finishProcessing(soundBuffer);
await mockAudioEffects.instance._finishProcessing(soundBuffer);
wrapper.update();
component = wrapper.find(SoundEditorComponent);
expect(component.prop('canRedo')).toEqual(false);
});
test('undo and redo submit new samples and play the sound', () => {
test('undo and redo submit new samples and play the sound', async () => {
const wrapper = mountWithIntl(
<SoundEditor
soundIndex={soundIndex}
@@ -260,12 +260,12 @@ describe('Sound Editor Container', () => {
// Set up an undoable state
component.props().onFaster();
mockAudioEffects.instance._finishProcessing(soundBuffer);
await mockAudioEffects.instance._finishProcessing(soundBuffer);
wrapper.update();
component = wrapper.find(SoundEditorComponent);
// Undo should update the sound buffer and play the new samples
component.props().onUndo();
await component.props().onUndo();
expect(mockAudioBufferPlayer.instance.play).toHaveBeenCalled();
expect(vm.updateSoundBuffer).toHaveBeenCalled();
@@ -274,7 +274,7 @@ describe('Sound Editor Container', () => {
mockAudioBufferPlayer.instance.play.mockClear();
// Undo should update the sound buffer and play the new samples
component.props().onRedo();
await component.props().onRedo();
expect(mockAudioBufferPlayer.instance.play).toHaveBeenCalled();
expect(vm.updateSoundBuffer).toHaveBeenCalled();
});
+51 -1
View File
@@ -1,4 +1,9 @@
import {computeRMS, computeChunkedRMS} from '../../../src/lib/audio/audio-util';
import {
computeRMS,
computeChunkedRMS,
downsampleIfNeeded,
dropEveryOtherSample
} from '../../../src/lib/audio/audio-util';
describe('computeRMS', () => {
test('returns 0 when given no samples', () => {
@@ -49,3 +54,48 @@ describe('computeChunkedRMS', () => {
expect(chunkedLevels).toEqual([Math.sqrt(1 / 0.55), Math.sqrt(1 / 0.55)]);
});
});
describe('downsampleIfNeeded', () => {
const samples = {length: 1};
const sampleRate = 44100;
test('returns given data when no downsampling needed', async () => {
samples.length = 1;
const res = await downsampleIfNeeded({samples, sampleRate}, null);
expect(res.samples).toEqual(samples);
expect(res.sampleRate).toEqual(sampleRate);
});
test('downsamples to 22050 if that puts it under the limit', async () => {
samples.length = 44100 * 3 * 60;
const resampler = jest.fn(() => 'TEST');
const res = await downsampleIfNeeded({samples, sampleRate}, resampler);
expect(resampler).toHaveBeenCalledWith({samples, sampleRate}, 22050);
expect(res).toEqual('TEST');
});
test('fails if resampling would not put it under the limit', async () => {
samples.length = 44100 * 4 * 60;
try {
await downsampleIfNeeded({samples, sampleRate}, null);
} catch (e) {
expect(e).toEqual('Sound too large to save, refusing to edit');
}
});
});
describe('dropEveryOtherSample', () => {
const buffer = {
samples: [1, 0, 2, 0, 3, 0],
sampleRate: 2
};
test('result is half the length', () => {
const {samples} = dropEveryOtherSample(buffer);
expect(samples.length).toEqual(Math.floor(buffer.samples.length / 2));
});
test('result contains only even-index items', () => {
const {samples} = dropEveryOtherSample(buffer);
expect(samples).toEqual(new Float32Array([1, 2, 3]));
});
test('result sampleRate is given sampleRate / 2', () => {
const {sampleRate} = dropEveryOtherSample(buffer);
expect(sampleRate).toEqual(buffer.sampleRate / 2);
});
});
+2 -43
View File
@@ -60,7 +60,6 @@ describe('CloudManagerHOC', () => {
mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={store}
@@ -80,7 +79,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
mount(
<WrappedComponent
canSave
hasCloudPermission
store={store}
username="user"
@@ -98,7 +96,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={store}
@@ -115,7 +112,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={stillLoadingStore}
@@ -132,7 +128,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
mount(
<WrappedComponent
canSave
cloudHost="nonEmpty"
hasCloudPermission={false}
store={store}
@@ -153,7 +148,6 @@ describe('CloudManagerHOC', () => {
const mounted = mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={stillLoadingStore}
@@ -182,7 +176,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
const mounted = mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={stillLoadingStore}
@@ -209,7 +202,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
const mounted = mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={store}
@@ -235,7 +227,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
const mounted = mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={store}
@@ -262,7 +253,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
const mounted = mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={store}
@@ -293,7 +283,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={store}
@@ -315,7 +304,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={store}
@@ -343,7 +331,6 @@ describe('CloudManagerHOC', () => {
const WrappedComponent = cloudManagerHOC(Component);
mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={store}
@@ -364,12 +351,11 @@ describe('CloudManagerHOC', () => {
});
// Editor Mode Connection/Disconnection Tests
test('Entering editor mode and can\'t save project should disconnect cloud provider # 1', () => {
test('Entering editor mode and can\'t save project should disconnect cloud provider', () => {
const Component = () => <div />;
const WrappedComponent = cloudManagerHOC(Component);
const mounted = mount(
<WrappedComponent
canSave
hasCloudPermission
cloudHost="nonEmpty"
store={store}
@@ -382,34 +368,7 @@ describe('CloudManagerHOC', () => {
const requestCloseConnection = mockCloudProviderInstance.requestCloseConnection;
mounted.setProps({
canSave: false,
hasEverEnteredEditor: true
});
expect(vm.setCloudProvider.mock.calls.length).toBe(2);
expect(vm.setCloudProvider).toHaveBeenCalledWith(null);
expect(requestCloseConnection).toHaveBeenCalledTimes(1);
});
test('Entering editor mode and can\'t save project should disconnect cloud provider # 2', () => {
const Component = () => <div />;
const WrappedComponent = cloudManagerHOC(Component);
const mounted = mount(
<WrappedComponent
hasCloudPermission
canSave={false}
cloudHost="nonEmpty"
store={store}
username="user"
vm={vm}
/>
);
expect(CloudProvider).toHaveBeenCalled();
const requestCloseConnection = mockCloudProviderInstance.requestCloseConnection;
mounted.setProps({
hasEverEnteredEditor: true
canModifyCloudData: false
});
expect(vm.setCloudProvider.mock.calls.length).toBe(2);