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,