Notifications are working!

This commit is contained in:
Zach Fox 2018-10-31 13:23:58 -07:00
parent b6344acc1d
commit 448be8847f
7 changed files with 155 additions and 99 deletions

View file

@ -91,7 +91,6 @@ Rectangle {
if (result.status !== 'success') {
console.log("Failed to get Available Updates", result.data.message);
} else {
sendToScript({method: 'purchases_availableUpdatesReceived', numUpdates: result.data.updates.length });
root.numUpdatesAvailable = result.total_entries;
}
}

View file

@ -99,6 +99,13 @@ Rectangle {
}
}
onActiveViewChanged: {
if (activeView === "walletHome") {
walletHomeButtonContainer.messagesWaiting = false;
sendToScript({method: 'clearShouldShowDotHistory'});
}
}
HifiCommerceCommon.CommerceLightbox {
id: lightboxPopup;
visible: false;
@ -494,6 +501,7 @@ Rectangle {
// "WALLET HOME" tab button
Rectangle {
id: walletHomeButtonContainer;
property bool messagesWaiting: false;
visible: !walletSetup.visible;
color: root.activeView === "walletHome" ? hifi.colors.blueAccent : hifi.colors.black;
anchors.top: parent.top;
@ -514,6 +522,19 @@ Rectangle {
color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight);
}
Rectangle {
id: recentActivityMessagesWaitingLight;
visible: parent.messagesWaiting;
anchors.right: homeTabIcon.left;
anchors.rightMargin: -4;
anchors.top: homeTabIcon.top;
anchors.topMargin: 16;
height: 10;
width: height;
radius: height/2;
color: "red";
}
RalewaySemiBold {
text: "RECENT ACTIVITY";
// Text size
@ -572,7 +593,7 @@ Rectangle {
}
Rectangle {
id: messagesWaitingLight;
id: exchangeMoneyMessagesWaitingLight;
visible: parent.messagesWaiting;
anchors.right: exchangeMoneyTabIcon.left;
anchors.rightMargin: -4;
@ -889,6 +910,9 @@ Rectangle {
case 'updateWearables':
walletInventory.fromScript(message);
break;
case 'updateRecentActivityMessageLight':
walletHomeButtonContainer.messagesWaiting = message.messagesWaiting;
break;
default:
console.log('Unrecognized message from wallet.js:', JSON.stringify(message));
}

View file

@ -95,16 +95,16 @@ function AppUi(properties) {
activeIcon: isWaiting ? that.activeMessagesButton : that.activeButton
});
};
that.notificationPollTimeout = false;
that.notificationPollTimeoutMs = 60000;
that.notificationPollEndpoint = false;
that.notificationPollStopPaginatingConditionMet = false;
that.notificationPollTimeout = [false];
that.notificationPollTimeoutMs = [60000];
that.notificationPollEndpoint = [false];
that.notificationPollStopPaginatingConditionMet = [false];
that.notificationDataProcessPage = function (data) {
return data;
};
that.notificationPollCallback = that.ignore;
that.notificationPollCaresAboutSince = false;
that.notificationInitialCallbackMade = false;
that.notificationPollCallback = [that.ignore];
that.notificationPollCaresAboutSince = [false];
that.notificationInitialCallbackMade = [false];
that.notificationDisplayBanner = function (message) {
if (!that.isOpen) {
Window.displayAnnouncement(message);
@ -149,73 +149,105 @@ function AppUi(properties) {
//
// START Notification Handling
//
var currentDataPageToRetrieve = [];
var concatenatedServerResponse = [];
for (var i = 0; i < that.notificationPollEndpoint.length; i++) {
currentDataPageToRetrieve[i] = 1;
concatenatedServerResponse[i] = new Array();
}
function requestCallback(error, response, optionalParams) {
var indexOfRequest = optionalParams.indexOfRequest;
var urlOfRequest = optionalParams.urlOfRequest;
if (error || (response.status !== 'success')) {
print("Error: unable to get", urlOfRequest, error || response.status);
that.notificationPollTimeout[indexOfRequest] = Script.setTimeout(
that.notificationPoll(indexOfRequest), that.notificationPollTimeoutMs[indexOfRequest]);
return;
}
if (!that.notificationPollStopPaginatingConditionMet[indexOfRequest] ||
that.notificationPollStopPaginatingConditionMet[indexOfRequest](response)) {
that.notificationPollTimeout[indexOfRequest] = Script.setTimeout(function () {
that.notificationPoll(indexOfRequest);
}, that.notificationPollTimeoutMs[indexOfRequest]);
var notificationData;
if (concatenatedServerResponse[indexOfRequest].length) {
notificationData = concatenatedServerResponse[indexOfRequest];
} else {
notificationData = that.notificationDataProcessPage[indexOfRequest](response);
}
console.debug(that.buttonName, that.notificationPollEndpoint[indexOfRequest],
'notification data for processing:', JSON.stringify(notificationData));
that.notificationPollCallback[indexOfRequest](notificationData);
that.notificationInitialCallbackMade[indexOfRequest] = true;
currentDataPageToRetrieve[indexOfRequest] = 1;
concatenatedServerResponse[indexOfRequest] = new Array();
} else {
concatenatedServerResponse[indexOfRequest] =
concatenatedServerResponse[indexOfRequest].concat(that.notificationDataProcessPage[indexOfRequest](response));
currentDataPageToRetrieve[indexOfRequest]++;
request({
json: true,
uri: (urlOfRequest + "&page=" + currentDataPageToRetrieve[indexOfRequest])
}, requestCallback, optionalParams);
}
}
var METAVERSE_BASE = Account.metaverseServerURL;
var currentDataPageToRetrieve = 1;
var concatenatedServerResponse = new Array();
that.notificationPoll = function () {
if (!that.notificationPollEndpoint) {
that.notificationPoll = function (i) {
if (!that.notificationPollEndpoint[i]) {
return;
}
// User is "appearing offline" or is offline
if (GlobalServices.findableBy === "none" || Account.username === "") {
that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs);
that.notificationPollTimeout[i] = Script.setTimeout(
that.notificationPoll(i), that.notificationPollTimeoutMs[i]);
return;
}
var url = METAVERSE_BASE + that.notificationPollEndpoint;
var url = METAVERSE_BASE + that.notificationPollEndpoint[i];
var settingsKey = "notifications/" + that.buttonName + "/lastPoll";
var settingsKey = "notifications/" + that.notificationPollEndpoint[i] + "/lastPoll";
var currentTimestamp = new Date().getTime();
var lastPollTimestamp = Settings.getValue(settingsKey, currentTimestamp);
if (that.notificationPollCaresAboutSince) {
url = url + "&since=" + lastPollTimestamp/1000;
if (that.notificationPollCaresAboutSince[i]) {
url = url + "&since=" + lastPollTimestamp / 1000;
}
Settings.setValue(settingsKey, currentTimestamp);
console.debug(that.buttonName, 'polling for notifications at endpoint', url);
function requestCallback(error, response) {
if (error || (response.status !== 'success')) {
print("Error: unable to get", url, error || response.status);
that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs);
return;
}
if (!that.notificationPollStopPaginatingConditionMet || that.notificationPollStopPaginatingConditionMet(response)) {
that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs);
var notificationData;
if (concatenatedServerResponse.length) {
notificationData = concatenatedServerResponse;
} else {
notificationData = that.notificationDataProcessPage(response);
}
console.debug(that.buttonName, 'notification data for processing:', JSON.stringify(notificationData));
that.notificationPollCallback(notificationData);
that.notificationInitialCallbackMade = true;
currentDataPageToRetrieve = 1;
concatenatedServerResponse = new Array();
} else {
concatenatedServerResponse = concatenatedServerResponse.concat(that.notificationDataProcessPage(response));
currentDataPageToRetrieve++;
request({ json: true, uri: (url + "&page=" + currentDataPageToRetrieve) }, requestCallback);
}
}
request({ json: true, uri: url }, requestCallback);
request({
json: true,
uri: url
},
requestCallback,
{
indexOfRequest: i,
urlOfRequest: url
});
};
// This won't do anything if there isn't a notification endpoint set
that.notificationPoll();
for (i = 0; i < that.notificationPollEndpoint.length; i++) {
that.notificationPoll(i);
}
function restartNotificationPoll() {
that.notificationInitialCallbackMade = false;
if (that.notificationPollTimeout) {
Script.clearTimeout(that.notificationPollTimeout);
that.notificationPollTimeout = false;
for (var j = 0; j < that.notificationPollEndpoint.length; j++) {
that.notificationInitialCallbackMade[j] = false;
if (that.notificationPollTimeout[j]) {
Script.clearTimeout(that.notificationPollTimeout[j]);
that.notificationPollTimeout[j] = false;
}
that.notificationPoll(j);
}
that.notificationPoll();
}
//
// END Notification Handling
@ -322,9 +354,11 @@ function AppUi(properties) {
}
that.tablet.removeButton(that.button);
}
if (that.notificationPollTimeout) {
Script.clearInterval(that.notificationPollTimeout);
that.notificationPollTimeout = false;
for (var i = 0; i < that.notificationPollTimeout.length; i++) {
if (that.notificationPollTimeout[i]) {
Script.clearInterval(that.notificationPollTimeout[i]);
that.notificationPollTimeout[i] = false;
}
}
};
// Set up the handlers.
@ -333,7 +367,7 @@ function AppUi(properties) {
Script.scriptEnding.connect(that.onScriptEnding);
GlobalServices.findableByChanged.connect(restartNotificationPoll);
GlobalServices.myUsernameChanged.connect(restartNotificationPoll);
if (that.buttonName == Settings.getValue("startUpApp")) {
if (that.buttonName === Settings.getValue("startUpApp")) {
Settings.setValue("startUpApp", "");
Script.setTimeout(function () {
that.open();

View file

@ -18,7 +18,8 @@
module.exports = {
// ------------------------------------------------------------------
request: function (options, callback) { // cb(error, responseOfCorrectContentType) of url. A subset of npm request.
// cb(error, responseOfCorrectContentType, optionalCallbackParameter) of url. A subset of npm request.
request: function (options, callback, optionalCallbackParameter) {
var httpRequest = new XMLHttpRequest(), key;
// QT bug: apparently doesn't handle onload. Workaround using readyState.
httpRequest.onreadystatechange = function () {
@ -38,7 +39,7 @@ module.exports = {
if (error) {
response = { statusCode: httpRequest.status };
}
callback(error, response);
callback(error, response, optionalCallbackParameter);
}
};
if (typeof options === 'string') {

View file

@ -506,10 +506,6 @@ function fromQml(message) {
ui.tablet.sendToQml({ method: 'updateWearables', wornWearables: currentlyWornWearables });
break;
case 'purchases_availableUpdatesReceived':
shouldShowDot = message.numUpdates > 0;
ui.messagesWaiting(shouldShowDot && !ui.isOpen);
break;
case 'purchases_walletNotSetUp':
ui.tablet.sendToQml({
method: 'updateWalletReferrer',
@ -525,6 +521,10 @@ function fromQml(message) {
openMarketplace(itemId);
}
break;
case 'clearShouldShowDotHistory':
shouldShowDotHistory = false;
ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory);
break;
case 'http.request':
// Handled elsewhere, don't log.
break;
@ -541,8 +541,13 @@ function walletOpened() {
triggerMapping.enable();
triggerPressMapping.enable();
isWired = true;
shouldShowDot = false;
ui.messagesWaiting(shouldShowDot);
if (shouldShowDotHistory) {
ui.sendMessage({
method: 'updateRecentActivityMessageLight',
messagesWaiting: shouldShowDotHistory
});
}
}
function walletClosed() {
@ -557,20 +562,20 @@ function notificationDataProcessPageHistory(data) {
return data.data.history;
}
var shouldShowDot = false;
var shouldShowDotUpdates = false;
function notificationPollCallbackUpdates(updatesArray) {
shouldShowDot = shouldShowDot || updatesArray.length > 0;
ui.messagesWaiting(shouldShowDot && !ui.isOpen);
shouldShowDotUpdates = shouldShowDotUpdates || updatesArray.length > 0;
ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory);
if (updatesArray.length > 0) {
var message;
if (!ui.notificationInitialCallbackMade) {
if (!ui.notificationInitialCallbackMade[0]) {
message = updatesArray.length + " of your purchased items " +
(updatesArray.length === 1 ? "has an update " : "have updates ") +
"available. Open WALLET to update.";
ui.notificationDisplayBanner(message);
ui.notificationPollCaresAboutSince = true;
ui.notificationPollCaresAboutSince[0] = true;
} else {
for (var i = 0; i < updatesArray.length; i++) {
message = "Update available for \"" +
@ -581,15 +586,16 @@ function notificationPollCallbackUpdates(updatesArray) {
}
}
}
var shouldShowDotHistory = false;
function notificationPollCallbackHistory(historyArray) {
if (!ui.isOpen) {
var notificationCount = historyArray.length;
shouldShowDot = shouldShowDot || notificationCount > 0;
ui.messagesWaiting(shouldShowDot);
shouldShowDotHistory = shouldShowDotHistory || notificationCount > 0;
ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory);
if (notificationCount > 0) {
var message;
if (!ui.notificationInitialCallbackMade) {
if (!ui.notificationInitialCallbackMade[1]) {
message = "You have " + notificationCount + " unread wallet " +
"transaction" + (notificationCount === 1 ? "" : "s") + ". Open WALLET to see all activity.";
ui.notificationDisplayBanner(message);
@ -605,8 +611,8 @@ function notificationPollCallbackHistory(historyArray) {
}
function isReturnedDataEmptyUpdates(data) {
var historyArray = data.data.history;
return historyArray.length === 0;
var updatesArray = data.data.updates;
return updatesArray.length === 0;
}
function isReturnedDataEmptyHistory(data) {
@ -657,20 +663,12 @@ function startup() {
onOpened: walletOpened,
onClosed: walletClosed,
onMessage: fromQml,
/* Gotta re-add all this stuff once I get it working
notificationPollEndpoint: ["/api/v1/commerce/available_updates?per_page=10", "/api/v1/commerce/history?per_page=10"],
notificationPollTimeoutMs: [NOTIFICATION_POLL_TIMEOUT, NOTIFICATION_POLL_TIMEOUT],
notificationDataProcessPage: [notificationDataProcessPageUpdates, notificationDataProcessPageHistory],
notificationPollCallback: [notificationPollCallbackUpdates, notificationPollCallbackHistory],
notificationPollStopPaginatingConditionMet: [isReturnedDataEmptyUpdates, isReturnedDataEmptyHistory],
notificationPollCaresAboutSince: [false, true]
*/
notificationPollEndpoint: "/api/v1/commerce/available_updates?per_page=10",
notificationPollTimeoutMs: 300000,
notificationDataProcessPage: notificationDataProcessPageUpdates,
notificationPollCallback: notificationPollCallbackUpdates,
notificationPollStopPaginatingConditionMet: isReturnedDataEmptyUpdates,
notificationPollCaresAboutSince: false
});
GlobalServices.myUsernameChanged.connect(onUsernameChanged);
installMarketplaceItemTester();

View file

@ -844,7 +844,7 @@ function notificationPollCallback(connectionsArray) {
newOnlineUsers++;
storedOnlineUsers[user.username] = user;
if (!ui.isOpen && ui.notificationInitialCallbackMade) {
if (!ui.isOpen && ui.notificationInitialCallbackMade[0]) {
message = user.username + " is available in " +
user.location.root.name + ". Open PEOPLE to join them.";
ui.notificationDisplayBanner(message);
@ -868,7 +868,7 @@ function notificationPollCallback(connectionsArray) {
shouldShowDot: shouldShowDot
});
if (newOnlineUsers > 0 && !ui.notificationInitialCallbackMade) {
if (newOnlineUsers > 0 && !ui.notificationInitialCallbackMade[0]) {
message = newOnlineUsers + " of your connections " +
(newOnlineUsers === 1 ? "is" : "are") + " available online. Open PEOPLE to join them.";
ui.notificationDisplayBanner(message);
@ -889,12 +889,12 @@ function startup() {
onOpened: palOpened,
onClosed: off,
onMessage: fromQml,
notificationPollEndpoint: "/api/v1/users?filter=connections&status=online&per_page=10",
notificationPollTimeoutMs: 60000,
notificationDataProcessPage: notificationDataProcessPage,
notificationPollCallback: notificationPollCallback,
notificationPollStopPaginatingConditionMet: isReturnedDataEmpty,
notificationPollCaresAboutSince: false
notificationPollEndpoint: ["/api/v1/users?filter=connections&status=online&per_page=10"],
notificationPollTimeoutMs: [60000],
notificationDataProcessPage: [notificationDataProcessPage],
notificationPollCallback: [notificationPollCallback],
notificationPollStopPaginatingConditionMet: [isReturnedDataEmpty],
notificationPollCaresAboutSince: [false]
});
Window.domainChanged.connect(clearLocalQMLDataAndClosePAL);
Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL);

View file

@ -37,7 +37,7 @@ function notificationPollCallback(userStoriesArray) {
//
pingPong = !pingPong;
var totalNewStories = 0;
var shouldNotifyIndividually = !ui.isOpen && ui.notificationInitialCallbackMade;
var shouldNotifyIndividually = !ui.isOpen && ui.notificationInitialCallbackMade[0];
userStoriesArray.forEach(function (story) {
if (story.audience !== "for_connections" &&
story.audience !== "for_feed") {
@ -91,7 +91,7 @@ function notificationPollCallback(userStoriesArray) {
shouldShowDot = totalNewStories > 0 || (totalStories > 0 && shouldShowDot);
ui.messagesWaiting(shouldShowDot && !ui.isOpen);
if (totalStories > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) {
if (totalStories > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade[0]) {
message = "There " + (totalStories === 1 ? "is " : "are ") + totalStories + " event" +
(totalStories === 1 ? "" : "s") + " to know about. " +
"Open GOTO to see " + (totalStories === 1 ? "it" : "them") + ".";
@ -122,12 +122,12 @@ function startup() {
sortOrder: 8,
onOpened: gotoOpened,
home: GOTO_QML_SOURCE,
notificationPollEndpoint: endpoint,
notificationPollTimeoutMs: 60000,
notificationDataProcessPage: notificationDataProcessPage,
notificationPollCallback: notificationPollCallback,
notificationPollStopPaginatingConditionMet: isReturnedDataEmpty,
notificationPollCaresAboutSince: false
notificationPollEndpoint: [endpoint],
notificationPollTimeoutMs: [60000],
notificationDataProcessPage: [notificationDataProcessPage],
notificationPollCallback: [notificationPollCallback],
notificationPollStopPaginatingConditionMet: [isReturnedDataEmpty],
notificationPollCaresAboutSince: [false]
});
}