From ce7f3197f679eafc367134419b5ecb54107ad66b Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 21 Apr 2017 14:27:38 -0700 Subject: [PATCH] watch for announcements --- .../scripting/WindowScriptingInterface.cpp | 4 + .../src/scripting/WindowScriptingInterface.h | 2 + scripts/system/notifications.js | 5 +- scripts/system/tablet-goto.js | 109 +++++++++++++++++- 4 files changed, 116 insertions(+), 4 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 39c2f2e402..6256bd456d 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -243,6 +243,10 @@ void WindowScriptingInterface::makeConnection(bool success, const QString& userN } } +void WindowScriptingInterface::displayAnnouncement(const QString& message) { + emit announcement(message); +} + bool WindowScriptingInterface::isPhysicsEnabled() { return qApp->isPhysicsEnabled(); } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index d4ff278fea..99ccf4eed0 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -57,6 +57,7 @@ public slots: void copyToClipboard(const QString& text); void takeSnapshot(bool notify = true, bool includeAnimated = false, float aspectRatio = 0.0f); void makeConnection(bool success, const QString& userNameOrError); + void displayAnnouncement(const QString& message); void shareSnapshot(const QString& path, const QUrl& href = QUrl("")); bool isPhysicsEnabled(); @@ -78,6 +79,7 @@ signals: void connectionAdded(const QString& connectionName); void connectionError(const QString& errorString); + void announcement(const QString& message); void messageBoxClosed(int id, int button); diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 006ef3f90f..c08cb44c0c 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -188,10 +188,10 @@ function fadeOut(noticeOut, buttonOut, arraysOut) { pauseTimer = Script.setInterval(function () { r -= 1; - rFade = r / 10.0; + rFade = Math.max(0.0, r / 10.0); Overlays.editOverlay(noticeOut, { alpha: rFade }); Overlays.editOverlay(buttonOut, { alpha: rFade }); - if (r < 0) { + if (r <= 0) { dismiss(noticeOut, buttonOut, arraysOut); arrays.splice(arraysOut, 1); ready = true; @@ -660,6 +660,7 @@ Window.stillSnapshotTaken.connect(onSnapshotTaken); Window.processingGifStarted.connect(processingGif); Window.connectionAdded.connect(connectionAdded); Window.connectionError.connect(connectionError); +Window.announcement.connect(onNotify); Window.notifyEditError = onEditError; Window.notify = onNotify; Tablet.tabletNotification.connect(tabletNotification); diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 84f7357b1a..3bb8c746c7 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -33,6 +33,7 @@ onGotoScreen = true; shouldActivateButton = true; button.editProperties({isActive: shouldActivateButton}); + messagesWaiting(false); } else { shouldActivateButton = false; onGotoScreen = false; @@ -41,17 +42,121 @@ } var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var NORMAL_ICON = "icons/tablet-icons/goto-i.svg"; + var NORMAL_ACTIVE = "icons/tablet-icons/goto-a.svg"; + var WAITING_ICON = "icons/tablet-icons/help-i.svg"; // To be changed when we get the artwork. + var WAITING_ACTIVE = "icons/tablet-icons/help-a.svg"; var button = tablet.addButton({ - icon: "icons/tablet-icons/goto-i.svg", - activeIcon: "icons/tablet-icons/goto-a.svg", + icon: NORMAL_ICON, + activeIcon: NORMAL_ACTIVE, text: buttonName, sortOrder: 8 }); + function messagesWaiting(isWaiting) { + button.editProperties({ + icon: isWaiting ? WAITING_ICON : NORMAL_ICON, + activeIcon: isWaiting ? WAITING_ACTIVE : NORMAL_ACTIVE + }); + } button.clicked.connect(onClicked); tablet.screenChanged.connect(onScreenChanged); + var METAVERSE_BASE = location.metaverseServerUrl; + function request(options, callback) { // cb(error, responseOfCorrectContentType) of url. A subset of npm request. + var httpRequest = new XMLHttpRequest(), key; + // QT bug: apparently doesn't handle onload. Workaround using readyState. + httpRequest.onreadystatechange = function () { + var READY_STATE_DONE = 4; + var HTTP_OK = 200; + if (httpRequest.readyState >= READY_STATE_DONE) { + var error = (httpRequest.status !== HTTP_OK) && httpRequest.status.toString() + ':' + httpRequest.statusText, + response = !error && httpRequest.responseText, + contentType = !error && httpRequest.getResponseHeader('content-type'); + if (!error && contentType.indexOf('application/json') === 0) { // ignoring charset, etc. + try { + response = JSON.parse(response); + } catch (e) { + error = e; + } + } + callback(error, response); + } + }; + if (typeof options === 'string') { + options = {uri: options}; + } + if (options.url) { + options.uri = options.url; + } + if (!options.method) { + options.method = 'GET'; + } + if (options.body && (options.method === 'GET')) { // add query parameters + var params = [], appender = (-1 === options.uri.search('?')) ? '?' : '&'; + for (key in options.body) { + params.push(key + '=' + options.body[key]); + } + options.uri += appender + params.join('&'); + delete options.body; + } + if (options.json) { + options.headers = options.headers || {}; + options.headers["Content-type"] = "application/json"; + options.body = JSON.stringify(options.body); + } + for (key in options.headers || {}) { + httpRequest.setRequestHeader(key, options.headers[key]); + } + httpRequest.open(options.method, options.uri, true); + httpRequest.send(options.body); + } + + var stories = {}; + var DEBUG = false; + function pollForAnnouncements() { + var actions = DEBUG ? 'snapshot' : 'announcement'; + var count = DEBUG ? 10 : 100; + var options = [ + 'now=' + new Date().toISOString(), + 'include_actions=' + actions, + 'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'), + 'require_online=true', + 'protocol=' + encodeURIComponent(location.protocolVersion()), + 'per_page=' + count + ]; + var url = location.metaverseServerUrl + '/api/v1/user_stories?' + options.join('&'); + request({ + uri: url + }, function (error, data) { + if (error || (data.status !== 'success')) { + print("Error: unable to get", url, error || response.status); + return; + } + var didNotify = false; + data.user_stories.forEach(function (story) { + if (stories[story.id]) { // already seen + return; + } + stories[story.id] = story; + var message = story.username + " says something is happending in " + story.place_name + ". Open GOTO to join them."; + Window.displayAnnouncement(message); + didNotify = true; + }); + if (didNotify) { + messagesWaiting(true); + if (HMD.isHandControllerAvailable()) { + var STRENGTH = 1.0, DURATION_MS = 60, HAND = 2; // both hands + Controller.triggerHapticPulse(STRENGTH, DURATION_MS, HAND); + } + } + }); + } + var ANNOUNCEMENTS_POLL_TIME_MS = (DEBUG ? 10 : 60) * 1000; + var pollTimer = Script.setInterval(pollForAnnouncements, ANNOUNCEMENTS_POLL_TIME_MS); + Script.scriptEnding.connect(function () { + Script.clearInterval(pollTimer); button.clicked.disconnect(onClicked); tablet.removeButton(button); tablet.screenChanged.disconnect(onScreenChanged);