From 6792464fbf77b445564e19ecbfe0d64eea19b59f Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 5 Sep 2016 17:54:24 +0200 Subject: [PATCH 01/15] limit rtc to parties --- website/client/js/services/pusherService.js | 4 +--- website/server/controllers/api-v3/auth.js | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index 041e389e95..70bed993ad 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -58,8 +58,6 @@ angular.module('habitrpg') api.socketId = api.pusher.connection.socket_id; }); - if (!partyId) return; - var partyChannelName = 'presence-group-' + partyId; var partyChannel = api.pusher.subscribe(partyChannelName); @@ -132,7 +130,7 @@ angular.module('habitrpg') // Connect the user to Pusher and to the party's chat channel partyId = user && $rootScope.user.party && $rootScope.user.party._id; - // if (!partyId) return; + if (!partyId) return; // See if another tab is already connected to Pusher if (!localStorage.getItem(tabIdKey)) { diff --git a/website/server/controllers/api-v3/auth.js b/website/server/controllers/api-v3/auth.js index 74e3663637..48a138d5da 100644 --- a/website/server/controllers/api-v3/auth.js +++ b/website/server/controllers/api-v3/auth.js @@ -327,7 +327,7 @@ api.pusherAuth = { // Channel names are in the form of {presence|private}-{group|...}-{resourceId} let [channelType, resourceType, ...resourceId] = channelName.split('-'); - if (['presence'].indexOf(channelType) === -1) { // presence is used only for parties, private for guilds too + if (['presence'].indexOf(channelType) === -1) { // presence is used only for parties, private for guilds throw new BadRequest('Invalid Pusher channel type.'); } From f28dead69288ac46a7b7ec8ccab96629c252ecd8 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 6 Sep 2016 11:18:52 +0200 Subject: [PATCH 02/15] do not sync party every time the page is opened, update chat in realtime --- website/client/js/controllers/partyCtrl.js | 2 +- website/client/js/services/pusherService.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/website/client/js/controllers/partyCtrl.js b/website/client/js/controllers/partyCtrl.js index c4cd345358..c7ddc42908 100644 --- a/website/client/js/controllers/partyCtrl.js +++ b/website/client/js/controllers/partyCtrl.js @@ -28,7 +28,7 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User',' } if ($state.is('options.social.party') && $rootScope.party && $rootScope.party.id) { - Groups.party(true).then(handlePartyResponse, handlePartyError); + Groups.party().then(handlePartyResponse, handlePartyError); } else { Groups.Group.syncParty().then(handlePartyResponse, handlePartyError); } diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index 70bed993ad..ebe1b17354 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -98,8 +98,9 @@ angular.module('habitrpg') // When a new chat message is posted partyChannel.bind('new-chat', function (data) { Groups.party().then(function () { - // Groups.data.party.chat.unshift(data); - // Groups.data.party.chat.splice(200); + // Update the party data + Groups.data.party.chat.unshift(data); + Groups.data.party.chat.splice(200); }); }); }; From fd00543a8da9b0f4774d7ae19bcbae491ef8b968 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 7 Sep 2016 16:01:21 +0200 Subject: [PATCH 03/15] change button text for syncing party --- common/locales/en/groups.json | 1 + website/views/options/social/chat-box.jade | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common/locales/en/groups.json b/common/locales/en/groups.json index 5deb87aa92..4ca12b3cd6 100644 --- a/common/locales/en/groups.json +++ b/common/locales/en/groups.json @@ -45,6 +45,7 @@ "chat": "Chat", "sendChat": "Send Chat", "toolTipMsg": "Fetch Recent Messages", + "syncPartyAndChat": "Sync Party and Chat", "guildBankPop1": "Guild Bank", "guildBankPop2": "Gems which your guild leader can use for challenge prizes.", "guildGems": "Guild Gems", diff --git a/website/views/options/social/chat-box.jade b/website/views/options/social/chat-box.jade index 3792070706..a2282b165a 100644 --- a/website/views/options/social/chat-box.jade +++ b/website/views/options/social/chat-box.jade @@ -4,7 +4,7 @@ div.chat-form.guidelines-not-accepted(ng-if='!user.flags.communityGuidelinesAcce div button.btn.btn-warning(ng-click='acceptCommunityGuidelines()')=env.t('iAcceptCommunityGuidelines') .chat-buttons - button(type="button", ng-click='sync(group)')=env.t('toolTipMsg') + button(type="button", ng-click='sync(group)') {{group.type === 'party' ? env.t('syncPartyAndChat') : env.t('toolTipMsg')}} form.chat-form(ng-if='user.flags.communityGuidelinesAccepted' ng-submit='postChat(group,message.content)') div(ng-controller='AutocompleteCtrl') @@ -16,7 +16,7 @@ form.chat-form(ng-if='user.flags.communityGuidelinesAccepted' ng-submit='postCha .chat-controls.clearfix .chat-buttons input.btn(type='submit', value=env.t('sendChat'), ng-disabled='_sending') - button.btn(type="button", ng-click='sync(group)', ng-disabled='_sending')=env.t('toolTipMsg') + button.btn(type="button", ng-click='sync(group)', ng-disabled='_sending') {{group.type === 'party' ? env.t('syncPartyAndChat') : env.t('toolTipMsg')}} include ../../shared/formatting-help .chat-controls.clearfix .chat-buttons From a4ecdbeb3efd5ff80e6691f8f2dc54ec407ac2ee Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 7 Sep 2016 16:39:53 +0200 Subject: [PATCH 04/15] fully sync party on system messages --- website/client/js/services/pusherService.js | 30 +++++++++++++++++---- website/server/models/group.js | 6 +++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index ebe1b17354..c4e387dbc3 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -16,7 +16,7 @@ angular.module('habitrpg') var tabIdKey = 'habitica-active-tab'; var tabId = Shared.uuid(); - function connectToPusher (partyId) { + function connectToPusher (partyId, reconnecting) { localStorage.setItem(tabIdKey, tabId); window.onbeforeunload = function () { localStorage.removeItem(tabIdKey); @@ -69,6 +69,17 @@ angular.module('habitrpg') // When the user correctly enters the party channel partyChannel.bind('pusher:subscription_succeeded', function(members) { // TODO members = [{id, info}] + + // If we just reconnected after some inactivity, sync the party + if (reconnecting === true) { + Groups.party(true).then(function (syncedParty) { + // Assign and not replace so that all the references get the modifications + if ($rootScope.party) { + _.assign($rootScope.party, syncedParty); + $rootScope.loadingParty = false; // make sure the party is set as loaded + } + }); + } }); // When a member enters the party channel @@ -97,10 +108,20 @@ angular.module('habitrpg') // When a new chat message is posted partyChannel.bind('new-chat', function (data) { - Groups.party().then(function () { + Groups.party().then(function () { // wait for the party to be fully loaded + $rootScope.loadingParty = false; // make sure the party is set as loaded + // Update the party data Groups.data.party.chat.unshift(data); Groups.data.party.chat.splice(200); + + // If a system message comes in, sync the party as quest status may have changed + if (data.uuid === 'system') { + Groups.party(true).then(function (syncedParty) { + // Assign and not replace so that all the references get the modifications + _.assign($rootScope.party, syncedParty); + }); + } }); }); }; @@ -112,12 +133,11 @@ angular.module('habitrpg') console.log('Reconnecting to Pusher.'); $(document).off('mousemove keydown mousedown touchstart', awaitActivity); if (!localStorage.getItem(tabIdKey) || localStorage.getItem(tabIdKey) === tabId) { - connectToPusher(partyId); + connectToPusher(partyId, true); } }; $(document).on('mousemove keydown mousedown touchstart', awaitActivity); - }; // Setup chat channels once app is ready, only for parties for now @@ -144,7 +164,7 @@ angular.module('habitrpg') if (e.key === tabIdKey && e.newValue === null) { setTimeout(function () { if (!localStorage.getItem(tabIdKey)) { - connectToPusher(partyId); + connectToPusher(partyId, true); } }, Math.floor(Math.random() * 501) + 100); } diff --git a/website/server/models/group.js b/website/server/models/group.js index 68393172ad..c9a275679b 100644 --- a/website/server/models/group.js +++ b/website/server/models/group.js @@ -351,6 +351,12 @@ schema.methods.sendChat = function sendChat (message, user) { User.update(query, lastSeenUpdate, {multi: true}).exec(); + // If the message being sent is a system message (not gone through the api.postChat controller) + // then notify Pusher about it (only parties for now) + if (newMessage.uuid === 'system' && this.privacy === 'private' && this.type === 'party') { + pusher.trigger(`presence-group-${this._id}`, 'new-chat', newMessage); + } + return newMessage; }; From 0baff2dfd98bcb20d5bd1b38231c4c2e46944b34 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 7 Sep 2016 16:44:20 +0200 Subject: [PATCH 05/15] remove limit of 1 connected tab per browser --- website/client/js/services/pusherService.js | 46 ++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index c4e387dbc3..a8eec49a66 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -13,14 +13,17 @@ angular.module('habitrpg') pusher: undefined, socketId: undefined, // when defined the user is connected }; - var tabIdKey = 'habitica-active-tab'; - var tabId = Shared.uuid(); + + // Limit of 1 connected tab is disabled for now + // var tabIdKey = 'habitica-active-tab'; + // var tabId = Shared.uuid(); function connectToPusher (partyId, reconnecting) { - localStorage.setItem(tabIdKey, tabId); - window.onbeforeunload = function () { - localStorage.removeItem(tabIdKey); - } + // Limit of 1 connected tab is disabled for now + // localStorage.setItem(tabIdKey, tabId); + // window.onbeforeunload = function () { + // localStorage.removeItem(tabIdKey); + // } api.pusher = new Pusher(window.env['PUSHER:KEY'], { encrypted: true, @@ -40,7 +43,6 @@ angular.module('habitrpg') var awaitIdle = function() { if(disconnectionTimeout) clearTimeout(disconnectionTimeout); disconnectionTimeout = setTimeout(function () { - console.log('Disconnecting from Pusher.'); $(document).off('mousemove keydown mousedown touchstart', awaitIdle); disconnectPusher(); }, DISCONNECTION_AFTER); @@ -130,11 +132,8 @@ angular.module('habitrpg') api.pusher.disconnect(); var awaitActivity = function() { - console.log('Reconnecting to Pusher.'); $(document).off('mousemove keydown mousedown touchstart', awaitActivity); - if (!localStorage.getItem(tabIdKey) || localStorage.getItem(tabIdKey) === tabId) { - connectToPusher(partyId, true); - } + connectToPusher(partyId, true); }; $(document).on('mousemove keydown mousedown touchstart', awaitActivity); @@ -153,22 +152,23 @@ angular.module('habitrpg') partyId = user && $rootScope.user.party && $rootScope.user.party._id; if (!partyId) return; + // DISABLED FOR NOW // See if another tab is already connected to Pusher - if (!localStorage.getItem(tabIdKey)) { - connectToPusher(partyId); - } + // if (!localStorage.getItem(tabIdKey)) { + // connectToPusher(partyId); + // } // when a tab is closed, connect the next one // wait between 100 and 500ms to avoid two tabs connecting at the same time - window.addEventListener('storage', function(e) { - if (e.key === tabIdKey && e.newValue === null) { - setTimeout(function () { - if (!localStorage.getItem(tabIdKey)) { - connectToPusher(partyId, true); - } - }, Math.floor(Math.random() * 501) + 100); - } - }); + // window.addEventListener('storage', function(e) { + // if (e.key === tabIdKey && e.newValue === null) { + // setTimeout(function () { + // if (!localStorage.getItem(tabIdKey)) { + // connectToPusher(partyId, true); + // } + // }, Math.floor(Math.random() * 501) + 100); + // } + // }); }); return api; From 40c9c055141d1202d289ae174b86c656bd2cba44 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 7 Sep 2016 16:46:32 +0200 Subject: [PATCH 06/15] fix first connection to pusher --- website/client/js/services/pusherService.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index a8eec49a66..9358a19ce1 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -152,6 +152,8 @@ angular.module('habitrpg') partyId = user && $rootScope.user.party && $rootScope.user.party._id; if (!partyId) return; + connectToPusher(partyId); + // DISABLED FOR NOW // See if another tab is already connected to Pusher // if (!localStorage.getItem(tabIdKey)) { From 85c4332a403772e004e6b7ed7145fb41ae5d1cd7 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 7 Sep 2016 16:51:22 +0200 Subject: [PATCH 07/15] pusher: remove commented code that is unused --- website/client/js/services/pusherService.js | 28 --------------------- 1 file changed, 28 deletions(-) diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index 9358a19ce1..948c1bf77c 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -14,17 +14,7 @@ angular.module('habitrpg') socketId: undefined, // when defined the user is connected }; - // Limit of 1 connected tab is disabled for now - // var tabIdKey = 'habitica-active-tab'; - // var tabId = Shared.uuid(); - function connectToPusher (partyId, reconnecting) { - // Limit of 1 connected tab is disabled for now - // localStorage.setItem(tabIdKey, tabId); - // window.onbeforeunload = function () { - // localStorage.removeItem(tabIdKey); - // } - api.pusher = new Pusher(window.env['PUSHER:KEY'], { encrypted: true, authEndpoint: '/api/v3/user/auth/pusher', @@ -153,24 +143,6 @@ angular.module('habitrpg') if (!partyId) return; connectToPusher(partyId); - - // DISABLED FOR NOW - // See if another tab is already connected to Pusher - // if (!localStorage.getItem(tabIdKey)) { - // connectToPusher(partyId); - // } - - // when a tab is closed, connect the next one - // wait between 100 and 500ms to avoid two tabs connecting at the same time - // window.addEventListener('storage', function(e) { - // if (e.key === tabIdKey && e.newValue === null) { - // setTimeout(function () { - // if (!localStorage.getItem(tabIdKey)) { - // connectToPusher(partyId, true); - // } - // }, Math.floor(Math.random() * 501) + 100); - // } - // }); }); return api; From ea2be454141413b162cb1dd07e3e670477203bd5 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 7 Sep 2016 17:16:32 +0200 Subject: [PATCH 08/15] add notifications for real time messages --- website/client/js/services/chatServices.js | 6 +++--- website/client/js/services/pusherService.js | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/website/client/js/services/chatServices.js b/website/client/js/services/chatServices.js index b6eab706a0..993b1a3f2b 100644 --- a/website/client/js/services/chatServices.js +++ b/website/client/js/services/chatServices.js @@ -1,8 +1,8 @@ 'use strict'; angular.module('habitrpg') -.factory('Chat', ['$http', 'ApiUrl', 'User', 'Pusher', - function($http, ApiUrl, User, Pusher) { +.factory('Chat', ['$http', 'ApiUrl', 'User', '$rootScope', + function($http, ApiUrl, User, $rootScope) { var apiV3Prefix = '/api/v3'; function getChat (groupId) { @@ -24,7 +24,7 @@ angular.module('habitrpg') url: url, data: { message: message, - pusherSocketId: Pusher.socketId, // to make sure the send doesn't get notified of it's own message + pusherSocketId: $rootScope.pusherSocketId, // to make sure the send doesn't get notified of it's own message } }); } diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index 948c1bf77c..d9b0117010 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -1,8 +1,8 @@ 'use strict'; angular.module('habitrpg') -.factory('Pusher', ['$rootScope', 'STORAGE_SETTINGS_ID', 'Groups', 'Shared', - function($rootScope, STORAGE_SETTINGS_ID, Groups, Shared) { +.factory('Pusher', ['$rootScope', 'STORAGE_SETTINGS_ID', 'Groups', 'Shared', '$state', 'Chat', + function($rootScope, STORAGE_SETTINGS_ID, Groups, Shared, $state, Chat) { var settings = JSON.parse(localStorage.getItem(STORAGE_SETTINGS_ID)); var IS_PUSHER_ENABLED = window.env['PUSHER:ENABLED'] === 'true'; @@ -47,7 +47,7 @@ angular.module('habitrpg') }); api.pusher.connection.bind('connected', function () { - api.socketId = api.pusher.connection.socket_id; + $rootScope.pusherSocketId = api.socketId = api.pusher.connection.socket_id; }); var partyChannelName = 'presence-group-' + partyId; @@ -114,6 +114,15 @@ angular.module('habitrpg') _.assign($rootScope.party, syncedParty); }); } + + if ($state.is('options.social.party')) { // if we're on the party page, mark the chat as read + Chat.markChatSeen($rootScope.party._id); + } else { // show a notification + $rootScope.User.user.newMessages[$rootScope.party._id] = { + name: $rootScope.party.name, + value: true, + }; + } }); }); }; From cac764e5d11ed7062dbcf060ee5eb8626e1b5027 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 8 Sep 2016 18:48:07 +0200 Subject: [PATCH 09/15] add online indicator for party members --- common/locales/en/generic.json | 6 ++- website/client/js/controllers/partyCtrl.js | 9 ++-- website/client/js/controllers/rootCtrl.js | 5 +- website/client/js/services/pusherService.js | 58 ++++++++++++++------- website/views/options/social/group.jade | 5 +- 5 files changed, 57 insertions(+), 26 deletions(-) diff --git a/common/locales/en/generic.json b/common/locales/en/generic.json index 52b9d72a41..325ddb702c 100644 --- a/common/locales/en/generic.json +++ b/common/locales/en/generic.json @@ -182,5 +182,9 @@ "raisePetShare": "I raised a pet into a mount by completing my real-life tasks!", "wonChallengeShare": "I won a challenge in Habitica!", "achievementShare": "I earned a new achievement in Habitica!", - "orderBy": "Order By <%= item %>" + "orderBy": "Order By <%= item %>", + + "you": "you", + "online": "online", + "onlineCount": "<%= count %> online" } diff --git a/website/client/js/controllers/partyCtrl.js b/website/client/js/controllers/partyCtrl.js index c7ddc42908..ec170ab0b5 100644 --- a/website/client/js/controllers/partyCtrl.js +++ b/website/client/js/controllers/partyCtrl.js @@ -1,7 +1,7 @@ 'use strict'; -habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','Challenges','$state','$compile','Analytics','Quests','Social', 'Pusher', - function($rootScope, $scope, Groups, Chat, User, Challenges, $state, $compile, Analytics, Quests, Social, Pusher) { +habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','Challenges','$state','$compile','Analytics','Quests','Social', + function($rootScope, $scope, Groups, Chat, User, Challenges, $state, $compile, Analytics, Quests, Social) { var PARTY_LOADING_MESSAGES = 4; @@ -19,7 +19,10 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User',' $scope.partyLoadingMessage = window.env.t('partyLoading' + partyMessageNumber); function handlePartyResponse (group) { - $rootScope.party = $scope.group = group; + // Assign and not replace so that all the references get the modifications + _.assign($rootScope.party, group); + $scope.group = $rootScope.party; + $scope.group.loadingParty = false; checkForNotifications(); } diff --git a/website/client/js/controllers/rootCtrl.js b/website/client/js/controllers/rootCtrl.js index fc907283e5..fc27c94e54 100644 --- a/website/client/js/controllers/rootCtrl.js +++ b/website/client/js/controllers/rootCtrl.js @@ -3,8 +3,8 @@ /* Make user and settings available for everyone through root scope. */ -habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http', '$state', '$stateParams', 'Notification', 'Groups', 'Shared', 'Content', '$modal', '$timeout', 'ApiUrl', 'Payments','$sce','$window','Analytics','TAVERN_ID', - function($scope, $rootScope, $location, User, $http, $state, $stateParams, Notification, Groups, Shared, Content, $modal, $timeout, ApiUrl, Payments, $sce, $window, Analytics, TAVERN_ID) { +habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http', '$state', '$stateParams', 'Notification', 'Groups', 'Shared', 'Content', '$modal', '$timeout', 'ApiUrl', 'Payments','$sce','$window','Analytics','TAVERN_ID', 'Pusher', + function($scope, $rootScope, $location, User, $http, $state, $stateParams, Notification, Groups, Shared, Content, $modal, $timeout, ApiUrl, Payments, $sce, $window, Analytics, TAVERN_ID, Pusher) { var user = User.user; // Setup page once user is synced @@ -49,6 +49,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$ $rootScope.toJson = angular.toJson; $rootScope.Payments = Payments; $rootScope.userNotifications = []; + $rootScope.party = {}; // to be extended later with real data // Angular UI Router $rootScope.$state = $state; diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index d9b0117010..2c642e26d4 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -59,29 +59,49 @@ angular.module('habitrpg') }); // When the user correctly enters the party channel - partyChannel.bind('pusher:subscription_succeeded', function(members) { - // TODO members = [{id, info}] + partyChannel.bind('pusher:subscription_succeeded', function(pusherMembers) { + // Wait for the party to be loaded + Groups.party(reconnecting ? true : false).then(function (party) { + // If we just reconnected after some inactivity, sync the party + if (reconnecting === true) { + _.assign($rootScope.party, party); + $rootScope.loadingParty = false; // make sure the party is set as loaded + } - // If we just reconnected after some inactivity, sync the party - if (reconnecting === true) { - Groups.party(true).then(function (syncedParty) { - // Assign and not replace so that all the references get the modifications - if ($rootScope.party) { - _.assign($rootScope.party, syncedParty); - $rootScope.loadingParty = false; // make sure the party is set as loaded + $rootScope.party.onlineUsers = pusherMembers.count; + + $rootScope.party.members.forEach(function (member) { + if (pusherMembers.members[member._id]) { + member.online = true; } }); - } - }); + }); + + // When a member enters the party channel + partyChannel.bind('pusher:member_added', function(pusherMember) { + $rootScope.$apply(function() { + $rootScope.party.members.find(function (partyMember) { + if (partyMember._id === pusherMember.id) { + partyMember.online = true; + return true; + } + }); + $rootScope.party.onlineUsers++; + }); + }); - // When a member enters the party channel - partyChannel.bind('pusher:member_added', function(member) { - // TODO member = {id, info} - }); - - // When a member leaves the party channel - partyChannel.bind('pusher:member_removed', function(member) { - // TODO member = {id, info} + // When a member leaves the party channel + partyChannel.bind('pusher:member_removed', function(pusherMember) { + $rootScope.$apply(function() { + $rootScope.party.onlineUsers--; + $rootScope.party.members.find(function (partyMember) { + if (partyMember._id === pusherMember.id) { + partyMember.online = false; + return true; + } + }); + }); + }); }); // When the user is booted from the party, they get disconnected from Pusher diff --git a/website/views/options/social/group.jade b/website/views/options/social/group.jade index 4eb78e45a9..2d1b541742 100644 --- a/website/views/options/social/group.jade +++ b/website/views/options/social/group.jade @@ -69,6 +69,7 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter .panel-heading h3.panel-title =env.t('members') + span(ng-if='group.type=="party"')= ' (' + env.t('onlineCount', {count: "{{group.onlineUsers}}"}) + ')' button.pull-right.btn.btn-primary(ng-click="openInviteModal(group)")=env.t("inviteFriends") .panel-body.modal-fixed-height @@ -84,7 +85,9 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter span(ng-click='clickMember(member._id, true)') | {{member.profile.name}} span(ng-if='group.type === "party"') - | (#[strong {{member.stats.hp.toFixed(1)}}] #{env.t('hp')}) + | (#[strong {{member.stats.hp.toFixed(1)}}] #{env.t('hp')}) {{member.id === user.id ? ' (' + env.t('you') + ') ' : ''}} + .pull-right(ng-if='group.type === "party"') + span.text-success {{member.online ? '● ' + env.t('online') : ''}} tr(ng-if='::group.memberCount > group.members.length') td span.badge {{group.memberCount - group.members.length}} From 136b4ada45c9b465d43591e4eebdf26ba0e6a0a2 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 8 Sep 2016 19:05:03 +0200 Subject: [PATCH 10/15] renable limit on number of tabs connected --- website/client/js/services/pusherService.js | 29 +++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index 2c642e26d4..2cea4488d9 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -13,8 +13,17 @@ angular.module('habitrpg') pusher: undefined, socketId: undefined, // when defined the user is connected }; + var tabIdKey = 'habitica-active-tab'; + var tabId = Shared.uuid(); + function connectToPusher (partyId, reconnecting) { + // Limit 1 tab connected per user + localStorage.setItem(tabIdKey, tabId); + window.onbeforeunload = function () { + localStorage.removeItem(tabIdKey); + } + api.pusher = new Pusher(window.env['PUSHER:KEY'], { encrypted: true, authEndpoint: '/api/v3/user/auth/pusher', @@ -152,7 +161,9 @@ angular.module('habitrpg') var awaitActivity = function() { $(document).off('mousemove keydown mousedown touchstart', awaitActivity); - connectToPusher(partyId, true); + if (!localStorage.getItem(tabIdKey) || localStorage.getItem(tabIdKey) === tabId) { + connectToPusher(partyId, true); + } }; $(document).on('mousemove keydown mousedown touchstart', awaitActivity); @@ -171,7 +182,21 @@ angular.module('habitrpg') partyId = user && $rootScope.user.party && $rootScope.user.party._id; if (!partyId) return; - connectToPusher(partyId); + if (!localStorage.getItem(tabIdKey)) { + connectToPusher(partyId); + } + + // when a tab is closed, connect the next one + // wait between 100 and 500ms to avoid two tabs connecting at the same time + window.addEventListener('storage', function(e) { + if (e.key === tabIdKey && e.newValue === null) { + setTimeout(function () { + if (!localStorage.getItem(tabIdKey)) { + connectToPusher(partyId, true); + } + }, Math.floor(Math.random() * 501) + 100); + } + }); }); return api; From a748e57cd776c4b789a50622eb6e562afcd69d42 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 9 Sep 2016 19:11:21 +0200 Subject: [PATCH 11/15] do not sync automatically on chat seen requests --- website/client/js/config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/client/js/config.js b/website/client/js/config.js index 1c145d5475..6ac3097f42 100644 --- a/website/client/js/config.js +++ b/website/client/js/config.js @@ -13,13 +13,14 @@ angular.module('habitrpg') var isUserAvailable = $rootScope.appLoaded === true; var hasUserV = response.data && response.data.userV; var isNotSync = response.config.url.indexOf('/api/v3/user') !== 0 || response.config.method !== 'GET'; + var isNotMarkChatSeen = response.config.url.indexOf('/chat/seen') === -1; // exclude chat seen requests because with real time chat they would be too many if (isApiCall && isUserAvailable && hasUserV) { var oldUserV = $rootScope.User.user._v; $rootScope.User.user._v = response.data.userV; // Something has changed on the user object that was not tracked here, sync the user - if (isNotSync && ($rootScope.User.user._v - oldUserV) > 1) { + if (isNotMarkChatSeen && isNotSync && ($rootScope.User.user._v - oldUserV) > 1) { $rootScope.User.sync(); } } From 98df0f26e7999cd7cc1dce47a3f5fa1ecf8b962d Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 9 Sep 2016 20:12:17 +0200 Subject: [PATCH 12/15] add notifications, fix too many seen requests and misc fixes --- common/locales/en/groups.json | 4 ++- website/client/js/controllers/chatCtrl.js | 3 -- website/client/js/controllers/partyCtrl.js | 10 +++--- .../js/services/notificationServices.js | 14 +++++--- website/client/js/services/pusherService.js | 33 +++++++++++++++---- 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/common/locales/en/groups.json b/common/locales/en/groups.json index 4ca12b3cd6..a8aed20de8 100644 --- a/common/locales/en/groups.json +++ b/common/locales/en/groups.json @@ -194,5 +194,7 @@ "canOnlyInviteMaxInvites": "You can only invite \"<%= maxInvites %>\" at a time", "onlyCreatorOrAdminCanDeleteChat": "Not authorized to delete this message!", "onlyGroupLeaderCanEditTasks": "Not authorized to manage tasks!", - "onlyGroupTasksCanBeAssigned": "Only group tasks can be assigned" + "onlyGroupTasksCanBeAssigned": "Only group tasks can be assigned", + "newChatMessagePlainNotification": "New message in <%= groupName %> by <%= authorName %>. Click here to open the chat page!", + "newChatMessageTitle": "New message in <%= groupName %>" } diff --git a/website/client/js/controllers/chatCtrl.js b/website/client/js/controllers/chatCtrl.js index 976d5d4142..649a06b9a7 100644 --- a/website/client/js/controllers/chatCtrl.js +++ b/website/client/js/controllers/chatCtrl.js @@ -2,9 +2,6 @@ habitrpg.controller('ChatCtrl', ['$scope', 'Groups', 'Chat', 'User', '$http', 'ApiUrl', 'Notification', 'Members', '$rootScope', 'Analytics', function($scope, Groups, Chat, User, $http, ApiUrl, Notification, Members, $rootScope, Analytics){ - if ($scope.group) { - Chat.markChatSeen($scope.group.id); - } $scope.message = {content:''}; $scope._sending = false; diff --git a/website/client/js/controllers/partyCtrl.js b/website/client/js/controllers/partyCtrl.js index ec170ab0b5..615b8c8834 100644 --- a/website/client/js/controllers/partyCtrl.js +++ b/website/client/js/controllers/partyCtrl.js @@ -24,6 +24,12 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User',' $scope.group = $rootScope.party; $scope.group.loadingParty = false; checkForNotifications(); + if ($state.is('options.social.party')) { + if ('Notification' in window && window.Notification.permission === 'default') { + window.Notification.requestPermission(); + } + Chat.markChatSeen($scope.group._id); + } } function handlePartyError (response) { @@ -52,10 +58,6 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User',' } } - if ($scope.group && $scope.group._id) { - Chat.markChatSeen($scope.group._id); - } - $scope.create = function(group) { group.loadingParty = true; diff --git a/website/client/js/services/notificationServices.js b/website/client/js/services/notificationServices.js index b6b854cde1..3730910cef 100644 --- a/website/client/js/services/notificationServices.js +++ b/website/client/js/services/notificationServices.js @@ -93,9 +93,9 @@ angular.module("habitrpg").factory("Notification", _notify(window.env.t('streakName') + ': ' + val, 'streak', 'glyphicon glyphicon-repeat'); } - function text(val){ + function text(val, onClick){ if (val) { - _notify(val, 'info'); + _notify(val, 'info', null, null, onClick); } } @@ -114,7 +114,7 @@ angular.module("habitrpg").factory("Notification", // Used to stack notifications, must be outside of _notify var stack_topright = {"dir1": "down", "dir2": "left", "spacing1": 15, "spacing2": 15, "firstpos1": 60}; - function _notify(html, type, icon, canHide) { + function _notify(html, type, icon, canHide, onClick) { var notice = $.pnotify({ type: type || 'warning', //('info', 'text', 'warning', 'success', 'gp', 'xp', 'hp', 'lvl', 'death', 'mp', 'crit') text: html, @@ -126,7 +126,13 @@ angular.module("habitrpg").factory("Notification", width: "250px", stack: stack_topright, icon: icon || false - }).click(function() { notice.pnotify_remove() }); + }).click(function() { + notice.pnotify_remove(); + + if (onClick) { + onClick(); + } + }); } return { diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index 491a99263b..ba0b439cc9 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -1,8 +1,8 @@ 'use strict'; angular.module('habitrpg') -.factory('Pusher', ['$rootScope', 'STORAGE_SETTINGS_ID', 'Groups', 'Shared', '$state', 'Chat', - function($rootScope, STORAGE_SETTINGS_ID, Groups, Shared, $state, Chat) { +.factory('Pusher', ['$rootScope', 'STORAGE_SETTINGS_ID', 'Groups', 'Shared', '$state', 'Chat', 'Notification', + function($rootScope, STORAGE_SETTINGS_ID, Groups, Shared, $state, Chat, Notification) { var settings = JSON.parse(localStorage.getItem(STORAGE_SETTINGS_ID)); var IS_PUSHER_ENABLED = window.env['PUSHER:ENABLED'] === 'true'; @@ -128,29 +128,50 @@ angular.module('habitrpg') }); // When a new chat message is posted - partyChannel.bind('new-chat', function (data) { + partyChannel.bind('new-chat', function (chatData) { Groups.party().then(function () { // wait for the party to be fully loaded $rootScope.loadingParty = false; // make sure the party is set as loaded // Update the party data - Groups.data.party.chat.unshift(data); + Groups.data.party.chat.unshift(chatData); Groups.data.party.chat.splice(200); // If a system message comes in, sync the party as quest status may have changed - if (data.uuid === 'system') { + if (chatData.uuid === 'system') { Groups.party(true).then(function (syncedParty) { // Assign and not replace so that all the references get the modifications _.assign($rootScope.party, syncedParty); }); } - if ($state.is('options.social.party')) { // if we're on the party page, mark the chat as read + if ($state.is('options.social.party') && document.hasFocus()) { // if we're on the party page, mark the chat as read Chat.markChatSeen($rootScope.party._id); } else { // show a notification $rootScope.User.user.newMessages[$rootScope.party._id] = { name: $rootScope.party.name, value: true, }; + + if ('Notification' in window && window.Notification.permission === 'granted') { + var notif = new window.Notification(env.t('newChatMessageTitle', { + groupName: $rootScope.party.name, + }), { + body: (chatData.user || chatData.uuid) + ': ' + chatData.text, + icon: '/favicon_192x192-00993687.png?v=4' + }); + + notif.addEventListener('click', function () { + $state.go('options.social.party'); + notif.close(); + }); + } else { + Notification.text(env.t('newChatMessagePlainNotification', { + groupName: $rootScope.party.name, + authorName: chatData.user || chatData.uuid, + }), function() { + $state.go('options.social.party'); + }); + } } }); }); From f6c765b7b541ea35e4628af1d6777d4133372825 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 9 Sep 2016 21:03:47 +0200 Subject: [PATCH 13/15] better notifications icon --- common/img/gryphon_192-20.png | Bin 0 -> 4058 bytes website/client/js/services/pusherService.js | 2 +- website/views/index.jade | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 common/img/gryphon_192-20.png diff --git a/common/img/gryphon_192-20.png b/common/img/gryphon_192-20.png new file mode 100644 index 0000000000000000000000000000000000000000..045d89d37c9c6af17bfb252b54b3af8051134cb4 GIT binary patch literal 4058 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 VUC2IMiTcya0lFANbUn&G>VN&dVvYa+ literal 0 HcmV?d00001 diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index ba0b439cc9..b0a2ee3bc2 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -157,7 +157,7 @@ angular.module('habitrpg') groupName: $rootScope.party.name, }), { body: (chatData.user || chatData.uuid) + ': ' + chatData.text, - icon: '/favicon_192x192-00993687.png?v=4' + icon: '/common/img/gryphon_192-20.png' }); notif.addEventListener('click', function () { diff --git a/website/views/index.jade b/website/views/index.jade index 77c44c3c06..e2356e04a3 100644 --- a/website/views/index.jade +++ b/website/views/index.jade @@ -4,9 +4,9 @@ html(ng-app='habitrpg', ng-controller='RootCtrl', ng-class='{"applying-action":a head title(ng-bind="env.t('habitica') + ' | ' + $root.pageTitle") // ?v=1 needed to force refresh - link(rel='shortcut icon', sizes="32x32", href='#{env.getBuildUrl("favicon.ico")}?v=4') - link(rel='shortcut icon', sizes="144x144", href='#{env.getBuildUrl("favicon_192x192.png")}?v=4') - link(rel='mask-icon', href='#{env.getBuildUrl("favicon.ico")}?v=4') + link(rel='shortcut icon', sizes="32x32", href='#{env.getBuildUrl("favicon.ico")}') + link(rel='shortcut icon', sizes="144x144", href='#{env.getBuildUrl("favicon_192x192.png")}') + link(rel='mask-icon', href='#{env.getBuildUrl("favicon.ico")}') meta(charset='utf-8') meta(name='viewport', content='width=device-width, initial-scale=1.0') From 60f7a1dbd97e59cf06cf6cf89926b62e25cd40a7 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 9 Sep 2016 21:26:40 +0200 Subject: [PATCH 14/15] add small timeout before asking for notification permission --- website/client/js/controllers/partyCtrl.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/client/js/controllers/partyCtrl.js b/website/client/js/controllers/partyCtrl.js index 69ec7bad4b..cb06e4d601 100644 --- a/website/client/js/controllers/partyCtrl.js +++ b/website/client/js/controllers/partyCtrl.js @@ -26,7 +26,9 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User',' checkForNotifications(); if ($state.is('options.social.party')) { if ('Notification' in window && window.Notification.permission === 'default') { - window.Notification.requestPermission(); + setTimeout(function () { + window.Notification.requestPermission(); + }, 100); } Chat.markChatSeen($scope.group._id); } From 2d6223377fee037be55e47273c0f18e2c6a32b94 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 9 Sep 2016 21:34:24 +0200 Subject: [PATCH 15/15] chat: better behavior for menu notification --- website/client/js/services/pusherService.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/website/client/js/services/pusherService.js b/website/client/js/services/pusherService.js index b0a2ee3bc2..fd2a873c5a 100644 --- a/website/client/js/services/pusherService.js +++ b/website/client/js/services/pusherService.js @@ -144,7 +144,10 @@ angular.module('habitrpg') }); } - if ($state.is('options.social.party') && document.hasFocus()) { // if we're on the party page, mark the chat as read + var docHasFocus = document.hasFocus(); + var isOnPartyPage = $state.is('options.social.party'); + + if (isOnPartyPage && docHasFocus) { // if we're on the party page, mark the chat as read Chat.markChatSeen($rootScope.party._id); } else { // show a notification $rootScope.User.user.newMessages[$rootScope.party._id] = { @@ -161,7 +164,8 @@ angular.module('habitrpg') }); notif.addEventListener('click', function () { - $state.go('options.social.party'); + if (!isOnPartyPage) $state.go('options.social.party'); + if (!docHasFocus) Chat.markChatSeen($rootScope.party._id); notif.close(); }); } else { @@ -169,7 +173,8 @@ angular.module('habitrpg') groupName: $rootScope.party.name, authorName: chatData.user || chatData.uuid, }), function() { - $state.go('options.social.party'); + if (!isOnPartyPage) $state.go('options.social.party'); + if (!docHasFocus) Chat.markChatSeen($rootScope.party._id); }); } }