diff --git a/html/src/app.js b/html/src/app.js
index 2259e25c..140a7772 100644
--- a/html/src/app.js
+++ b/html/src/app.js
@@ -3585,14 +3585,31 @@ speechSynthesis.getVoices();
pendingUpdate: false
};
+ $app.data.appInit = false;
+ $app.data.notyInit = false;
+
+ API.$on('LOGIN', function (args) {
+ sharedRepository.setArray('wristFeed', []);
+ sharedRepository.setArray('notyFeed', []);
+ setTimeout(function() {
+ $app.appInit = true;
+ $app.updateSharedFeed(true);
+ $app.notyInit = true;
+ sharedRepository.setBool('VRInit', true);
+ }, 10000);
+ });
+
$app.methods.updateSharedFeed = function (forceUpdate) {
+ if (!this.appInit) {
+ return;
+ }
this.updateSharedFeedGameLog(forceUpdate);
this.updateSharedFeedFeedTable(forceUpdate);
this.updateSharedFeedNotificationTable(forceUpdate);
this.updateSharedFeedFriendLogTable(forceUpdate);
this.updateSharedFeedPlayerModerationTable(forceUpdate);
var feeds = this.sharedFeed;
- if (feeds.pendingUpdate === false) {
+ if (!feeds.pendingUpdate) {
return;
}
var wristFeed = [];
@@ -3663,6 +3680,7 @@ speechSynthesis.getVoices();
notyFeed.splice(5);
sharedRepository.setArray('wristFeed', wristFeed);
sharedRepository.setArray('notyFeed', notyFeed);
+ this.playNoty(notyFeed);
feeds.pendingUpdate = false;
};
@@ -3676,6 +3694,8 @@ speechSynthesis.getVoices();
return;
}
this.sharedFeed.gameLog.lastEntryDate = data[i - 1].created_at;
+ } else {
+ return;
}
var bias = new Date(Date.now() - 86400000).toJSON(); //24 hours
var wristArr = [];
@@ -3698,21 +3718,21 @@ speechSynthesis.getVoices();
var locationBias = new Date(Date.parse(ctx.created_at) + 10000).toJSON(); //10 seconds
for (var k = w - 1; k > -1; k--) {
var feedItem = wristArr[k];
- if (feedItem.type === 'OnPlayerJoined') {
- wristArr.splice(k, 1);
- w--;
- }
- if ((feedItem.created_at > locationBias) || (feedItem.type === 'Location')) {
- break;
- }
+ if (feedItem.type === 'OnPlayerJoined') {
+ wristArr.splice(k, 1);
+ w--;
}
- for (var k = n - 1; k > -1; k--) {
- var feedItem = notyArr[k];
- if (feedItem.type === 'OnPlayerJoined') {
- notyArr.splice(k, 1);
- n--;
- }
- if (feedItem.created_at > locationBias) {
+ if ((feedItem.created_at > locationBias) || (feedItem.type === 'Location')) {
+ break;
+ }
+ }
+ for (var k = n - 1; k > -1; k--) {
+ var feedItem = notyArr[k];
+ if (feedItem.type === 'OnPlayerJoined') {
+ notyArr.splice(k, 1);
+ n--;
+ }
+ if (feedItem.created_at > locationBias) {
break;
}
}
@@ -3769,6 +3789,8 @@ speechSynthesis.getVoices();
return;
}
this.sharedFeed.feedTable.lastEntryDate = data[i - 1].created_at;
+ } else {
+ return;
}
var bias = new Date(Date.now() - 86400000).toJSON(); //24 hours
var wristArr = [];
@@ -3828,6 +3850,8 @@ speechSynthesis.getVoices();
return;
}
this.sharedFeed.notificationTable.lastEntryDate = data[i - 1].created_at;
+ } else {
+ return;
}
var bias = new Date(Date.now() - 86400000).toJSON(); //24 hours
var wristArr = [];
@@ -3884,6 +3908,8 @@ speechSynthesis.getVoices();
return;
}
this.sharedFeed.friendLogTable.lastEntryDate = data[i - 1].created_at;
+ } else {
+ return;
}
var bias = new Date(Date.now() - 86400000).toJSON(); //24 hours
var wristArr = [];
@@ -3940,6 +3966,8 @@ speechSynthesis.getVoices();
return;
}
this.sharedFeed.playerModerationTable.lastEntryDate = data[i - 1].created;
+ } else {
+ return;
}
var bias = new Date(Date.now() - 86400000).toJSON(); //24 hours
var wristArr = [];
@@ -3984,6 +4012,256 @@ speechSynthesis.getVoices();
this.sharedFeed.pendingUpdate = true;
};
+ $app.data.notyMap = [];
+
+ $app.methods.playNoty = async function (notyFeed) {
+ var notyToPlay = [];
+ notyFeed.forEach((feed) => {
+ var displayName = '';
+ if (feed.displayName) {
+ displayName = feed.displayName;
+ } else if (feed.senderUsername) {
+ displayName = feed.senderUsername;
+ } else if (feed.sourceDisplayName) {
+ displayName = feed.sourceDisplayName;
+ } else if (feed.data) {
+ displayName = feed.data;
+ } else {
+ console.error('missing displayName');
+ }
+ if ((displayName) && (!this.notyMap[displayName]) ||
+ (this.notyMap[displayName] < feed.created_at)) {
+ this.notyMap[displayName] = feed.created_at;
+ notyToPlay.push(feed);
+ }
+ });
+ // disable notifications when busy
+ if ((this.currentUserStatus === 'busy') || (!this.notyInit)) {
+ return;
+ }
+ var bias = new Date(Date.now() - 60000).toJSON();
+ var noty = {};
+ var messageList = [ 'inviteMessage', 'requestMessage', 'responseMessage' ];
+ for (var i = 0; i < notyToPlay.length; i++) {
+ noty = notyToPlay[i];
+ if (noty.created_at < bias) {
+ continue;
+ }
+ var message = '';
+ for (i = 0; i < messageList.length; i++) {
+ if (typeof noty.details !== 'undefined' && typeof noty.details[messageList[i]] !== 'undefined') {
+ message = noty.details[messageList[i]];
+ }
+ }
+ if ((this.notificationTTS) && (this.isGameRunning)) {
+ this.playNotyTTS(noty, message);
+ }
+ if ((this.desktopToast === 'Always') ||
+ ((this.desktopToast === 'Game Closed') && (!this.isGameRunning)) ||
+ ((this.desktopToast === 'Desktop Mode') && (this.isGameNoVR) && (this.isGameRunning))) {
+ this.displayDesktopToast(noty, message);
+ }
+ }
+ };
+
+ $app.methods.playNotyTTS = async function (noty, message) {
+ switch (noty.type) {
+ case 'OnPlayerJoined':
+ this.speak(`${noty.data} has joined`);
+ break;
+ case 'OnPlayerLeft':
+ this.speak(`${noty.data} has left`);
+ break;
+ case 'OnPlayerJoining':
+ this.speak(`${noty.displayName} is joining`);
+ break;
+ case 'GPS':
+ this.speak(`${noty.displayName} is in ${await this.displayLocation(noty.location[0])}`);
+ break;
+ case 'Online':
+ this.speak(`${noty.displayName} has logged in`);
+ break;
+ case 'Offline':
+ this.speak(`${noty.displayName} has logged out`);
+ break;
+ case 'Status':
+ this.speak(`${noty.displayName} status is now ${noty.status[0].status} ${noty.status[0].statusDescription}`);
+ break;
+ case 'invite':
+ this.speak(`${noty.senderUsername} has invited you to ${noty.details.worldName} ${message}`);
+ break;
+ case 'requestInvite':
+ this.speak(`${noty.senderUsername} has requested an invite ${message}`);
+ break;
+ case 'inviteResponse':
+ this.speak(`${noty.senderUsername} has responded to your invite ${message}`);
+ break;
+ case 'requestInviteResponse':
+ this.speak(`${noty.senderUsername} has responded to your invite request ${message}`);
+ break;
+ case 'friendRequest':
+ this.speak(`${noty.senderUsername} has sent you a friend request`);
+ break;
+ case 'Friend':
+ this.speak(`${noty.displayName} is now your friend`);
+ break;
+ case 'Unfriend':
+ this.speak(`${noty.displayName} is no longer your friend`);
+ break;
+ case 'TrustLevel':
+ this.speak(`${noty.displayName} trust level is now ${noty.trustLevel}`);
+ break;
+ case 'DisplayName':
+ this.speak(`${noty.previousDisplayName} changed their name to ${noty.displayName}`);
+ break;
+ case 'showAvatar':
+ this.speak(`${noty.sourceDisplayName} has shown your avatar`);
+ break;
+ case 'hideAvatar':
+ this.speak(`${noty.sourceDisplayName} has hidden your avatar`);
+ break;
+ case 'block':
+ this.speak(`${noty.sourceDisplayName} has blocked you`);
+ break;
+ case 'mute':
+ this.speak(`${noty.sourceDisplayName} has muted you`);
+ break;
+ case 'unmute':
+ this.speak(`${noty.sourceDisplayName} has unmuted you`);
+ break;
+ default:
+ break;
+ }
+ };
+
+ $app.methods.displayDesktopToast = async function (noty, message) {
+ var imageURL = '';
+ var userId = '';
+ if (noty.userId) {
+ userId = noty.userId;
+ } else if (noty.senderUserId) {
+ userId = noty.senderUserId;
+ } else if (noty.sourceUserId) {
+ userId = noty.sourceUserId;
+ } else if (noty.data) {
+ for (var ref of API.cachedUsers.values()) {
+ if (ref.displayName === noty.data) {
+ userId = ref.id;
+ break;
+ }
+ }
+ }
+ if (userId) {
+ imageURL = await API.getCachedUser({
+ userId: userId
+ }).catch((err) => {
+ throw err;
+ }).then((args) => {
+ if ((this.displayVRCPlusIconsAsAvatar) && (args.json.userIcon)) {
+ return args.json.userIcon;
+ }
+ return args.json.currentAvatarThumbnailImageUrl;
+ });
+ }
+ switch (noty.type) {
+ case 'OnPlayerJoined':
+ AppApi.DesktopNotification(noty.data, 'has joined', imageURL);
+ break;
+ case 'OnPlayerLeft':
+ AppApi.DesktopNotification(noty.data, 'has left', imageURL);
+ break;
+ case 'OnPlayerJoining':
+ AppApi.DesktopNotification(noty.displayName, 'is joining', imageURL);
+ break;
+ case 'GPS':
+ AppApi.DesktopNotification(noty.displayName, `is in ${await this.displayLocation(noty.location[0])}`, imageURL);
+ break;
+ case 'Online':
+ AppApi.DesktopNotification(noty.displayName, 'has logged in', imageURL);
+ break;
+ case 'Offline':
+ AppApi.DesktopNotification(noty.displayName, 'has logged out', imageURL);
+ break;
+ case 'Status':
+ AppApi.DesktopNotification(noty.displayName, `status is now ${noty.status[0].status} ${noty.status[0].statusDescription}`, imageURL);
+ break;
+ case 'invite':
+ AppApi.DesktopNotification(noty.senderUsername, `has invited you to ${noty.details.worldName} ${message}`, imageURL);
+ break;
+ case 'requestInvite':
+ AppApi.DesktopNotification(noty.senderUsername, `has requested an invite ${message}`, imageURL);
+ break;
+ case 'inviteResponse':
+ AppApi.DesktopNotification(noty.senderUsername, `has responded to your invite ${message}`, imageURL);
+ break;
+ case 'requestInviteResponse':
+ AppApi.DesktopNotification(noty.senderUsername, `has responded to your invite request ${message}`, imageURL);
+ break;
+ case 'friendRequest':
+ AppApi.DesktopNotification(noty.senderUsername, 'has sent you a friend request', imageURL);
+ break;
+ case 'Friend':
+ AppApi.DesktopNotification(noty.displayName, 'has sent you a friend request', imageURL);
+ break;
+ case 'Unfriend':
+ AppApi.DesktopNotification(noty.displayName, 'is no longer your friend', imageURL);
+ break;
+ case 'TrustLevel':
+ AppApi.DesktopNotification(noty.displayName, `trust level is now ${noty.trustLevel}`, imageURL);
+ break;
+ case 'DisplayName':
+ AppApi.DesktopNotification(noty.previousDisplayName, `changed their name to ${noty.displayName}`, imageURL);
+ break;
+ case 'showAvatar':
+ AppApi.DesktopNotification(noty.sourceDisplayName, `has shown your avatar`, imageURL);
+ break;
+ case 'hideAvatar':
+ AppApi.DesktopNotification(noty.sourceDisplayName, `has hidden your avatar`, imageURL);
+ break;
+ case 'block':
+ AppApi.DesktopNotification(noty.sourceDisplayName, `has blocked you`, imageURL);
+ break;
+ case 'mute':
+ AppApi.DesktopNotification(noty.sourceDisplayName, `has muted you`, imageURL);
+ break;
+ case 'unmute':
+ AppApi.DesktopNotification(noty.sourceDisplayName, `has unmuted you`, imageURL);
+ break;
+ default:
+ break;
+ }
+ };
+
+ $app.methods.displayLocation = async function (location) {
+ var text = '';
+ var L = API.parseLocation(location);
+ if (L.isOffline) {
+ text = 'Offline';
+ } else if (L.isPrivate) {
+ text = 'Private';
+ } else if (L.worldId) {
+ var ref = API.cachedWorlds.get(L.worldId);
+ if (typeof ref === 'undefined') {
+ await API.getWorld({
+ worldId: L.worldId
+ }).then((args) => {
+ if (L.tag === location) {
+ if (L.instanceId) {
+ text = `${args.json.name} ${L.accessType}`;
+ } else {
+ text = args.json.name;
+ }
+ }
+ });
+ } else if (L.instanceId) {
+ text = `${ref.name} ${L.accessType}`;
+ } else {
+ text = ref.name;
+ }
+ }
+ return text;
+ };
+
$app.methods.notifyMenu = function (index) {
var { menu } = this.$refs;
if (menu.activeIndex !== index) {
diff --git a/html/src/index.pug b/html/src/index.pug
index f45737e9..94c51247 100644
--- a/html/src/index.pug
+++ b/html/src/index.pug
@@ -685,18 +685,18 @@ html
div.options-container-item
span.name Minimal Feed Icons
el-switch(v-model="minimalFeed" :disabled="!openVR")
- div.options-container-item
- span.name Hide Private Worlds
- el-switch(v-model="hidePrivateFromFeed" :disabled="!openVR")
- div.options-container-item
- span.name Hide Joins When Joining
- el-switch(v-model="hideOnPlayerJoined" :disabled="!openVR")
div.options-container-item
span.name Hide VR Devices
el-switch(v-model="hideDevicesFromFeed" :disabled="!openVR")
+ div.options-container-item
+ span.name Hide Private Worlds
+ el-switch(v-model="hidePrivateFromFeed")
+ div.options-container-item
+ span.name Hide Joins When Joining
+ el-switch(v-model="hideOnPlayerJoined")
div.options-container-item
el-button(size="small" icon="el-icon-notebook-2" @click="showWristFeedFiltersDialog()" :disabled="!openVR") Wrist Feed Filters
- el-button(size="small" icon="el-icon-chat-square" @click="showNotyFeedFiltersDialog()" :disabled="!openVR") Notification Filters
+ el-button(size="small" icon="el-icon-chat-square" @click="showNotyFeedFiltersDialog()") Notification Filters
br
span.sub-header VR Notifications
div.options-container-item
@@ -710,16 +710,16 @@ html
div.options-container-item
span.name When to display notifications:
br
- toggle-switch(:options="desktopToastToggleSwitchOption" group="desktopToastToggleSwitchOption" v-model="desktopToast" class="toggle-switch" :class="{ 'disableToggleSwitch': !openVR }" :disabled="!openVR")
+ toggle-switch(:options="desktopToastToggleSwitchOption" group="desktopToastToggleSwitchOption" v-model="desktopToast" class="toggle-switch")
br
span.sub-header TTS Options
div.options-container-item
span.name Notification TTS
- el-switch(v-model="notificationTTS" :disabled="!openVR")
+ el-switch(v-model="notificationTTS")
div.options-container-item
span.name Text-to-Speech Voice
el-dropdown(@command="(voice) => changeTTSVoice(voice)" trigger="click" size="small")
- el-button(v-text="TTSvoices[notificationTTSVoice].name" size="mini" :disabled="!openVR || !notificationTTS")
+ el-button(v-text="TTSvoices[notificationTTSVoice].name" size="mini" :disabled="!notificationTTS")
el-dropdown-menu(#default="dropdown")
el-dropdown-item(v-if="voice" v-for="(voice, index) in TTSvoices" :key="index" v-text="voice.name" :command="index")
div.options-container
diff --git a/html/src/vr.js b/html/src/vr.js
index ca875738..fcd528c4 100644
--- a/html/src/vr.js
+++ b/html/src/vr.js
@@ -727,10 +727,7 @@ speechSynthesis.getVoices();
if (this.appType === '1') {
this.updateCpuUsageLoop();
}
- if (this.appType === '2') {
- this.initNotyMap();
- }
- this.updateLoop();
+ this.initLoop();
return args;
});
}
@@ -747,7 +744,9 @@ speechSynthesis.getVoices();
this.config = newConfig;
this.notyFeedLastEntry = '';
this.wristFeedLastEntry = '';
- this.initNotyMap();
+ if (this.appType === '2') {
+ this.initNotyMap();
+ }
}
} else {
throw 'config not set';
@@ -779,6 +778,14 @@ speechSynthesis.getVoices();
});
};
+ $app.methods.initLoop = async function () {
+ if (!sharedRepository.getBool('VRInit')) {
+ setTimeout(this.initLoop, 500);
+ } else {
+ this.updateLoop();
+ }
+ };
+
$app.methods.updateLoop = async function () {
try {
this.currentTime = new Date().toJSON();
@@ -841,7 +848,6 @@ speechSynthesis.getVoices();
notyToPlay.push(feed);
}
});
-
// disable notifications when busy
if (this.currentUserStatus === 'busy') {
return;
@@ -939,144 +945,6 @@ speechSynthesis.getVoices();
}).show();
}
}
- if ((this.config.notificationTTS) && (!this.isGameNoVR) && (this.isGameRunning)) {
- switch (noty.type) {
- case 'OnPlayerJoined':
- this.speak(`${noty.data} has joined`);
- break;
- case 'OnPlayerLeft':
- this.speak(`${noty.data} has left`);
- break;
- case 'OnPlayerJoining':
- this.speak(`${noty.displayName} is joining`);
- break;
- case 'GPS':
- this.speak(`${noty.displayName} is in ${await this.displayLocation(noty.location[0])}`);
- break;
- case 'Online':
- this.speak(`${noty.displayName} has logged in`);
- break;
- case 'Offline':
- this.speak(`${noty.displayName} has logged out`);
- break;
- case 'Status':
- this.speak(`${noty.displayName} status is now ${noty.status[0].status} ${noty.status[0].statusDescription}`);
- break;
- case 'invite':
- this.speak(`${noty.senderUsername} has invited you to ${noty.details.worldName} ${message}`);
- break;
- case 'requestInvite':
- this.speak(`${noty.senderUsername} has requested an invite ${message}`);
- break;
- case 'inviteResponse':
- this.speak(`${noty.senderUsername} has responded to your invite ${message}`);
- break;
- case 'requestInviteResponse':
- this.speak(`${noty.senderUsername} has responded to your invite request ${message}`);
- break;
- case 'friendRequest':
- this.speak(`${noty.senderUsername} has sent you a friend request`);
- break;
- case 'Friend':
- this.speak(`${noty.displayName} is now your friend`);
- break;
- case 'Unfriend':
- this.speak(`${noty.displayName} is no longer your friend`);
- break;
- case 'TrustLevel':
- this.speak(`${noty.displayName} trust level is now ${noty.trustLevel}`);
- break;
- case 'DisplayName':
- this.speak(`${noty.previousDisplayName} changed their name to ${noty.displayName}`);
- break;
- case 'showAvatar':
- this.speak(`${noty.sourceDisplayName} has shown your avatar`);
- break;
- case 'hideAvatar':
- this.speak(`${noty.sourceDisplayName} has hidden your avatar`);
- break;
- case 'block':
- this.speak(`${noty.sourceDisplayName} has blocked you`);
- break;
- case 'mute':
- this.speak(`${noty.sourceDisplayName} has muted you`);
- break;
- case 'unmute':
- this.speak(`${noty.sourceDisplayName} has unmuted you`);
- break;
- default:
- break;
- }
- }
- if ((this.config.desktopToast === 'Always') ||
- ((this.config.desktopToast === 'Game Closed') && (!this.isGameRunning)) ||
- ((this.config.desktopToast === 'Desktop Mode') && (this.isGameNoVR) && (this.isGameRunning))) {
- var imageURL = '';
- if (noty.userId) {
- imageURL = await API.getCachedUser({
- userId: noty.userId
- }).catch((err) => {
- throw err;
- }).then((args) => {
- if ((this.config.displayVRCPlusIconsAsAvatar) && (args.json.userIcon)) {
- return args.json.userIcon;
- }
- return args.json.currentAvatarThumbnailImageUrl;
- });
- }
- switch (noty.type) {
- case 'OnPlayerJoined':
- AppApi.DesktopNotification(noty.data, 'has joined', imageURL);
- break;
- case 'OnPlayerLeft':
- AppApi.DesktopNotification(noty.data, 'has left', imageURL);
- break;
- case 'OnPlayerJoining':
- AppApi.DesktopNotification(noty.displayName, 'is joining', imageURL);
- break;
- case 'GPS':
- AppApi.DesktopNotification(noty.displayName, `is in ${await this.displayLocation(noty.location[0])}`, imageURL);
- break;
- case 'Online':
- AppApi.DesktopNotification(noty.displayName, 'has logged in', imageURL);
- break;
- case 'Offline':
- AppApi.DesktopNotification(noty.displayName, 'has logged out', imageURL);
- break;
- case 'Status':
- AppApi.DesktopNotification(noty.displayName, `status is now ${noty.status[0].status} ${noty.status[0].statusDescription}`, imageURL);
- break;
- case 'invite':
- AppApi.DesktopNotification(noty.senderUsername, `has invited you to ${noty.details.worldName} ${message}`, imageURL);
- break;
- case 'requestInvite':
- AppApi.DesktopNotification(noty.senderUsername, `has requested an invite ${message}`, imageURL);
- break;
- case 'inviteResponse':
- AppApi.DesktopNotification(noty.senderUsername, `has responded to your invite ${message}`, imageURL);
- break;
- case 'requestInviteResponse':
- AppApi.DesktopNotification(noty.senderUsername, `has responded to your invite request ${message}`, imageURL);
- break;
- case 'friendRequest':
- AppApi.DesktopNotification(noty.senderUsername, 'has sent you a friend request', imageURL);
- break;
- case 'Friend':
- AppApi.DesktopNotification(noty.displayName, 'has sent you a friend request', imageURL);
- break;
- case 'Unfriend':
- AppApi.DesktopNotification(noty.displayName, 'is no longer your friend', imageURL);
- break;
- case 'TrustLevel':
- AppApi.DesktopNotification(noty.displayName, `trust level is now ${noty.trustLevel}`, imageURL);
- break;
- case 'DisplayName':
- AppApi.DesktopNotification(noty.previousDisplayName, `changed their name to ${noty.displayName}`, imageURL);
- break;
- default:
- break;
- }
- }
}
};