diff --git a/interface/resources/icons/loadingDark.gif b/interface/resources/icons/loadingDark.gif new file mode 100644 index 0000000000..1fc22dc637 Binary files /dev/null and b/interface/resources/icons/loadingDark.gif differ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 99af5b1578..9c523f53e8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6417,7 +6417,7 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa // If we're not doing an animated snapshot as well... if (!includeAnimated || !(SnapshotAnimated::alsoTakeAnimatedSnapshot.get())) { // Tell the dependency manager that the capture of the still snapshot has taken place. - emit DependencyManager::get()->snapshotTaken(path, "", notify); + emit DependencyManager::get()->stillSnapshotTaken(path, notify); } else { // Get an animated GIF snapshot and save it SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get()); diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index b7bed7d85f..d4ff278fea 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -71,9 +71,10 @@ signals: void domainChanged(const QString& domainHostname); void svoImportRequested(const QString& url); void domainConnectionRefused(const QString& reasonMessage, int reasonCode, const QString& extraInfo); - void snapshotTaken(const QString& pathStillSnapshot, const QString& pathAnimatedSnapshot, bool notify); + void stillSnapshotTaken(const QString& pathStillSnapshot, bool notify); void snapshotShared(const QString& error); - void processingGif(); + void processingGifStarted(const QString& pathStillSnapshot); + void processingGifCompleted(const QString& pathAnimatedSnapshot); void connectionAdded(const QString& connectionName); void connectionError(const QString& errorString); diff --git a/interface/src/ui/SnapshotAnimated.cpp b/interface/src/ui/SnapshotAnimated.cpp index cf89504d92..70767b007d 100644 --- a/interface/src/ui/SnapshotAnimated.cpp +++ b/interface/src/ui/SnapshotAnimated.cpp @@ -86,7 +86,8 @@ void SnapshotAnimated::captureFrames() { SnapshotAnimated::snapshotAnimatedTimerRunning = false; // Notify the user that we're processing the snapshot - emit SnapshotAnimated::snapshotAnimatedDM->processingGif(); + // This also pops up the "Share" dialog. The unprocessed GIF will be visualized as a loading icon until processingGifCompleted() is called. + emit SnapshotAnimated::snapshotAnimatedDM->processingGifStarted(SnapshotAnimated::snapshotStillPath); // Kick off the thread that'll pack the frames into the GIF QtConcurrent::run(processFrames); @@ -132,7 +133,7 @@ void SnapshotAnimated::processFrames() { // Reset the current frame timestamp SnapshotAnimated::snapshotAnimatedTimestamp = 0; SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = 0; - - // Let the window scripting interface know that the snapshots have been taken. - emit SnapshotAnimated::snapshotAnimatedDM->snapshotTaken(SnapshotAnimated::snapshotStillPath, SnapshotAnimated::snapshotAnimatedPath, false); + + // Update the "Share" dialog with the processed GIF. + emit SnapshotAnimated::snapshotAnimatedDM->processingGifCompleted(SnapshotAnimated::snapshotAnimatedPath); } diff --git a/scripts/system/html/js/SnapshotReview.js b/scripts/system/html/js/SnapshotReview.js index d97207384a..4e2e0223a0 100644 --- a/scripts/system/html/js/SnapshotReview.js +++ b/scripts/system/html/js/SnapshotReview.js @@ -21,6 +21,7 @@ function addImage(data) { img = document.createElement("IMG"), div2 = document.createElement("DIV"), id = "p" + idCounter++; + img.id = id + "img"; function toggle() { data.share = input.checked; } div.style.height = "" + Math.floor(100 / imageCount) + "%"; if (imageCount > 1) { @@ -33,7 +34,7 @@ function addImage(data) { label.setAttribute('for', id); // cannot do label.for = input.id = id; input.type = "checkbox"; - input.checked = (id === "p0"); + input.checked = false; data.share = input.checked; input.addEventListener('change', toggle); div2.setAttribute("class", "property checkbox"); @@ -46,9 +47,9 @@ function addImage(data) { document.getElementById("snapshot-images").appendChild(div); paths.push(data); } -function handleShareButtons(shareMsg) { +function handleShareButtons(messageOptions) { var openFeed = document.getElementById('openFeed'); - openFeed.checked = shareMsg.openFeedAfterShare; + openFeed.checked = messageOptions.openFeedAfterShare; openFeed.onchange = function () { EventBridge.emitWebEvent(JSON.stringify({ type: "snapshot", @@ -56,7 +57,7 @@ function handleShareButtons(shareMsg) { })); }; - if (!shareMsg.canShare) { + if (!messageOptions.canShare) { // this means you may or may not be logged in, but can't share // because you are not in a public place. document.getElementById("sharing").innerHTML = "

