From a97f9eb79aeccf423517c099d12f3c4daf319cb8 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 12:28:03 -0700 Subject: [PATCH 01/17] Logic for Wallet notifications; some bugfixes --- scripts/modules/appUi.js | 18 +++-- scripts/modules/request.js | 4 +- scripts/system/commerce/wallet.js | 106 +++++++++++++++++++++++++++++- scripts/system/pal.js | 22 ++++--- 4 files changed, 131 insertions(+), 19 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index dab377911b..98f6dad1f9 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -155,8 +155,8 @@ function AppUi(properties) { return; } - // User is "appearing offline" - if (GlobalServices.findableBy === "none") { + // User is "appearing offline", or is offline, or the app is open + if (GlobalServices.findableBy === "none" || Account.username === "" || that.isOpen) { that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs); return; } @@ -164,7 +164,10 @@ function AppUi(properties) { var url = METAVERSE_BASE + that.notificationPollEndpoint; if (that.notificationPollCaresAboutSince) { - url = url + "&since=" + (new Date().getTime()); + var settingsKey = "notifications/" + that.buttonName + "/lastSince"; + var timestamp = Settings.getValue(settingsKey, new Date().getTime()); + url = url + "&since=" + timestamp; + Settings.setValue(settingsKey, timestamp); } console.debug(that.buttonName, 'polling for notifications at endpoint', url); @@ -203,7 +206,8 @@ function AppUi(properties) { // This won't do anything if there isn't a notification endpoint set that.notificationPoll(); - function availabilityChanged() { + function restartNotificationPoll() { + that.notificationInitialCallbackMade = false; if (that.notificationPollTimeout) { Script.clearTimeout(that.notificationPollTimeout); that.notificationPollTimeout = false; @@ -303,7 +307,8 @@ function AppUi(properties) { } : that.ignore; that.onScriptEnding = function onScriptEnding() { // Close if necessary, clean up any remaining handlers, and remove the button. - GlobalServices.findableByChanged.disconnect(availabilityChanged); + GlobalServices.myUsernameChanged.disconnect(restartNotificationPoll); + GlobalServices.findableByChanged.disconnect(restartNotificationPoll); if (that.isOpen) { that.close(); } @@ -323,6 +328,7 @@ function AppUi(properties) { that.tablet.screenChanged.connect(that.onScreenChanged); that.button.clicked.connect(that.onClicked); Script.scriptEnding.connect(that.onScriptEnding); - GlobalServices.findableByChanged.connect(availabilityChanged); + GlobalServices.findableByChanged.connect(restartNotificationPoll); + GlobalServices.myUsernameChanged.connect(restartNotificationPoll); } module.exports = AppUi; diff --git a/scripts/modules/request.js b/scripts/modules/request.js index 3516554567..d0037f9b43 100644 --- a/scripts/modules/request.js +++ b/scripts/modules/request.js @@ -19,7 +19,7 @@ module.exports = { // ------------------------------------------------------------------ request: function (options, callback) { // cb(error, responseOfCorrectContentType) of url. A subset of npm request. - var httpRequest = new XMLHttpRequest(), key; + var httpRequest = new XMLHttpRequest(), key; // QT bug: apparently doesn't handle onload. Workaround using readyState. httpRequest.onreadystatechange = function () { var READY_STATE_DONE = 4; @@ -72,7 +72,7 @@ module.exports = { } httpRequest.open(options.method, options.uri, true); httpRequest.send(options.body || null); - } + } }; // =========================================================================================== diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 993ea30c2e..26b8f95bd5 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -491,12 +491,110 @@ function walletOpened() { Controller.mouseMoveEvent.connect(handleMouseMoveEvent); triggerMapping.enable(); triggerPressMapping.enable(); + ui.messagesWaiting(false); } function walletClosed() { off(); } +function notificationDataProcessPage(data) { + return data.data.history; +} + +var shouldShowDot = false; +function notificationPollCallback(historyArray) { + var i; + var someoneElsePurchasedArray = []; + var proofIssuedArray = []; + var moneyReceivedArray = []; + var giftReceivedArray = []; + for (i = 0; i < historyArray.length; i++) { + var currentHistoryTxn = historyArray[i]; + + if (currentHistoryTxn.sent_certs <= 0 && + currentHistoryTxn.received_certs <= 0) { + // This is an HFC transfer. + if (currentHistoryTxn.received_money > 0) { + if (currentHistoryTxn.sender_name === "marketplace") { + someoneElsePurchasedArray.push(currentHistoryTxn); + } else { + moneyReceivedArray.push(currentHistoryTxn); + } + } + } else if (currentHistoryTxn.sent_money <= 0 && + currentHistoryTxn.received_money <= 0 && + currentHistoryTxn.received_certs > 0) { + // This is a non-HFC asset transfer. + if (currentHistoryTxn.sender_name === "marketplace") { + proofIssuedArray.push(currentHistoryTxn); + } else { + giftReceivedArray.push(currentHistoryTxn); + } + } + } + + if (!ui.isOpen) { + shouldShowDot = shouldShowDot || + (someoneElsePurchasedArray.length > 0) || + (proofIssuedArray.length > 0) || + (moneyReceivedArray.length > 0) || + (giftReceivedArray.length > 0); + ui.messagesWaiting(shouldShowDot); + + var notificationCount = someoneElsePurchasedArray.length + + proofIssuedArray.length + + moneyReceivedArray.length + + giftReceivedArray.length; + + if (notificationCount > 0) { + var message; + if (!ui.notificationInitialCallbackMade) { + message = "You have " + notificationCount + " unread wallet " + + "notification" + (notificationCount === 1 ? "" : "s") + "! Open WALLET to see all activity."; + ui.notificationDisplayBanner(message); + } else { + var currentItemName, senderName; + for (i = 0; i < someoneElsePurchasedArray.length; i++) { + currentItemName = (someoneElsePurchasedArray[i].message).match('(.*)')[1]; + message = "Someone purchased your item \"" + currentItemName + "\" from the Marketplace! " + + "Open WALLET to see all activity."; + ui.notificationDisplayBanner(message); + } + for (i = 0; i < proofIssuedArray.length; i++) { + currentItemName = (proofIssuedArray[i].message).match('(.*)')[1]; + message = "You have been issued a proof for your Marketplace item \"" + currentItemName + "\"! " + + "Open WALLET to see all activity."; + ui.notificationDisplayBanner(message); + } + for (i = 0; i < moneyReceivedArray.length; i++) { + senderName = moneyReceivedArray[i].sender_name; + if (senderName === "") { + senderName = "Someone"; + } + message = senderName + " sent you " + moneyReceivedArray[i].received_money + " HFC! " + + "Open WALLET to see all activity."; + ui.notificationDisplayBanner(message); + } + for (i = 0; i < giftReceivedArray.length; i++) { + senderName = giftReceivedArray[i].sender_name; + if (senderName === "") { + senderName = "Someone"; + } + message = senderName + " sent you a gift! " + + "Open WALLET to see all activity."; + ui.notificationDisplayBanner(message); + } + } + } + } +} + +function isReturnedDataEmpty(data) { + var historyArray = data.data.history; + return historyArray.length === 0; +} + // // Manage the connection between the button and the window. // @@ -510,7 +608,13 @@ function startup() { home: WALLET_QML_SOURCE, onOpened: walletOpened, onClosed: walletClosed, - onMessage: fromQml + onMessage: fromQml, + notificationPollEndpoint: "/api/v1/notifications?source=commerce-history&per_page=10", + notificationPollTimeoutMs: 60000, + notificationDataProcessPage: notificationDataProcessPage, + notificationPollCallback: notificationPollCallback, + notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, + notificationPollCaresAboutSince: true }); GlobalServices.myUsernameChanged.connect(onUsernameChanged); } diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 1be5b44786..38359fbab9 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -874,16 +874,18 @@ function notificationPollCallback(connectionsArray) { shouldShowDot: shouldShowDot }); - var message; - if (!ui.notificationInitialCallbackMade) { - message = newlyOnlineConnectionsArray.length + " of your connections " + - (newlyOnlineConnectionsArray.length === 1 ? "is" : "are") + " online. Open PEOPLE to join them!"; - ui.notificationDisplayBanner(message); - } else { - for (i = 0; i < newlyOnlineConnectionsArray.length; i++) { - message = newlyOnlineConnectionsArray[i].username + " is available in " + - newlyOnlineConnectionsArray[i].location.root.name + ". Open PEOPLE to join them!"; + if (newlyOnlineConnectionsArray.length > 0) { + var message; + if (!ui.notificationInitialCallbackMade) { + message = newlyOnlineConnectionsArray.length + " of your connections " + + (newlyOnlineConnectionsArray.length === 1 ? "is" : "are") + " online! Open PEOPLE to join them."; ui.notificationDisplayBanner(message); + } else { + for (i = 0; i < newlyOnlineConnectionsArray.length; i++) { + message = newlyOnlineConnectionsArray[i].username + " is available in " + + newlyOnlineConnectionsArray[i].location.root.name + "! Open PEOPLE to join them."; + ui.notificationDisplayBanner(message); + } } } } @@ -902,7 +904,7 @@ function startup() { onOpened: palOpened, onClosed: off, onMessage: fromQml, - notificationPollEndpoint: "/api/v1/users?filter=connections&per_page=10", + notificationPollEndpoint: "/api/v1/notifications?source=users&filter=connections&per_page=10", notificationPollTimeoutMs: 60000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, From 04b44d05942d3247ccf5f6eaf523432ec64e7e29 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 12:38:33 -0700 Subject: [PATCH 02/17] Fix small since bug --- scripts/modules/appUi.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index 98f6dad1f9..b8e5cc45f9 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -165,9 +165,10 @@ function AppUi(properties) { if (that.notificationPollCaresAboutSince) { var settingsKey = "notifications/" + that.buttonName + "/lastSince"; - var timestamp = Settings.getValue(settingsKey, new Date().getTime()); - url = url + "&since=" + timestamp; - Settings.setValue(settingsKey, timestamp); + var currentTimestamp = new Date().getTime(); + var settingsTimestamp = Settings.getValue(settingsKey, currentTimestamp); + url = url + "&since=" + settingsTimestamp; + Settings.setValue(settingsKey, currentTimestamp); } console.debug(that.buttonName, 'polling for notifications at endpoint', url); From 55a0f77697bb66190b8b8086df14ddb24ad27716 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 14:45:14 -0700 Subject: [PATCH 03/17] Notifications for MARKET --- .../qml/hifi/commerce/wallet/WalletHome.qml | 8 ---- scripts/modules/appUi.js | 10 ++-- scripts/system/commerce/wallet.js | 3 -- scripts/system/marketplaces/marketplaces.js | 46 +++++++++++++++++-- 4 files changed, 47 insertions(+), 20 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 50208793fe..627da1d43f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -45,14 +45,6 @@ Item { onHistoryResult : { transactionHistoryModel.handlePage(null, result); } - - onAvailableUpdatesResult: { - if (result.status !== 'success') { - console.log("Failed to get Available Updates", result.data.message); - } else { - sendToScript({method: 'wallet_availableUpdatesReceived', numUpdates: result.data.updates.length }); - } - } } Connections { diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index b8e5cc45f9..c7f6cc5f39 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -163,13 +163,13 @@ function AppUi(properties) { var url = METAVERSE_BASE + that.notificationPollEndpoint; + var settingsKey = "notifications/" + that.buttonName + "/lastPoll"; + var currentTimestamp = new Date().getTime(); + var lastPollTimestamp = Settings.getValue(settingsKey, currentTimestamp); if (that.notificationPollCaresAboutSince) { - var settingsKey = "notifications/" + that.buttonName + "/lastSince"; - var currentTimestamp = new Date().getTime(); - var settingsTimestamp = Settings.getValue(settingsKey, currentTimestamp); - url = url + "&since=" + settingsTimestamp; - Settings.setValue(settingsKey, currentTimestamp); + url = url + "&since=" + lastPollTimestamp; } + Settings.setValue(settingsKey, currentTimestamp); console.debug(that.buttonName, 'polling for notifications at endpoint', url); diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 26b8f95bd5..a896bd4071 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -474,9 +474,6 @@ function fromQml(message) { Window.location = "hifi://BankOfHighFidelity"; } break; - case 'wallet_availableUpdatesReceived': - // NOP - break; case 'http.request': // Handled elsewhere, don't log. break; diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 13ad1f6b69..1bb0713f50 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -908,10 +908,9 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { removeOverlays(); } break; - case 'wallet_availableUpdatesReceived': case 'purchases_availableUpdatesReceived': - userHasUpdates = message.numUpdates > 0; - ui.messagesWaiting(userHasUpdates); + shouldShowDot = message.numUpdates > 0; + ui.messagesWaiting(shouldShowDot); break; case 'purchases_updateWearables': var currentlyWornWearables = []; @@ -1030,6 +1029,39 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) { "\nNew screen URL: " + url + "\nCurrent app open status: " + ui.isOpen + "\n"); }; +function notificationDataProcessPage(data) { + return data.data.updates; +} + +var shouldShowDot = false; +function notificationPollCallback(updatesArray) { + shouldShowDot = shouldShowDot || updatesArray.length > 0; + ui.messagesWaiting(shouldShowDot); + + if (updatesArray.length > 0) { + var message; + if (!ui.notificationInitialCallbackMade) { + message = updatesArray.length + " of your purchased items have updates available! " + + "Open MARKET to update."; + ui.notificationDisplayBanner(message); + + ui.notificationPollCaresAboutSince = true; + } else { + for (var i = 0; i < updatesArray.length; i++) { + message = "There's an update available for your version of \"" + + updatesArray[i].marketplace_item_name + "\"!" + + "Open MARKET to update."; + ui.notificationDisplayBanner(message); + } + } + } +} + +function isReturnedDataEmpty(data) { + var historyArray = data.data.updates; + return historyArray.length === 0; +} + // // Manage the connection between the button and the window. // @@ -1044,7 +1076,13 @@ function startup() { inject: MARKETPLACES_INJECT_SCRIPT_URL, home: MARKETPLACE_URL_INITIAL, onScreenChanged: onTabletScreenChanged, - onMessage: onQmlMessageReceived + onMessage: onQmlMessageReceived, + notificationPollEndpoint: "/api/v1/notifications?source=commerce-available_updates&per_page=10", + notificationPollTimeoutMs: 60000, + notificationDataProcessPage: notificationDataProcessPage, + notificationPollCallback: notificationPollCallback, + notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, + notificationPollCaresAboutSince: false // Changes to true after first poll }); ContextOverlay.contextOverlayClicked.connect(openInspectionCertificateQML); Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged); From 498716470641908c61e39bb0ca52583d282a8002 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 15:30:43 -0700 Subject: [PATCH 04/17] Notifications for GOTO (using a cool algorithm) --- scripts/system/commerce/wallet.js | 9 +- scripts/system/tablet-goto.js | 193 +++++++++++++++--------------- 2 files changed, 99 insertions(+), 103 deletions(-) diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index a896bd4071..2f3f5c109d 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -532,17 +532,12 @@ function notificationPollCallback(historyArray) { } if (!ui.isOpen) { - shouldShowDot = shouldShowDot || - (someoneElsePurchasedArray.length > 0) || - (proofIssuedArray.length > 0) || - (moneyReceivedArray.length > 0) || - (giftReceivedArray.length > 0); - ui.messagesWaiting(shouldShowDot); - var notificationCount = someoneElsePurchasedArray.length + proofIssuedArray.length + moneyReceivedArray.length + giftReceivedArray.length; + shouldShowDot = shouldShowDot || notificationCount > 0; + ui.messagesWaiting(shouldShowDot); if (notificationCount > 0) { var message; diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 804f838d04..26099828dc 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -15,118 +15,119 @@ // (function () { // BEGIN LOCAL_SCOPE -var request = Script.require('request').request; var AppUi = Script.require('appUi'); -var DEBUG = false; -function debug() { - if (!DEBUG) { - return; - } - print('tablet-goto.js:', [].map.call(arguments, JSON.stringify)); -} - -var stories = {}, pingPong = false; -function expire(id) { - var options = { - uri: Account.metaverseServerURL + '/api/v1/user_stories/' + id, - method: 'PUT', - json: true, - body: {expire: "true"} - }; - request(options, function (error, response) { - debug('expired story', options, 'error:', error, 'response:', response); - if (error || (response.status !== 'success')) { - print("ERROR expiring story: ", error || response.status); - } - }); -} -var PER_PAGE_DEBUG = 10; -var PER_PAGE_NORMAL = 100; -function pollForAnnouncements() { - // We could bail now if !Account.isLoggedIn(), but what if we someday have system-wide announcments? - var actions = 'announcement'; - var count = DEBUG ? PER_PAGE_DEBUG : PER_PAGE_NORMAL; - var options = [ - 'now=' + new Date().toISOString(), - 'include_actions=' + actions, - 'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'), - 'require_online=true', - 'protocol=' + encodeURIComponent(Window.protocolSignature()), - 'per_page=' + count - ]; - var url = Account.metaverseServerURL + '/api/v1/user_stories?' + options.join('&'); - request({ - uri: url - }, function (error, data) { - debug(url, error, data); - if (error || (data.status !== 'success')) { - print("Error: unable to get", url, error || data.status); - return; - } - var didNotify = false, key; - pingPong = !pingPong; - data.user_stories.forEach(function (story) { - var stored = stories[story.id], storedOrNew = stored || story; - debug('story exists:', !!stored, storedOrNew); - if ((storedOrNew.username === Account.username) && (storedOrNew.place_name !== location.placename)) { - if (storedOrNew.audience === 'for_connections') { // Only expire if we haven't already done so. - expire(story.id); - } - return; // before marking - } - storedOrNew.pingPong = pingPong; - if (stored) { // already seen - return; - } - stories[story.id] = story; - var message = story.username + " " + story.action_string + " in " + - story.place_name + ". Open GOTO to join them."; - Window.displayAnnouncement(message); - didNotify = true; - }); - for (key in stories) { // Any story we were tracking that was not marked, has expired. - if (stories[key].pingPong !== pingPong) { - debug('removing story', key); - delete stories[key]; - } - } - if (didNotify) { - ui.messagesWaiting(true); - if (HMD.isHandControllerAvailable()) { - var STRENGTH = 1.0, DURATION_MS = 60, HAND = 2; // both hands - Controller.triggerHapticPulse(STRENGTH, DURATION_MS, HAND); - } - } else if (!Object.keys(stories).length) { // If there's nothing being tracked, then any messageWaiting has expired. - ui.messagesWaiting(false); - } - }); -} -var MS_PER_SEC = 1000; -var DEBUG_POLL_TIME_SEC = 10; -var NORMAL_POLL_TIME_SEC = 60; -var ANNOUNCEMENTS_POLL_TIME_MS = (DEBUG ? DEBUG_POLL_TIME_SEC : NORMAL_POLL_TIME_SEC) * MS_PER_SEC; -var pollTimer = Script.setInterval(pollForAnnouncements, ANNOUNCEMENTS_POLL_TIME_MS); function gotoOpened() { ui.messagesWaiting(false); } +function notificationDataProcessPage(data) { + return data.user_stories; +} + +var shouldShowDot = false; +var pingPong = false; +var storedAnnouncements = {}; +var storedFeaturedStories = {}; +function notificationPollCallback(userStoriesArray) { + // + // START logic for keeping track of new info + // + pingPong = !pingPong; + var totalCountedStories = 0; + userStoriesArray.forEach(function (story) { + if (story.audience !== "for_connections" && + story.audience !== "for_feed") { + return; + } else { + totalCountedStories++; + } + + var stored = storedAnnouncements[story.id] || storedFeaturedStories[story.id]; + var storedOrNew = stored || story; + storedOrNew.pingPong = pingPong; + if (stored) { + return; + } + + if (story.audience === "for_connections") { + storedAnnouncements[story.id] = story; + } else if (story.audience === "for_feed") { + storedFeaturedStories[story.id] = story; + } + }); + var key; + for (key in storedAnnouncements) { + if (storedAnnouncements[key].pingPong !== pingPong) { + delete storedAnnouncements[key]; + } + } + for (key in storedFeaturedStories) { + if (storedFeaturedStories[key].pingPong !== pingPong) { + delete storedFeaturedStories[key]; + } + } + // + // END logic for keeping track of new info + // + + var notificationCount = Object.keys(storedAnnouncements).length + + Object.keys(storedFeaturedStories).length; + shouldShowDot = totalCountedStories > 0 || (notificationCount > 0 && shouldShowDot); + ui.messagesWaiting(shouldShowDot && !ui.isOpen); + + if (notificationCount > 0 && !ui.isOpen) { + var message; + if (!ui.notificationInitialCallbackMade) { + message = "You have " + userStoriesArray.length + "event invitations pending! " + + "Open GOTO to see them."; + ui.notificationDisplayBanner(message); + } else { + for (key in storedAnnouncements) { + message = storedAnnouncements[key].username + " says something is happening in " + + storedAnnouncements[key].place_name + "! Open GOTO to join them."; + ui.notificationDisplayBanner(message); + } + for (key in storedFeaturedStories) { + message = storedFeaturedStories[key].username + " has invited you to an event in " + + storedFeaturedStories[key].place_name + "! Open GOTO to join them."; + ui.notificationDisplayBanner(message); + } + } + } +} + +function isReturnedDataEmpty(data) { + var storiesArray = data.user_stories; + return storiesArray.length === 0; +} + var ui; var GOTO_QML_SOURCE = "hifi/tablet/TabletAddressDialog.qml"; var BUTTON_NAME = "GOTO"; function startup() { + var options = [ + 'include_actions=announcement', + 'restriction=open,hifi', + 'require_online=true', + 'protocol=' + encodeURIComponent(Window.protocolSignature()), + 'per_page=10' + ]; + var endpoint = '/api/v1/notifications?source=user_stories?' + options.join('&'); + ui = new AppUi({ buttonName: BUTTON_NAME, sortOrder: 8, onOpened: gotoOpened, - home: GOTO_QML_SOURCE + home: GOTO_QML_SOURCE, + notificationPollEndpoint: endpoint, + notificationPollTimeoutMs: 60000, + notificationDataProcessPage: notificationDataProcessPage, + notificationPollCallback: notificationPollCallback, + notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, + notificationPollCaresAboutSince: true }); } -function shutdown() { - Script.clearInterval(pollTimer); -} - startup(); -Script.scriptEnding.connect(shutdown); }()); // END LOCAL_SCOPE From 9db11aeda77be5368e2f13cacf1e32bebfcb0bc7 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 16:35:53 -0700 Subject: [PATCH 05/17] Bugfixes and new algo for PAL notifs --- scripts/system/pal.js | 77 +++++++++++++++-------------------- scripts/system/tablet-goto.js | 36 ++++++++-------- 2 files changed, 50 insertions(+), 63 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 38359fbab9..355ed0a504 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -823,46 +823,42 @@ function notificationDataProcessPage(data) { } var shouldShowDot = false; -var storedOnlineUsersArray = []; +var pingPong = false; +var storedOnlineUsers = {}; function notificationPollCallback(connectionsArray) { // // START logic for handling online/offline user changes // - var i, j; - var newlyOnlineConnectionsArray = []; - for (i = 0; i < connectionsArray.length; i++) { - var currentUser = connectionsArray[i]; + pingPong = !pingPong; + var newOnlineUsers = 0; + var message; - if (connectionsArray[i].online) { - var indexOfStoredOnlineUser = -1; - for (j = 0; j < storedOnlineUsersArray.length; j++) { - if (currentUser.username === storedOnlineUsersArray[j].username) { - indexOfStoredOnlineUser = j; - break; - } - } - // If the user record isn't already presesnt inside `storedOnlineUsersArray`... - if (indexOfStoredOnlineUser < 0) { - storedOnlineUsersArray.push(currentUser); - newlyOnlineConnectionsArray.push(currentUser); - } - } else { - var indexOfOfflineUser = -1; - for (j = 0; j < storedOnlineUsersArray.length; j++) { - if (currentUser.username === storedOnlineUsersArray[j].username) { - indexOfOfflineUser = j; - break; - } - } - if (indexOfOfflineUser >= 0) { - storedOnlineUsersArray.splice(indexOfOfflineUser); + connectionsArray.forEach(function (user) { + var stored = storedOnlineUsers[user.username]; + var storedOrNew = stored || user; + storedOrNew.pingPong = pingPong; + if (stored) { + return; + } + + if (user.online) { + newOnlineUsers++; + storedOnlineUsers[user.username] = user; + + if (!ui.isOpen && ui.notificationInitialCallbackMade) { + message = user.username + " is available in " + + user.location.root.name + "! Open PEOPLE to join them."; + ui.notificationDisplayBanner(message); } } + }); + var key; + for (key in storedOnlineUsers) { + if (storedOnlineUsers[key].pingPong !== pingPong) { + delete storedOnlineUsers[key]; + } } - // If there's new data, the light should turn on. - // If the light is already on and you have connections online, the light should stay on. - // In all other cases, the light should turn off or stay off. - shouldShowDot = newlyOnlineConnectionsArray.length > 0 || (storedOnlineUsersArray.length > 0 && shouldShowDot); + shouldShowDot = newOnlineUsers > 0 || (Object.keys(storedOnlineUsers).length > 0 && shouldShowDot); // // END logic for handling online/offline user changes // @@ -874,19 +870,10 @@ function notificationPollCallback(connectionsArray) { shouldShowDot: shouldShowDot }); - if (newlyOnlineConnectionsArray.length > 0) { - var message; - if (!ui.notificationInitialCallbackMade) { - message = newlyOnlineConnectionsArray.length + " of your connections " + - (newlyOnlineConnectionsArray.length === 1 ? "is" : "are") + " online! Open PEOPLE to join them."; - ui.notificationDisplayBanner(message); - } else { - for (i = 0; i < newlyOnlineConnectionsArray.length; i++) { - message = newlyOnlineConnectionsArray[i].username + " is available in " + - newlyOnlineConnectionsArray[i].location.root.name + "! Open PEOPLE to join them."; - ui.notificationDisplayBanner(message); - } - } + if (newOnlineUsers > 0 && !ui.notificationInitialCallbackMade) { + message = newOnlineUsers + " of your connections " + + (newOnlineUsers === 1 ? "is" : "are") + " online! Open PEOPLE to join them."; + ui.notificationDisplayBanner(message); } } } diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 26099828dc..972b9d9841 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -29,12 +29,14 @@ var shouldShowDot = false; var pingPong = false; var storedAnnouncements = {}; var storedFeaturedStories = {}; +var message; function notificationPollCallback(userStoriesArray) { // // START logic for keeping track of new info // pingPong = !pingPong; var totalCountedStories = 0; + var shouldNotifyIndividually = !ui.isOpen && ui.notificationInitialCallbackMade; userStoriesArray.forEach(function (story) { if (story.audience !== "for_connections" && story.audience !== "for_feed") { @@ -52,8 +54,20 @@ function notificationPollCallback(userStoriesArray) { if (story.audience === "for_connections") { storedAnnouncements[story.id] = story; + + if (shouldNotifyIndividually) { + message = storedAnnouncements[key].username + " says something is happening in " + + storedAnnouncements[key].place_name + "! Open GOTO to join them."; + ui.notificationDisplayBanner(message); + } } else if (story.audience === "for_feed") { storedFeaturedStories[story.id] = story; + + if (shouldNotifyIndividually) { + message = storedFeaturedStories[key].username + " has invited you to an event in " + + storedFeaturedStories[key].place_name + "! Open GOTO to join them."; + ui.notificationDisplayBanner(message); + } } }); var key; @@ -76,24 +90,10 @@ function notificationPollCallback(userStoriesArray) { shouldShowDot = totalCountedStories > 0 || (notificationCount > 0 && shouldShowDot); ui.messagesWaiting(shouldShowDot && !ui.isOpen); - if (notificationCount > 0 && !ui.isOpen) { - var message; - if (!ui.notificationInitialCallbackMade) { - message = "You have " + userStoriesArray.length + "event invitations pending! " + - "Open GOTO to see them."; - ui.notificationDisplayBanner(message); - } else { - for (key in storedAnnouncements) { - message = storedAnnouncements[key].username + " says something is happening in " + - storedAnnouncements[key].place_name + "! Open GOTO to join them."; - ui.notificationDisplayBanner(message); - } - for (key in storedFeaturedStories) { - message = storedFeaturedStories[key].username + " has invited you to an event in " + - storedFeaturedStories[key].place_name + "! Open GOTO to join them."; - ui.notificationDisplayBanner(message); - } - } + if (notificationCount > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) { + message = "You have " + notificationCount + "event invitations pending! " + + "Open GOTO to see them."; + ui.notificationDisplayBanner(message); } } From f70ecdad1698468c87f09b58f47127347c09316d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 17:00:53 -0700 Subject: [PATCH 06/17] Small bugfix --- scripts/system/tablet-goto.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 972b9d9841..63bc8431e8 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -35,14 +35,12 @@ function notificationPollCallback(userStoriesArray) { // START logic for keeping track of new info // pingPong = !pingPong; - var totalCountedStories = 0; + var totalNewStories = 0; var shouldNotifyIndividually = !ui.isOpen && ui.notificationInitialCallbackMade; userStoriesArray.forEach(function (story) { if (story.audience !== "for_connections" && story.audience !== "for_feed") { return; - } else { - totalCountedStories++; } var stored = storedAnnouncements[story.id] || storedFeaturedStories[story.id]; @@ -52,6 +50,8 @@ function notificationPollCallback(userStoriesArray) { return; } + totalNewStories++; + if (story.audience === "for_connections") { storedAnnouncements[story.id] = story; @@ -85,13 +85,13 @@ function notificationPollCallback(userStoriesArray) { // END logic for keeping track of new info // - var notificationCount = Object.keys(storedAnnouncements).length + + var totalStories = Object.keys(storedAnnouncements).length + Object.keys(storedFeaturedStories).length; - shouldShowDot = totalCountedStories > 0 || (notificationCount > 0 && shouldShowDot); + shouldShowDot = totalNewStories > 0 || (totalStories > 0 && shouldShowDot); ui.messagesWaiting(shouldShowDot && !ui.isOpen); - if (notificationCount > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) { - message = "You have " + notificationCount + "event invitations pending! " + + if (totalStories > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) { + message = "You have " + totalStories + "event invitations pending! " + "Open GOTO to see them."; ui.notificationDisplayBanner(message); } From 144771b77b28918d544e2bb5bf13f2d8c73b803f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 19 Sep 2018 11:35:17 -0700 Subject: [PATCH 07/17] Request JSON from server --- scripts/modules/appUi.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index c7f6cc5f39..10c3ed023c 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -197,11 +197,11 @@ function AppUi(properties) { } else { concatenatedServerResponse = concatenatedServerResponse.concat(that.notificationDataProcessPage(response)); currentDataPageToRetrieve++; - request({ uri: (url + "&page=" + currentDataPageToRetrieve) }, requestCallback); + request({ json: true, uri: (url + "&page=" + currentDataPageToRetrieve) }, requestCallback); } } - request({ uri: url }, requestCallback); + request({ json: true, uri: url }, requestCallback); }; // This won't do anything if there isn't a notification endpoint set From ed84b49ece9fe29171d7c5864fb4405d09014797 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 19 Sep 2018 16:15:59 -0700 Subject: [PATCH 08/17] Small bugfixes and using original endpoints --- .../icons/tablet-icons/goto-a-msg.svg | 57 +++++++++++++++++++ .../{goto-msg.svg => goto-i-msg.svg} | 0 .../icons/tablet-icons/wallet-a-msg.svg | 6 ++ .../icons/tablet-icons/wallet-i-msg.svg | 16 ++++++ .../qml/hifi/commerce/purchases/Purchases.qml | 2 +- scripts/system/commerce/wallet.js | 2 +- scripts/system/marketplaces/marketplaces.js | 5 +- scripts/system/pal.js | 2 +- scripts/system/tablet-goto.js | 2 +- 9 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 interface/resources/icons/tablet-icons/goto-a-msg.svg rename interface/resources/icons/tablet-icons/{goto-msg.svg => goto-i-msg.svg} (100%) create mode 100644 interface/resources/icons/tablet-icons/wallet-a-msg.svg create mode 100644 interface/resources/icons/tablet-icons/wallet-i-msg.svg diff --git a/interface/resources/icons/tablet-icons/goto-a-msg.svg b/interface/resources/icons/tablet-icons/goto-a-msg.svg new file mode 100644 index 0000000000..f1f611adb9 --- /dev/null +++ b/interface/resources/icons/tablet-icons/goto-a-msg.svg @@ -0,0 +1,57 @@ + + + +image/svg+xml + + \ No newline at end of file diff --git a/interface/resources/icons/tablet-icons/goto-msg.svg b/interface/resources/icons/tablet-icons/goto-i-msg.svg similarity index 100% rename from interface/resources/icons/tablet-icons/goto-msg.svg rename to interface/resources/icons/tablet-icons/goto-i-msg.svg diff --git a/interface/resources/icons/tablet-icons/wallet-a-msg.svg b/interface/resources/icons/tablet-icons/wallet-a-msg.svg new file mode 100644 index 0000000000..d51c3e99a2 --- /dev/null +++ b/interface/resources/icons/tablet-icons/wallet-a-msg.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/interface/resources/icons/tablet-icons/wallet-i-msg.svg b/interface/resources/icons/tablet-icons/wallet-i-msg.svg new file mode 100644 index 0000000000..676f97a966 --- /dev/null +++ b/interface/resources/icons/tablet-icons/wallet-i-msg.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 3b8e2c0f4d..2435678e77 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -93,7 +93,7 @@ Rectangle { console.log("Failed to get Available Updates", result.data.message); } else { sendToScript({method: 'purchases_availableUpdatesReceived', numUpdates: result.data.updates.length }); - root.numUpdatesAvailable = result.data.updates.length; + root.numUpdatesAvailable = result.total_entries; } } diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 2f3f5c109d..c903080f62 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -601,7 +601,7 @@ function startup() { onOpened: walletOpened, onClosed: walletClosed, onMessage: fromQml, - notificationPollEndpoint: "/api/v1/notifications?source=commerce-history&per_page=10", + notificationPollEndpoint: "/api/v1/commerce/history?per_page=10", notificationPollTimeoutMs: 60000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 1bb0713f50..9bd3a9facf 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -137,7 +137,6 @@ function onUsernameChanged() { } } -var userHasUpdates = false; function sendCommerceSettings() { ui.sendToHtml({ type: "marketplaces", @@ -147,7 +146,7 @@ function sendCommerceSettings() { userIsLoggedIn: Account.loggedIn, walletNeedsSetup: Wallet.walletStatus === 1, metaverseServerURL: Account.metaverseServerURL, - messagesWaiting: userHasUpdates + messagesWaiting: shouldShowDot } }); } @@ -1077,7 +1076,7 @@ function startup() { home: MARKETPLACE_URL_INITIAL, onScreenChanged: onTabletScreenChanged, onMessage: onQmlMessageReceived, - notificationPollEndpoint: "/api/v1/notifications?source=commerce-available_updates&per_page=10", + notificationPollEndpoint: "/api/v1/commerce/available_updates?per_page=10", notificationPollTimeoutMs: 60000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 355ed0a504..b3499d759a 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -891,7 +891,7 @@ function startup() { onOpened: palOpened, onClosed: off, onMessage: fromQml, - notificationPollEndpoint: "/api/v1/notifications?source=users&filter=connections&per_page=10", + notificationPollEndpoint: "/api/v1/users?filter=connections&per_page=10", notificationPollTimeoutMs: 60000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 63bc8431e8..f37b13c406 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -113,7 +113,7 @@ function startup() { 'protocol=' + encodeURIComponent(Window.protocolSignature()), 'per_page=10' ]; - var endpoint = '/api/v1/notifications?source=user_stories?' + options.join('&'); + var endpoint = '/api/v1/user_stories?' + options.join('&'); ui = new AppUi({ buttonName: BUTTON_NAME, From 87e91a44015710713c9bf5ed0a881df06b7be1fe Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 20 Sep 2018 13:36:50 -0700 Subject: [PATCH 09/17] GOTO doesn't care about SINCE; reduce data for PEOPLE --- scripts/system/pal.js | 16 +++++++--------- scripts/system/tablet-goto.js | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index b3499d759a..02bf92dcfe 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -841,15 +841,13 @@ function notificationPollCallback(connectionsArray) { return; } - if (user.online) { - newOnlineUsers++; - storedOnlineUsers[user.username] = user; + newOnlineUsers++; + storedOnlineUsers[user.username] = user; - if (!ui.isOpen && ui.notificationInitialCallbackMade) { - message = user.username + " is available in " + - user.location.root.name + "! Open PEOPLE to join them."; - ui.notificationDisplayBanner(message); - } + if (!ui.isOpen && ui.notificationInitialCallbackMade) { + message = user.username + " is available in " + + user.location.root.name + "! Open PEOPLE to join them."; + ui.notificationDisplayBanner(message); } }); var key; @@ -891,7 +889,7 @@ function startup() { onOpened: palOpened, onClosed: off, onMessage: fromQml, - notificationPollEndpoint: "/api/v1/users?filter=connections&per_page=10", + notificationPollEndpoint: "/api/v1/users?filter=connections&status=online&per_page=10", notificationPollTimeoutMs: 60000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index f37b13c406..fde558d728 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -125,7 +125,7 @@ function startup() { notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, - notificationPollCaresAboutSince: true + notificationPollCaresAboutSince: false }); } From 33c04631ea1b459924f8c2dfa15bafe491d88fbd Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 20 Sep 2018 14:34:55 -0700 Subject: [PATCH 10/17] Comments on Confluence doc --- scripts/system/commerce/wallet.js | 23 ++++++--------------- scripts/system/marketplaces/marketplaces.js | 8 +++---- scripts/system/pal.js | 4 ++-- scripts/system/tablet-goto.js | 11 +++++----- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index c903080f62..1fce45bb6f 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -543,37 +543,26 @@ function notificationPollCallback(historyArray) { var message; if (!ui.notificationInitialCallbackMade) { message = "You have " + notificationCount + " unread wallet " + - "notification" + (notificationCount === 1 ? "" : "s") + "! Open WALLET to see all activity."; + "transaction" + (notificationCount === 1 ? "" : "s") + ". Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } else { - var currentItemName, senderName; for (i = 0; i < someoneElsePurchasedArray.length; i++) { - currentItemName = (someoneElsePurchasedArray[i].message).match('(.*)')[1]; - message = "Someone purchased your item \"" + currentItemName + "\" from the Marketplace! " + + message = '"' + (someoneElsePurchasedArray[i].message) + '" ' + "Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } for (i = 0; i < proofIssuedArray.length; i++) { - currentItemName = (proofIssuedArray[i].message).match('(.*)')[1]; - message = "You have been issued a proof for your Marketplace item \"" + currentItemName + "\"! " + + message = '"' + (proofIssuedArray[i].message) + '" ' + "Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } for (i = 0; i < moneyReceivedArray.length; i++) { - senderName = moneyReceivedArray[i].sender_name; - if (senderName === "") { - senderName = "Someone"; - } - message = senderName + " sent you " + moneyReceivedArray[i].received_money + " HFC! " + + message = '"' + (moneyReceivedArray[i].message) + '" ' + "Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } for (i = 0; i < giftReceivedArray.length; i++) { - senderName = giftReceivedArray[i].sender_name; - if (senderName === "") { - senderName = "Someone"; - } - message = senderName + " sent you a gift! " + + message = '"' + (giftReceivedArray[i].message) + '" ' + "Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } @@ -602,7 +591,7 @@ function startup() { onClosed: walletClosed, onMessage: fromQml, notificationPollEndpoint: "/api/v1/commerce/history?per_page=10", - notificationPollTimeoutMs: 60000, + notificationPollTimeoutMs: 300000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 9bd3a9facf..d535884c94 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -1040,15 +1040,15 @@ function notificationPollCallback(updatesArray) { if (updatesArray.length > 0) { var message; if (!ui.notificationInitialCallbackMade) { - message = updatesArray.length + " of your purchased items have updates available! " + + message = updatesArray.length + " of your purchased items have updates available. " + "Open MARKET to update."; ui.notificationDisplayBanner(message); ui.notificationPollCaresAboutSince = true; } else { for (var i = 0; i < updatesArray.length; i++) { - message = "There's an update available for your version of \"" + - updatesArray[i].marketplace_item_name + "\"!" + + message = "Update available for \"" + + updatesArray[i].marketplace_item_name + "\"." + "Open MARKET to update."; ui.notificationDisplayBanner(message); } @@ -1077,7 +1077,7 @@ function startup() { onScreenChanged: onTabletScreenChanged, onMessage: onQmlMessageReceived, notificationPollEndpoint: "/api/v1/commerce/available_updates?per_page=10", - notificationPollTimeoutMs: 60000, + notificationPollTimeoutMs: 300000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 02bf92dcfe..a2ebae1a33 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -846,7 +846,7 @@ function notificationPollCallback(connectionsArray) { if (!ui.isOpen && ui.notificationInitialCallbackMade) { message = user.username + " is available in " + - user.location.root.name + "! Open PEOPLE to join them."; + user.location.root.name + ". Open PEOPLE to join them."; ui.notificationDisplayBanner(message); } }); @@ -870,7 +870,7 @@ function notificationPollCallback(connectionsArray) { if (newOnlineUsers > 0 && !ui.notificationInitialCallbackMade) { message = newOnlineUsers + " of your connections " + - (newOnlineUsers === 1 ? "is" : "are") + " online! Open PEOPLE to join them."; + (newOnlineUsers === 1 ? "is" : "are") + " available online. Open PEOPLE to join them."; ui.notificationDisplayBanner(message); } } diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index fde558d728..22a9752db8 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -57,15 +57,15 @@ function notificationPollCallback(userStoriesArray) { if (shouldNotifyIndividually) { message = storedAnnouncements[key].username + " says something is happening in " + - storedAnnouncements[key].place_name + "! Open GOTO to join them."; + storedAnnouncements[key].place_name + ". Open GOTO to join them."; ui.notificationDisplayBanner(message); } } else if (story.audience === "for_feed") { storedFeaturedStories[story.id] = story; if (shouldNotifyIndividually) { - message = storedFeaturedStories[key].username + " has invited you to an event in " + - storedFeaturedStories[key].place_name + "! Open GOTO to join them."; + message = storedFeaturedStories[key].username + " invites you to an event in " + + storedFeaturedStories[key].place_name + ". Open GOTO to join them."; ui.notificationDisplayBanner(message); } } @@ -91,8 +91,9 @@ function notificationPollCallback(userStoriesArray) { ui.messagesWaiting(shouldShowDot && !ui.isOpen); if (totalStories > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) { - message = "You have " + totalStories + "event invitations pending! " + - "Open GOTO to see them."; + message = "There " + (totalStories === 1 ? "is " : "are ") + totalStories + "event" + + (totalStories === 1 ? "" : "s") + " to know about. " + + "Open GOTO to see " + (totalStories === 1 ? "it" : "them") + "."; ui.notificationDisplayBanner(message); } } From 6284074ff96f076f9395fdc02a7e478b577ab29a Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 21 Sep 2018 10:46:49 -0700 Subject: [PATCH 11/17] Don't show banner when app is open but continue updating data --- scripts/modules/appUi.js | 8 +++++--- scripts/system/marketplaces/marketplaces.js | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index 10c3ed023c..78e9ed38f0 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -107,7 +107,9 @@ function AppUi(properties) { that.notificationPollCaresAboutSince = false; that.notificationInitialCallbackMade = false; that.notificationDisplayBanner = function (message) { - Window.displayAnnouncement(message); + if (that.isOpen) { + Window.displayAnnouncement(message); + } }; // // END Notification Handling Defaults @@ -155,8 +157,8 @@ function AppUi(properties) { return; } - // User is "appearing offline", or is offline, or the app is open - if (GlobalServices.findableBy === "none" || Account.username === "" || that.isOpen) { + // User is "appearing offline" or is offline + if (GlobalServices.findableBy === "none" || Account.username === "") { that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs); return; } diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index d535884c94..3a239aa774 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -909,7 +909,7 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { break; case 'purchases_availableUpdatesReceived': shouldShowDot = message.numUpdates > 0; - ui.messagesWaiting(shouldShowDot); + ui.messagesWaiting(shouldShowDot && !ui.isOpen); break; case 'purchases_updateWearables': var currentlyWornWearables = []; @@ -1035,7 +1035,7 @@ function notificationDataProcessPage(data) { var shouldShowDot = false; function notificationPollCallback(updatesArray) { shouldShowDot = shouldShowDot || updatesArray.length > 0; - ui.messagesWaiting(shouldShowDot); + ui.messagesWaiting(shouldShowDot && !ui.isOpen); if (updatesArray.length > 0) { var message; From a76c3f028d4bff2fd8ce1c0381de7d32169943dc Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 24 Sep 2018 14:46:00 -0700 Subject: [PATCH 12/17] Small bugfixes --- scripts/modules/appUi.js | 3 ++- scripts/system/commerce/wallet.js | 4 +--- scripts/system/marketplaces/marketplaces.js | 11 +++++------ scripts/system/tablet-goto.js | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index 78e9ed38f0..db395ea778 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -107,7 +107,7 @@ function AppUi(properties) { that.notificationPollCaresAboutSince = false; that.notificationInitialCallbackMade = false; that.notificationDisplayBanner = function (message) { - if (that.isOpen) { + if (!that.isOpen) { Window.displayAnnouncement(message); } }; @@ -120,6 +120,7 @@ function AppUi(properties) { // Set isOpen, wireEventBridge, set buttonActive as appropriate, // and finally call onOpened() or onClosed() IFF defined. that.setCurrentVisibleScreenMetadata(type, url); + if (that.checkIsOpen(type, url)) { that.wireEventBridge(true); if (!that.isOpen) { diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 1fce45bb6f..639c8aa0b3 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -576,9 +576,7 @@ function isReturnedDataEmpty(data) { return historyArray.length === 0; } -// -// Manage the connection between the button and the window. -// + var BUTTON_NAME = "WALLET"; var WALLET_QML_SOURCE = "hifi/commerce/wallet/Wallet.qml"; var ui; diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 3a239aa774..27fa929390 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -1040,15 +1040,16 @@ function notificationPollCallback(updatesArray) { if (updatesArray.length > 0) { var message; if (!ui.notificationInitialCallbackMade) { - message = updatesArray.length + " of your purchased items have updates available. " + - "Open MARKET to update."; + message = updatesArray.length + " of your purchased items " + + (updatesArray.length === 1 ? "has an update " : "have updates ") + + "available. Open MARKET to update."; ui.notificationDisplayBanner(message); ui.notificationPollCaresAboutSince = true; } else { for (var i = 0; i < updatesArray.length; i++) { message = "Update available for \"" + - updatesArray[i].marketplace_item_name + "\"." + + updatesArray[i].base_item_title + "\"." + "Open MARKET to update."; ui.notificationDisplayBanner(message); } @@ -1061,9 +1062,7 @@ function isReturnedDataEmpty(data) { return historyArray.length === 0; } -// -// Manage the connection between the button and the window. -// + var BUTTON_NAME = "MARKET"; var MARKETPLACE_URL = METAVERSE_SERVER_URL + "/marketplace"; var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page. diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 22a9752db8..0f032ae74d 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -91,7 +91,7 @@ function notificationPollCallback(userStoriesArray) { ui.messagesWaiting(shouldShowDot && !ui.isOpen); if (totalStories > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) { - message = "There " + (totalStories === 1 ? "is " : "are ") + totalStories + "event" + + message = "There " + (totalStories === 1 ? "is " : "are ") + totalStories + " event" + (totalStories === 1 ? "" : "s") + " to know about. " + "Open GOTO to see " + (totalStories === 1 ? "it" : "them") + "."; ui.notificationDisplayBanner(message); From be304ea97585de71f2217029cc72487b3ec98c13 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 24 Sep 2018 17:32:30 -0700 Subject: [PATCH 13/17] Small bugfixes again --- scripts/modules/appUi.js | 2 +- scripts/system/tablet-goto.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index db395ea778..12ba115815 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -170,7 +170,7 @@ function AppUi(properties) { var currentTimestamp = new Date().getTime(); var lastPollTimestamp = Settings.getValue(settingsKey, currentTimestamp); if (that.notificationPollCaresAboutSince) { - url = url + "&since=" + lastPollTimestamp; + url = url + "&since=" + lastPollTimestamp/1000; } Settings.setValue(settingsKey, currentTimestamp); diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 0f032ae74d..902e1b7fef 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -18,7 +18,8 @@ var AppUi = Script.require('appUi'); function gotoOpened() { - ui.messagesWaiting(false); + shouldShowDot = false; + ui.messagesWaiting(shouldShowDot); } function notificationDataProcessPage(data) { From 1ac2800e181b87ff229ed5d3fe88958ea04b6b69 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 24 Sep 2018 17:49:52 -0700 Subject: [PATCH 14/17] Fix wallet dot logic --- scripts/system/commerce/wallet.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 639c8aa0b3..a9ebe37feb 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -488,7 +488,8 @@ function walletOpened() { Controller.mouseMoveEvent.connect(handleMouseMoveEvent); triggerMapping.enable(); triggerPressMapping.enable(); - ui.messagesWaiting(false); + shouldShowDot = false; + ui.messagesWaiting(shouldShowDot); } function walletClosed() { From 82b08f1a939bfd6ad93285a5e86a1fea8d0370a2 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 25 Sep 2018 16:21:05 -0700 Subject: [PATCH 15/17] Wait until skeleton is loaded to locate the avatar --- interface/src/avatar/MyAvatar.cpp | 54 ++++++++----------------------- interface/src/avatar/MyAvatar.h | 2 ++ 2 files changed, 15 insertions(+), 41 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index df7ec93b6a..49ba763485 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -118,6 +118,7 @@ MyAvatar::MyAvatar(QThread* thread) : _goToSafe(true), _goToPosition(), _goToOrientation(), + _goToFeetAjustment(false), _prevShouldDrawHead(true), _audioListenerMode(FROM_HEAD), _hmdAtRestDetector(glm::vec3(0), glm::quat()), @@ -498,7 +499,7 @@ void MyAvatar::update(float deltaTime) { setCurrentStandingHeight(computeStandingHeightMode(getControllerPoseInAvatarFrame(controller::Action::HEAD))); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); - if (_drawAverageFacingEnabled) { + if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation()); glm::vec3 worldFacingAverage = transformVectorFast(getSensorToWorldMatrix(), glm::vec3(_headControllerFacingMovingAverage.x, 0.0f, _headControllerFacingMovingAverage.y)); @@ -526,6 +527,11 @@ void MyAvatar::update(float deltaTime) { _physicsSafetyPending = getCollisionsEnabled(); _characterController.recomputeFlying(); // In case we've gone to into the sky. } + if (_goToFeetAjustment && _skeletonModelLoaded) { + auto feetAjustment = getWorldPosition() - getWorldFeetPosition(); + goToLocation(getWorldPosition() + feetAjustment); + _goToFeetAjustment = false; + } if (_physicsSafetyPending && qApp->isPhysicsEnabled() && _characterController.isEnabledAndReady()) { // When needed and ready, arrange to check and fix. _physicsSafetyPending = false; @@ -1728,6 +1734,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _headBoneSet.clear(); _cauterizationNeedsUpdate = true; + _skeletonModelLoaded = false; std::shared_ptr skeletonConnection = std::make_shared(); *skeletonConnection = QObject::connect(_skeletonModel.get(), &SkeletonModel::skeletonLoaded, [this, skeletonModelChangeCount, skeletonConnection]() { @@ -1745,6 +1752,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); initAnimGraph(); + _skeletonModelLoaded = true; } QObject::disconnect(*skeletonConnection); }); @@ -2945,46 +2953,10 @@ void MyAvatar::goToLocation(const QVariant& propertiesVar) { } void MyAvatar::goToFeetLocation(const glm::vec3& newPosition, - bool hasOrientation, const glm::quat& newOrientation, - bool shouldFaceLocation) { - - qCDebug(interfaceapp).nospace() << "MyAvatar goToFeetLocation - moving to " << newPosition.x << ", " - << newPosition.y << ", " << newPosition.z; - - ShapeInfo shapeInfo; - computeShapeInfo(shapeInfo); - glm::vec3 halfExtents = shapeInfo.getHalfExtents(); - glm::vec3 localFeetPos = shapeInfo.getOffset() - glm::vec3(0.0f, halfExtents.y + halfExtents.x, 0.0f); - glm::mat4 localFeet = createMatFromQuatAndPos(Quaternions::IDENTITY, localFeetPos); - - glm::mat4 worldFeet = createMatFromQuatAndPos(Quaternions::IDENTITY, newPosition); - - glm::mat4 avatarMat = worldFeet * glm::inverse(localFeet); - - glm::vec3 adjustedPosition = extractTranslation(avatarMat); - - _goToPending = true; - _goToPosition = adjustedPosition; - _goToOrientation = getWorldOrientation(); - if (hasOrientation) { - qCDebug(interfaceapp).nospace() << "MyAvatar goToFeetLocation - new orientation is " - << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w; - - // orient the user to face the target - glm::quat quatOrientation = cancelOutRollAndPitch(newOrientation); - - if (shouldFaceLocation) { - quatOrientation = newOrientation * glm::angleAxis(PI, Vectors::UP); - - // move the user a couple units away - const float DISTANCE_TO_USER = 2.0f; - _goToPosition = adjustedPosition - quatOrientation * IDENTITY_FORWARD * DISTANCE_TO_USER; - } - - _goToOrientation = quatOrientation; - } - - emit transformChanged(); + bool hasOrientation, const glm::quat& newOrientation, + bool shouldFaceLocation) { + _goToFeetAjustment = true; + goToLocation(newPosition, hasOrientation, newOrientation, shouldFaceLocation); } void MyAvatar::goToLocation(const glm::vec3& newPosition, diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1dc0b3cd40..d7379a18c4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1732,6 +1732,7 @@ private: bool _goToPending { false }; bool _physicsSafetyPending { false }; bool _goToSafe { true }; + bool _goToFeetAjustment { false }; glm::vec3 _goToPosition; glm::quat _goToOrientation; @@ -1807,6 +1808,7 @@ private: bool _haveReceivedHeightLimitsFromDomain { false }; int _disableHandTouchCount { 0 }; + bool _skeletonModelLoaded { false }; Setting::Handle _dominantHandSetting; Setting::Handle _headPitchSetting; From 754653b093d2af5e5fe56e5caa33d1b2252e088d Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 25 Sep 2018 17:31:18 -0700 Subject: [PATCH 16/17] Fix warnings --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 49ba763485..f2e6b68a0f 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -116,9 +116,9 @@ MyAvatar::MyAvatar(QThread* thread) : _bodySensorMatrix(), _goToPending(false), _goToSafe(true), + _goToFeetAjustment(false), _goToPosition(), _goToOrientation(), - _goToFeetAjustment(false), _prevShouldDrawHead(true), _audioListenerMode(FROM_HEAD), _hmdAtRestDetector(glm::vec3(0), glm::quat()), From 6877af04f118edf56562113d60ed28b951603c28 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 26 Sep 2018 14:57:32 -0700 Subject: [PATCH 17/17] Fix GOTO notifs; fix WALLET notifs (pending backend change) --- scripts/system/commerce/wallet.js | 54 ++----------------------------- scripts/system/tablet-goto.js | 8 ++--- 2 files changed, 7 insertions(+), 55 deletions(-) diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 639c8aa0b3..c0e044c84b 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -501,41 +501,8 @@ function notificationDataProcessPage(data) { var shouldShowDot = false; function notificationPollCallback(historyArray) { - var i; - var someoneElsePurchasedArray = []; - var proofIssuedArray = []; - var moneyReceivedArray = []; - var giftReceivedArray = []; - for (i = 0; i < historyArray.length; i++) { - var currentHistoryTxn = historyArray[i]; - - if (currentHistoryTxn.sent_certs <= 0 && - currentHistoryTxn.received_certs <= 0) { - // This is an HFC transfer. - if (currentHistoryTxn.received_money > 0) { - if (currentHistoryTxn.sender_name === "marketplace") { - someoneElsePurchasedArray.push(currentHistoryTxn); - } else { - moneyReceivedArray.push(currentHistoryTxn); - } - } - } else if (currentHistoryTxn.sent_money <= 0 && - currentHistoryTxn.received_money <= 0 && - currentHistoryTxn.received_certs > 0) { - // This is a non-HFC asset transfer. - if (currentHistoryTxn.sender_name === "marketplace") { - proofIssuedArray.push(currentHistoryTxn); - } else { - giftReceivedArray.push(currentHistoryTxn); - } - } - } - if (!ui.isOpen) { - var notificationCount = someoneElsePurchasedArray.length + - proofIssuedArray.length + - moneyReceivedArray.length + - giftReceivedArray.length; + var notificationCount = historyArray.length; shouldShowDot = shouldShowDot || notificationCount > 0; ui.messagesWaiting(shouldShowDot); @@ -546,23 +513,8 @@ function notificationPollCallback(historyArray) { "transaction" + (notificationCount === 1 ? "" : "s") + ". Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } else { - for (i = 0; i < someoneElsePurchasedArray.length; i++) { - message = '"' + (someoneElsePurchasedArray[i].message) + '" ' + - "Open WALLET to see all activity."; - ui.notificationDisplayBanner(message); - } - for (i = 0; i < proofIssuedArray.length; i++) { - message = '"' + (proofIssuedArray[i].message) + '" ' + - "Open WALLET to see all activity."; - ui.notificationDisplayBanner(message); - } - for (i = 0; i < moneyReceivedArray.length; i++) { - message = '"' + (moneyReceivedArray[i].message) + '" ' + - "Open WALLET to see all activity."; - ui.notificationDisplayBanner(message); - } - for (i = 0; i < giftReceivedArray.length; i++) { - message = '"' + (giftReceivedArray[i].message) + '" ' + + for (var i = 0; i < notificationCount; i++) { + message = '"' + (historyArray[i].message) + '" ' + "Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 902e1b7fef..6d8ba3a927 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -57,16 +57,16 @@ function notificationPollCallback(userStoriesArray) { storedAnnouncements[story.id] = story; if (shouldNotifyIndividually) { - message = storedAnnouncements[key].username + " says something is happening in " + - storedAnnouncements[key].place_name + ". Open GOTO to join them."; + message = story.username + " says something is happening in " + + story.place_name + ". Open GOTO to join them."; ui.notificationDisplayBanner(message); } } else if (story.audience === "for_feed") { storedFeaturedStories[story.id] = story; if (shouldNotifyIndividually) { - message = storedFeaturedStories[key].username + " invites you to an event in " + - storedFeaturedStories[key].place_name + ". Open GOTO to join them."; + message = story.username + " invites you to an event in " + + story.place_name + ". Open GOTO to join them."; ui.notificationDisplayBanner(message); } }