Snapshots can be shared when they're taken in shareable places."; @@ -74,13 +75,26 @@ window.onload = function () { return; } - // last element of list contains a bool for whether or not we can share stuff - var shareMsg = message.action.pop(); - handleShareButtons(shareMsg); - - // rest are image paths which we add - imageCount = message.action.length; - message.action.forEach(addImage); + // The last element of the message contents list contains a bunch of options, + // including whether or not we can share stuff + // The other elements of the list contain image paths. + var messageOptions = message.action.pop(); + handleShareButtons(messageOptions); + + if (messageOptions.containsGif) { + if (messageOptions.processingGif) { + imageCount = message.action.length + 1; // "+1" for the GIF that'll finish processing soon + message.action.unshift({ localPath: '../../../resources/icons/loadingDark.gif' }); + message.action.forEach(addImage); + document.getElementById('p0').disabled = true; + } else { + document.getElementById('p0').disabled = false; + document.getElementById('p0img').src = message.action[0].localPath; + } + } else { + imageCount = message.action.length; + message.action.forEach(addImage); + } }); EventBridge.emitWebEvent(JSON.stringify({ type: "snapshot", diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 25a5edf3a3..006ef3f90f 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -532,7 +532,7 @@ function onNotify(msg) { createNotification(wordWrap(msg), NotificationType.UNKNOWN); // Needs a generic notification system for user feedback, thus using this } -function onSnapshotTaken(pathStillSnapshot, pathAnimatedSnapshot, notify) { +function onSnapshotTaken(pathStillSnapshot, notify) { if (notify) { var imageProperties = { path: "file:///" + pathStillSnapshot, @@ -656,8 +656,8 @@ Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); Menu.menuItemEvent.connect(menuItemEvent); Window.domainConnectionRefused.connect(onDomainConnectionRefused); -Window.snapshotTaken.connect(onSnapshotTaken); -Window.processingGif.connect(processingGif); +Window.stillSnapshotTaken.connect(onSnapshotTaken); +Window.processingGifStarted.connect(processingGif); Window.connectionAdded.connect(connectionAdded); Window.connectionError.connect(connectionError); Window.notifyEditError = onEditError; diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 76f72d97e1..ee441278aa 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -157,7 +157,9 @@ function onClicked() { resetOverlays = Menu.isOptionChecked("Overlays"); // For completness. Certainly true if the button is visible to be clicke. reticleVisible = Reticle.visible; Reticle.visible = false; - Window.snapshotTaken.connect(resetButtons); + Window.stillSnapshotTaken.connect(stillSnapshotTaken); + Window.processingGifStarted.connect(processingGifStarted); + Window.processingGifCompleted.connect(processingGifCompleted); // hide overlays if they are on if (resetOverlays) { @@ -193,25 +195,14 @@ function isDomainOpen(id) { response.total_entries; } -function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) { - // If we're not taking an animated snapshot, we have to show the HUD. - // If we ARE taking an animated snapshot, we've already re-enabled the HUD by this point. - if (pathAnimatedSnapshot === "") { - // show hud - - Reticle.visible = reticleVisible; - // show overlays if they were on - if (resetOverlays) { - Menu.setIsOptionChecked("Overlays", true); - } - } else { - // Allow the user to click the snapshot HUD button again - if (!buttonConnected) { - button.clicked.connect(onClicked); - buttonConnected = true; - } +function stillSnapshotTaken(pathStillSnapshot, notify) { + // show hud + Reticle.visible = reticleVisible; + // show overlays if they were on + if (resetOverlays) { + Menu.setIsOptionChecked("Overlays", true); } - Window.snapshotTaken.disconnect(resetButtons); + Window.stillSnapshotTaken.disconnect(stillSnapshotTaken); // A Snapshot Review dialog might be left open indefinitely after taking the picture, // during which time the user may have moved. So stash that info in the dialog so that @@ -220,12 +211,11 @@ function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) { var confirmShareContents = [ { localPath: pathStillSnapshot, href: href }, { + containsGif: false, + processingGif: false, canShare: !!isDomainOpen(domainId), openFeedAfterShare: shouldOpenFeedAfterShare() }]; - if (pathAnimatedSnapshot !== "") { - confirmShareContents.unshift({ localPath: pathAnimatedSnapshot, href: href }); - } confirmShare(confirmShareContents); if (clearOverlayWhenMoving) { MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog @@ -233,15 +223,51 @@ function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) { HMD.openTablet(); } -function processingGif() { - // show hud - Reticle.visible = reticleVisible; +function processingGifStarted(pathStillSnapshot) { + Window.processingGifStarted.disconnect(processingGifStarted); button.clicked.disconnect(onClicked); buttonConnected = false; + // show hud + Reticle.visible = reticleVisible; // show overlays if they were on if (resetOverlays) { Menu.setIsOptionChecked("Overlays", true); } + + var confirmShareContents = [ + { localPath: pathStillSnapshot, href: href }, + { + containsGif: true, + processingGif: true, + canShare: !!isDomainOpen(domainId), + openFeedAfterShare: shouldOpenFeedAfterShare() + }]; + confirmShare(confirmShareContents); + if (clearOverlayWhenMoving) { + MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog + } + HMD.openTablet(); +} + +function processingGifCompleted(pathAnimatedSnapshot) { + Window.processingGifCompleted.disconnect(processingGifCompleted); + button.clicked.connect(onClicked); + buttonConnected = true; + + var confirmShareContents = [ + { localPath: pathAnimatedSnapshot, href: href }, + { + containsGif: true, + processingGif: false, + canShare: !!isDomainOpen(domainId), + openFeedAfterShare: shouldOpenFeedAfterShare() + }]; + readyData = confirmShareContents; + + tablet.emitScriptEvent(JSON.stringify({ + type: "snapshot", + action: readyData + })); } function onTabletScreenChanged(type, url) { @@ -265,7 +291,6 @@ function onConnected() { button.clicked.connect(onClicked); buttonConnected = true; Window.snapshotShared.connect(snapshotShared); -Window.processingGif.connect(processingGif); tablet.screenChanged.connect(onTabletScreenChanged); Account.usernameChanged.connect(onConnected); Script.scriptEnding.connect(function () { @@ -277,7 +302,6 @@ Script.scriptEnding.connect(function () { tablet.removeButton(button); } Window.snapshotShared.disconnect(snapshotShared); - Window.processingGif.disconnect(processingGif); tablet.screenChanged.disconnect(onTabletScreenChanged); });