Add feed filters, vuejs-toggle-switch, OnPlayerJoining, and refactor vr.js

This commit is contained in:
Natsumi
2021-01-11 11:03:09 +13:00
parent 89d644d2d0
commit 15c57959e8
8 changed files with 649 additions and 232 deletions

View File

@@ -8,6 +8,7 @@ import Noty from 'noty';
import Vue from 'vue';
import VueLazyload from 'vue-lazyload';
import { DataTables } from 'vue-data-tables';
import ToggleSwitch from 'vuejs-toggle-switch'
import ElementUI from 'element-ui';
import locale from 'element-ui/lib/locale/lang/en';
@@ -3415,7 +3416,6 @@ speechSynthesis.getVoices();
AppApi.CheckGameRunning().then(([isGameRunning, isGameNoVR]) => {
if (isGameRunning !== this.isGameRunning) {
this.isGameRunning = isGameRunning;
sharedRepository.setBool('is_game_running', isGameRunning);
Discord.SetTimestamps(Date.now(), 0);
}
this.isGameNoVR = isGameNoVR;
@@ -3472,9 +3472,7 @@ speechSynthesis.getVoices();
}
var ctx = data[--i];
// GPS, Online, Offline, Status, Avatar
if ((ctx.type !== 'Avatar') &&
!((ctx.type === 'GPS') && (ctx.location[0] === 'private') && (this.hidePrivateFromFeed === true)) &&
!(((ctx.type === 'Online') || (ctx.type === 'Offline')) && (this.hideLoginsFromFeed === true))) {
if (ctx.type !== 'Avatar') {
arr.push({
...ctx,
isFriend: this.friends.has(ctx.userId),
@@ -3483,6 +3481,7 @@ speechSynthesis.getVoices();
++j;
}
}
// invite, requestInvite, friendRequest
var { data } = this.notificationTable;
for (i = 0; i < data.length; i++) {
var ctx = data[i];
@@ -5705,7 +5704,6 @@ speechSynthesis.getVoices();
$app.data.openVRAlways = configRepository.getBool('openVRAlways');
$app.data.overlaybutton = configRepository.getBool('VRCX_overlaybutton');
$app.data.hidePrivateFromFeed = configRepository.getBool('VRCX_hidePrivateFromFeed');
$app.data.hideLoginsFromFeed = configRepository.getBool('VRCX_hideLoginsFromFeed');
$app.data.hideDevicesFromFeed = configRepository.getBool('VRCX_hideDevicesFromFeed');
$app.data.overlayNotifications = configRepository.getBool('VRCX_overlayNotifications');
$app.data.minimalFeed = configRepository.getBool('VRCX_minimalFeed');
@@ -5717,10 +5715,10 @@ speechSynthesis.getVoices();
configRepository.setBool('openVRAlways', this.openVRAlways);
configRepository.setBool('VRCX_overlaybutton', this.overlaybutton);
configRepository.setBool('VRCX_hidePrivateFromFeed', this.hidePrivateFromFeed);
configRepository.setBool('VRCX_hideLoginsFromFeed', this.hideLoginsFromFeed);
configRepository.setBool('VRCX_hideDevicesFromFeed', this.hideDevicesFromFeed);
configRepository.setBool('VRCX_overlayNotifications', this.overlayNotifications);
configRepository.setBool('VRCX_minimalFeed', this.minimalFeed);
AppApi.RefreshVR();
};
$app.data.TTSvoices = speechSynthesis.getVoices();
var saveNotificationTTS = function () {
@@ -5729,12 +5727,12 @@ speechSynthesis.getVoices();
if (this.notificationTTS) {
this.speak('Notification text-to-speech enabled');
}
AppApi.RefreshVR();
};
$app.watch.openVR = saveOpenVROption;
$app.watch.openVRAlways = saveOpenVROption;
$app.watch.overlaybutton = saveOpenVROption;
$app.watch.hidePrivateFromFeed = saveOpenVROption;
$app.watch.hideLoginsFromFeed = saveOpenVROption;
$app.watch.hideDevicesFromFeed = saveOpenVROption;
$app.watch.overlayNotifications = saveOpenVROption;
$app.watch.minimalFeed = saveOpenVROption;
@@ -5744,6 +5742,7 @@ speechSynthesis.getVoices();
$app.watch.isDarkMode = function () {
configRepository.setBool('isDarkMode', this.isDarkMode);
$appDarkStyle.disabled = this.isDarkMode === false;
AppApi.RefreshVR();
};
$app.data.isStartAtWindowsStartup = configRepository.getBool('VRCX_StartAtWindowsStartup');
$app.data.isStartAsMinimizedState = (VRCXStorage.Get('VRCX_StartAsMinimizedState') === 'true');
@@ -5760,40 +5759,142 @@ speechSynthesis.getVoices();
$app.watch.isStartAsMinimizedState = saveVRCXWindowOption;
$app.watch.isCloseToTray = saveVRCXWindowOption;
$app.watch.isAutoLogin = saveVRCXWindowOption;
if (!configRepository.getString('VRCX_notificationTimeout')) {
$app.data.notificationTimeout = 3000;
configRepository.setString('VRCX_notificationTimeout', $app.data.notificationTimeout);
}
if (!configRepository.getString('VRCX_notificationJoinLeaveFilter')) {
$app.data.notificationJoinLeaveFilter = 'VIP';
configRepository.setString('VRCX_notificationJoinLeaveFilter', $app.data.notificationJoinLeaveFilter);
}
if (!configRepository.getString('VRCX_notificationOnlineOfflineFilter')) {
$app.data.notificationOnlineOfflineFilter = 'VIP';
configRepository.setString('VRCX_notificationOnlineOfflineFilter', $app.data.notificationOnlineOfflineFilter);
}
//setting defaults
if (!configRepository.getString('VRCX_notificationPosition')) {
$app.data.notificationPosition = 'topCenter';
configRepository.setString('VRCX_notificationPosition', $app.data.notificationPosition);
}
if (!configRepository.getString('VRCX_notificationTimeout')) {
$app.data.notificationTimeout = 3000;
configRepository.setString('VRCX_notificationTimeout', $app.data.notificationTimeout);
}
if (!configRepository.getString('VRCX_notificationTTSVoice')) {
$app.data.notificationTTSVoice = '0';
configRepository.setString('VRCX_notificationTTSVoice', $app.data.notificationTTSVoice);
}
$app.data.notificationJoinLeaveFilter = configRepository.getString('VRCX_notificationJoinLeaveFilter');
$app.methods.changeNotificationJoinLeaveFilter = function () {
configRepository.setString('VRCX_notificationJoinLeaveFilter', this.notificationJoinLeaveFilter);
if (!configRepository.getString('sharedFeedFilters')) {
var sharedFeedFilters = {
noty: {},
wrist: {}
};
sharedFeedFilters.noty.Location = 'Off';
sharedFeedFilters.noty.OnPlayerJoined = 'VIP';
sharedFeedFilters.noty.OnPlayerLeft = 'VIP';
sharedFeedFilters.noty.OnPlayerJoining = 'VIP';
sharedFeedFilters.noty.Online = 'VIP';
sharedFeedFilters.noty.Offline = 'VIP';
sharedFeedFilters.noty.GPS = 'Off';
sharedFeedFilters.noty.Status = 'Off';
sharedFeedFilters.noty.invite = 'Friends';
sharedFeedFilters.noty.requestInvite = 'Friends';
sharedFeedFilters.noty.friendRequest = 'On';
sharedFeedFilters.noty.Friend = 'On';
sharedFeedFilters.noty.Unfriend = 'On';
sharedFeedFilters.noty.DisplayName = 'VIP';
sharedFeedFilters.noty.TrustLevel = 'VIP';
sharedFeedFilters.wrist.Location = 'On';
sharedFeedFilters.wrist.OnPlayerJoined = 'Everyone';
sharedFeedFilters.wrist.OnPlayerLeft = 'Everyone';
sharedFeedFilters.wrist.OnPlayerJoining = 'Friends';
sharedFeedFilters.wrist.Online = 'Friends';
sharedFeedFilters.wrist.Offline = 'Friends';
sharedFeedFilters.wrist.GPS = 'Friends';
sharedFeedFilters.wrist.Status = 'Friends';
sharedFeedFilters.wrist.invite = 'Friends';
sharedFeedFilters.wrist.requestInvite = 'Friends';
sharedFeedFilters.wrist.friendRequest = 'On';
sharedFeedFilters.wrist.Friend = 'On';
sharedFeedFilters.wrist.Unfriend = 'On';
sharedFeedFilters.wrist.DisplayName = 'Friends';
sharedFeedFilters.wrist.TrustLevel = 'Friends';
configRepository.setString('sharedFeedFilters', JSON.stringify(sharedFeedFilters));
}
$app.data.sharedFeedFilters = JSON.parse(configRepository.getString('sharedFeedFilters'));
$app.data.toggleSwitchOptionsEveryone = {
layout: {
backgroundColor: "white",
selectedBackgroundColor: "#409eff",
selectedColor: "white",
color: "#409eff",
borderColor: "#409eff",
fontWeight: "bold",
fontFamily: '"Noto Sans JP", "Noto Sans KR", "Meiryo UI", "Malgun Gothic", "Segoe UI", "sans-serif"'
},
size: {
height: 1.5,
width: 15,
padding: 0.1,
fontSize: 0.75
},
items: {
labels: [{ name: "Off" }, { name: "VIP" }, { name: "Friends" }, { name: "Everyone" }]
}
};
$app.data.notificationOnlineOfflineFilter = configRepository.getString('VRCX_notificationOnlineOfflineFilter');
$app.methods.changeNotificationOnlineOfflineFilter = function () {
configRepository.setString('VRCX_notificationOnlineOfflineFilter', this.notificationOnlineOfflineFilter);
$app.data.toggleSwitchOptionsFriends = {
layout: {
backgroundColor: "white",
selectedBackgroundColor: "#409eff",
selectedColor: "white",
color: "#409eff",
borderColor: "#409eff",
fontWeight: "bold",
fontFamily: '"Noto Sans JP", "Noto Sans KR", "Meiryo UI", "Malgun Gothic", "Segoe UI", "sans-serif"'
},
size: {
height: 1.5,
width: 11.25,
padding: 0.1,
fontSize: 0.75
},
items: {
labels: [{ name: "Off" }, { name: "VIP" }, { name: "Friends" }]
}
};
$app.data.toggleSwitchOptionsOn = {
layout: {
backgroundColor: "white",
selectedBackgroundColor: "#409eff",
selectedColor: "white",
color: "#409eff",
borderColor: "#409eff",
fontWeight: "bold",
fontFamily: '"Noto Sans JP", "Noto Sans KR", "Meiryo UI", "Malgun Gothic", "Segoe UI", "sans-serif"'
},
size: {
height: 1.5,
width: 7.5,
padding: 0.1,
fontSize: 0.75
},
items: {
labels: [{ name: "Off" }, { name: "On" }]
}
};
$app.methods.saveSharedFeedFilters = function () {
this.notyFeedFiltersDialog.visible = false;
this.wristFeedFiltersDialog.visible = false;
configRepository.setString('sharedFeedFilters', JSON.stringify(this.sharedFeedFilters));
AppApi.RefreshVR();
}
$app.methods.cancelSharedFeedFilters = function () {
this.notyFeedFiltersDialog.visible = false;
this.wristFeedFiltersDialog.visible = false;
this.sharedFeedFilters = JSON.parse(configRepository.getString('sharedFeedFilters'));
}
$app.data.notificationPosition = configRepository.getString('VRCX_notificationPosition');
$app.methods.changeNotificationPosition = function () {
configRepository.setString('VRCX_notificationPosition', this.notificationPosition);
AppApi.RefreshVR();
};
sharedRepository.setBool('is_game_running', false);
var isGameRunningStateChange = function () {
sharedRepository.setBool('is_game_running', this.isGameRunning);
$app.lastLocation = '';
if (this.isGameRunning) {
API.currentUser.$online_for = Date.now();
@@ -5872,6 +5973,7 @@ speechSynthesis.getVoices();
var voiceName = voices[index].name;
speechSynthesis.cancel();
this.speak(voiceName);
AppApi.RefreshVR();
};
$app.methods.speak = function (text) {
@@ -7579,6 +7681,28 @@ speechSynthesis.getVoices();
this.notificationPositionDialog.visible = true;
};
// App: Noty feed filters
$app.data.notyFeedFiltersDialog = {
visible: false
};
$app.methods.showNotyFeedFiltersDialog = function () {
this.$nextTick(() => adjustDialogZ(this.$refs.notyFeedFiltersDialog.$el));
this.notyFeedFiltersDialog.visible = true;
};
// App: Wrist feed filters
$app.data.wristFeedFiltersDialog = {
visible: false
};
$app.methods.showWristFeedFiltersDialog = function () {
this.$nextTick(() => adjustDialogZ(this.$refs.wristFeedFiltersDialog.$el));
this.wristFeedFiltersDialog.visible = true;
};
// App: Launch Dialog
$app.data.launchDialog = {

View File

@@ -567,3 +567,19 @@ i.x-user-status.busy {
display: inline-block;
min-width: 175px;
}
.toggle-switch {
display: inline-block;
}
.toggle-list {
font-size: 12px;
}
.toggle-list .toggle-name {
display: inline-block;
min-width: 100px;
padding: 2px 5px 2px 0;
vertical-align: top;
text-align: right;
}

View File

@@ -515,18 +515,18 @@ html
span.name VRCPlus Profile Icons
el-switch(v-model="displayVRCPlusIconsAsAvatar")
div.options-container
span.header Friends Sort Option
span.header Side Pannel Sorting Options
div.options-container-item
span.name VIP
el-switch(v-model="orderFriendsGroup0" inactive-text="by name" active-text="by state")
div.options-container-item
span.name ONLINE
span.name Online
el-switch(v-model="orderFriendsGroup1" inactive-text="by name" active-text="by state")
div.options-container-item
span.name ACTIVE
span.name Active
el-switch(v-model="orderFriendsGroup2" inactive-text="by name" active-text="by state")
div.options-container-item
span.name OFFLINE
span.name Offline
el-switch(v-model="orderFriendsGroup3" inactive-text="by name" active-text="by state")
div.options-container
span.header Discord Presence
@@ -560,9 +560,6 @@ html
div.options-container-item
span.name Hide VR Devices
el-switch(v-model="hideDevicesFromFeed" :disabled="!openVR")
div.options-container-item
span.name Hide Online/Offline
el-switch(v-model="hideLoginsFromFeed" :disabled="!openVR")
div.options-container-item
span.name Hide Private Worlds
el-switch(v-model="hidePrivateFromFeed" :disabled="!openVR")
@@ -581,24 +578,12 @@ html
el-button(v-text="TTSvoices[notificationTTSVoice].name" size="mini" :disabled="!openVR || !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-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="!overlayNotifications || !openVR") Notification Filters
div.options-container-item
el-button(size="small" icon="el-icon-time" @click="promptNotificationTimeout()" :disabled="!overlayNotifications || !openVR") Notification Timeout
el-button(size="small" icon="el-icon-rank" @click="showNotificationPositionDialog()" :disabled="!overlayNotifications || !openVR") Notification Position
div.options-container-item
span Join/Leave Notifications
br
el-radio-group(v-model="notificationJoinLeaveFilter" size="mini" @change="changeNotificationJoinLeaveFilter" :disabled="!overlayNotifications && !notificationTTS || !openVR")
el-radio(label="VIP" v-model="notificationJoinLeaveFilter") VIP
el-radio(label="Friends" v-model="notificationJoinLeaveFilter") Friends
el-radio(label="Everyone" v-model="notificationJoinLeaveFilter") Everyone
el-radio(label="Off" v-model="notificationJoinLeaveFilter") Off
div.options-container-item
span Online/Offline Notifications
br
el-radio-group(v-model="notificationOnlineOfflineFilter" size="mini" @change="changeNotificationOnlineOfflineFilter" :disabled="!overlayNotifications && !notificationTTS || !openVR")
el-radio(label="VIP" v-model="notificationOnlineOfflineFilter") VIP
el-radio(label="Friends" v-model="notificationOnlineOfflineFilter") Friends
el-radio(label="Off" v-model="notificationOnlineOfflineFilter") Off
div.options-container
span.header Application
div.options-container-item
@@ -1206,6 +1191,107 @@ html
div(style="display:flex")
el-button(type="primary" size="small" style="margin-left:auto" @click="notificationPositionDialog.visible = false") OK
//- dialog: Noty feed filters
el-dialog.x-dialog(ref="notyFeedFiltersDialog" :visible.sync="notyFeedFiltersDialog.visible" title="Notification Filters" width="400px")
div.toggle-list
div
span.toggle-name OnPlayerJoining
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchNotyGroupOnPlayerJoining" v-model="sharedFeedFilters.noty.OnPlayerJoining" class="toggle-switch")
div
span.toggle-name OnPlayerJoined
toggle-switch(:options="toggleSwitchOptionsEveryone" group="switchNotyGroupOnPlayerJoined" v-model="sharedFeedFilters.noty.OnPlayerJoined" class="toggle-switch")
div
span.toggle-name OnPlayerLeft
toggle-switch(:options="toggleSwitchOptionsEveryone" group="switchNotyGroupOnPlayerLeft" v-model="sharedFeedFilters.noty.OnPlayerLeft" class="toggle-switch")
div
span.toggle-name Online
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchNotyGroupOnline" v-model="sharedFeedFilters.noty.Online" class="toggle-switch")
div
span.toggle-name Offline
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchNotyGroupOffline" v-model="sharedFeedFilters.noty.Offline" class="toggle-switch")
div
span.toggle-name GPS
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchNotyGroupGPS" v-model="sharedFeedFilters.noty.GPS" class="toggle-switch")
div
span.toggle-name Status
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchNotyGroupStatus" v-model="sharedFeedFilters.noty.Status" class="toggle-switch")
div
span.toggle-name Invite
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchNotyGroupinvite" v-model="sharedFeedFilters.noty.invite" class="toggle-switch")
div
span.toggle-name Request Invite
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchNotyGrouprequestInvite" v-model="sharedFeedFilters.noty.requestInvite" class="toggle-switch")
div
span.toggle-name Friend Request
toggle-switch(:options="toggleSwitchOptionsOn" group="switchNotyGrouprequestfriendRequest" v-model="sharedFeedFilters.noty.friendRequest" class="toggle-switch")
div
span.toggle-name New Friend
toggle-switch(:options="toggleSwitchOptionsOn" group="switchNotyGrouprequestFriend" v-model="sharedFeedFilters.noty.Friend" class="toggle-switch")
div
span.toggle-name Unfriend
toggle-switch(:options="toggleSwitchOptionsOn" group="switchNotyGrouprequestUnfriend" v-model="sharedFeedFilters.noty.Unfriend" class="toggle-switch")
div
span.toggle-name DisplayName
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchNotyGrouprequestDisplayName" v-model="sharedFeedFilters.noty.DisplayName" class="toggle-switch")
div
span.toggle-name TrustLevel
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchNotyGrouprequestTrustLevel" v-model="sharedFeedFilters.noty.TrustLevel" class="toggle-switch")
template(#footer)
el-button(type="small" @click="cancelSharedFeedFilters") Cancel
el-button(type="primary" size="small" style="margin-left:10px" @click="saveSharedFeedFilters") Save
//- dialog: wrist feed filters
el-dialog.x-dialog(ref="wristFeedFiltersDialog" :visible.sync="wristFeedFiltersDialog.visible" title="Wrist Feed Filters" width="400px")
div.toggle-list
div
span.toggle-name Self Location
toggle-switch(:options="toggleSwitchOptionsOn" group="switchWristGroupLocation" v-model="sharedFeedFilters.wrist.Location" class="toggle-switch")
div
span.toggle-name OnPlayerJoining
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchWristGroupOnPlayerJoining" v-model="sharedFeedFilters.wrist.OnPlayerJoining" class="toggle-switch")
div
span.toggle-name OnPlayerJoined
toggle-switch(:options="toggleSwitchOptionsEveryone" group="switchWristGroupOnPlayerJoined" v-model="sharedFeedFilters.wrist.OnPlayerJoined" class="toggle-switch")
div
span.toggle-name OnPlayerLeft
toggle-switch(:options="toggleSwitchOptionsEveryone" group="switchWristGroupOnPlayerLeft" v-model="sharedFeedFilters.wrist.OnPlayerLeft" class="toggle-switch")
div
span.toggle-name Online
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchWristGroupOnline" v-model="sharedFeedFilters.wrist.Online" class="toggle-switch")
div
span.toggle-name Offline
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchWristGroupOffline" v-model="sharedFeedFilters.wrist.Offline" class="toggle-switch")
div
span.toggle-name GPS
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchWristGroupGPS" v-model="sharedFeedFilters.wrist.GPS" class="toggle-switch")
div
span.toggle-name Status
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchWristGroupStatus" v-model="sharedFeedFilters.wrist.Status" class="toggle-switch")
div
span.toggle-name Invite
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchWristGroupinvite" v-model="sharedFeedFilters.wrist.invite" class="toggle-switch")
div
span.toggle-name Request Invite
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchWristGrouprequestInvite" v-model="sharedFeedFilters.wrist.requestInvite" class="toggle-switch")
div
span.toggle-name Friend Request
toggle-switch(:options="toggleSwitchOptionsOn" group="switchWristGrouprequestfriendRequest" v-model="sharedFeedFilters.wrist.friendRequest" class="toggle-switch")
div
span.toggle-name New Friend
toggle-switch(:options="toggleSwitchOptionsOn" group="switchWristGrouprequestFriend" v-model="sharedFeedFilters.wrist.Friend" class="toggle-switch")
div
span.toggle-name Unfriend
toggle-switch(:options="toggleSwitchOptionsOn" group="switchWristGrouprequestUnfriend" v-model="sharedFeedFilters.wrist.Unfriend" class="toggle-switch")
div
span.toggle-name DisplayName
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchWristGrouprequestDisplayName" v-model="sharedFeedFilters.wrist.DisplayName" class="toggle-switch")
div
span.toggle-name TrustLevel
toggle-switch(:options="toggleSwitchOptionsFriends" group="switchWristGrouprequestTrustLevel" v-model="sharedFeedFilters.wrist.TrustLevel" class="toggle-switch")
template(#footer)
el-button(type="small" @click="cancelSharedFeedFilters") Cancel
el-button(type="primary" size="small" @click="saveSharedFeedFilters") Save
//- dialog: open source software notice
el-dialog.x-dialog(:visible.sync="ossDialog" title="Open Source Software Notice" width="650px")
div(style="height:350px;overflow:hidden scroll;word-break:break-all")
@@ -1480,6 +1566,30 @@ html
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
div(style="margin-top:15px")
p(style="font-weight:bold") vuejs-toggle-switch
pre(style="font-size:12px;white-space:pre-line").
MIT License
Copyright (c) 2018 Lars-Martin Hejll
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

View File

@@ -573,9 +573,21 @@ speechSynthesis.getVoices();
currentTime: new Date().toJSON(),
currentUserStatus: null,
cpuUsage: 0,
feeds: [],
isGameRunning: false,
lastLocation: '',
lastFeedEntry: [],
feedFilters: [],
wristFeed: [],
notyMap: [],
devices: [],
overlayNotificationsToggle: false,
notificationTTSToggle: false,
notificationTTSVoice: '0',
hideDevicesToggle: false,
isMinimalFeed: false,
notificationPosition: 'topCenter',
notificationTimeout: '3000',
notificationTheme: 'relax'
},
computed: {},
methods: {},
@@ -600,6 +612,8 @@ speechSynthesis.getVoices();
// FIXME: 어케 복구하냐 이건
throw err;
}).then((args) => {
this.initConfigVars();
this.initNotyMap();
this.updateLoop();
this.updateCpuUsageLoop();
this.$nextTick(function () {
@@ -612,23 +626,70 @@ speechSynthesis.getVoices();
}
};
$app.methods.initConfigVars = function () {
this.notificationTTSToggle = configRepository.getBool('VRCX_notificationTTS');
this.notificationTTSVoice = configRepository.getString('VRCX_notificationTTSVoice');
this.overlayNotificationsToggle = configRepository.getBool('VRCX_overlayNotifications');
this.hidePrivateFromFeed = configRepository.getBool('VRCX_hidePrivateFromFeed');
this.hideDevicesToggle = configRepository.getBool('VRCX_hideDevicesFromFeed');
this.isMinimalFeed = configRepository.getBool('VRCX_minimalFeed');
this.feedFilters = JSON.parse(configRepository.getString('sharedFeedFilters'));
this.notificationPosition = configRepository.getString('VRCX_notificationPosition');
this.notificationTimeout = configRepository.getString('VRCX_notificationTimeout');
if (configRepository.getBool('isDarkMode')) {
this.notificationTheme = 'sunset';
} else {
this.notificationTheme = 'relax';
}
};
$app.methods.initNotyMap = function () {
var feeds = sharedRepository.getArray('feeds');
if (feeds === null) {
return;
}
var filter = this.feedFilters.noty;
var filtered = [];
feeds.forEach((feed) => {
if (filter[feed.type]) {
if ((filter[feed.type] !== 'Off') &&
((filter[feed.type] === 'Everyone') || (filter[feed.type] === 'On') ||
((filter[feed.type] === 'Friends') && (feed.isFriend)) ||
((filter[feed.type] === 'VIP') && (feed.isFavorite)))) {
var displayName = '';
if (feed.data) {
displayName = feed.data;
} else if (feed.displayName) {
displayName = feed.displayName;
} else if (feed.senderUsername) {
displayName = feed.senderUsername;
}
if ((displayName) && (!this.notyMap[displayName]) ||
(this.notyMap[displayName] < feed.created_at)) {
this.notyMap[displayName] = feed.created_at;
}
}
}
});
};
$app.methods.updateLoop = async function () {
try {
this.currentTime = new Date().toJSON();
this.currentUserStatus = sharedRepository.getString('current_user_status');
this.isGameRunning = sharedRepository.getBool('is_game_running');
if (configRepository.getBool('VRCX_hideDevicesFromFeed') === false) {
this.lastLocation = sharedRepository.getString('last_location');
if (!this.hideDevicesToggle) {
AppApi.GetVRDevices().then((devices) => {
devices.forEach((device) => {
device[2] = parseInt(device[2], 10);
});
this.devices = devices;
});
}
else {
} else {
this.devices = '';
}
await this.updateSharedFeed();
await this.updateSharedFeeds();
} catch (err) {
console.error(err);
}
@@ -645,185 +706,228 @@ speechSynthesis.getVoices();
setTimeout(() => this.updateCpuUsageLoop(), 1000);
};
$app.methods.updateSharedFeed = async function () {
// TODO: block mute hideAvatar unfriend
this.isMinimalFeed = configRepository.getBool('VRCX_minimalFeed');
var notificationPosition = configRepository.getString('VRCX_notificationPosition');
var notificationTimeout = configRepository.getString('VRCX_notificationTimeout');
var notificationJoinLeaveFilter = configRepository.getString('VRCX_notificationJoinLeaveFilter');
var notificationOnlineOfflineFilter = configRepository.getString('VRCX_notificationOnlineOfflineFilter');
var theme = 'relax';
if (configRepository.getBool('isDarkMode') === true) {
theme = 'sunset';
}
$app.methods.updateSharedFeeds = async function () {
var feeds = sharedRepository.getArray('feeds');
if (feeds === null) {
return;
}
var _feeds = this.feeds;
this.feeds = feeds;
if ((this.appType === '2') && this.isGameRunning) {
var map = {};
_feeds.forEach((feed) => {
if (feed.type === 'OnPlayerJoined' ||
feed.type === 'OnPlayerLeft') {
if (!map[feed.data] ||
map[feed.data] < feed.created_at) {
map[feed.data] = feed.created_at;
}
} else if (feed.type === 'Online' ||
feed.type === 'Offline') {
if (!map[feed.displayName] ||
map[feed.displayName] < feed.created_at) {
map[feed.displayName] = feed.created_at;
}
} else if (feed.type === 'invite' ||
feed.type === 'requestInvite' ||
feed.type === 'friendRequest') {
if (!map[feed.senderUsername] ||
map[feed.senderUsername] < feed.created_at) {
map[feed.senderUsername] = feed.created_at;
}
} else if (feed.type === 'Friend' ||
feed.type === 'Unfriend') {
if (!map[feed.displayName] ||
map[feed.displayName] < feed.created_at) {
map[feed.displayName] = feed.created_at;
}
}
});
// disable notification on busy
if (this.currentUserStatus === 'busy') {
return;
}
var notys = [];
this.feeds.forEach((feed) => {
if (((notificationOnlineOfflineFilter === "Friends") && (feed.isFriend)) ||
((notificationOnlineOfflineFilter === "VIP") && (feed.isFavorite))) {
if (feed.type === 'Online' ||
feed.type === 'Offline') {
if (!map[feed.displayName] ||
map[feed.displayName] < feed.created_at) {
map[feed.displayName] = feed.created_at;
notys.push(feed);
}
}
}
if ((notificationJoinLeaveFilter === "Everyone") ||
((notificationJoinLeaveFilter === "Friends") && (feed.isFriend)) ||
((notificationJoinLeaveFilter === "VIP") && (feed.isFavorite))) {
if (feed.type === 'OnPlayerJoined' ||
feed.type === 'OnPlayerLeft') {
if (!map[feed.data] ||
map[feed.data] < feed.created_at) {
map[feed.data] = feed.created_at;
notys.push(feed);
}
}
}
if (feed.type === 'invite' ||
feed.type === 'requestInvite' ||
feed.type === 'friendRequest') {
if (!map[feed.senderUsername] ||
map[feed.senderUsername] < feed.created_at) {
map[feed.senderUsername] = feed.created_at;
notys.push(feed);
}
}
if (feed.type === 'Friend' ||
feed.type === 'Unfriend') {
if (!map[feed.displayName] ||
map[feed.displayName] < feed.created_at) {
map[feed.displayName] = feed.created_at;
notys.push(feed);
}
}
});
var bias = new Date(Date.now() - 60000).toJSON();
var theme = 'relax';
if (configRepository.getBool('isDarkMode') === true) {
theme = 'sunset';
}
notys.forEach((noty) => {
if (noty.created_at > bias) {
if (configRepository.getBool('VRCX_overlayNotifications')) {
var text = '';
switch (noty.type) {
case 'OnPlayerJoined':
text = `<strong>${noty.data}</strong> has joined`;
break;
case 'OnPlayerLeft':
text = `<strong>${noty.data}</strong> has left`;
break;
case 'Online':
text = `<strong>${noty.displayName}</strong> has logged in`;
break;
case 'Offline':
text = `<strong>${noty.displayName}</strong> has logged out`;
break;
case 'invite':
text = `<strong>${noty.senderUsername}</strong> has invited you to ${noty.details.worldName}`;
break;
case 'requestInvite':
text = `<strong>${noty.senderUsername}</strong> has requested an invite`;
break;
case 'friendRequest':
text = `<strong>${noty.senderUsername}</strong> has sent you a friend request`;
break;
case 'Friend':
text = `<strong>${noty.displayName}</strong> is now your friend`;
break;
case 'Unfriend':
text = `<strong>${noty.displayName}</strong> has unfriended you`;
break;
}
if (text) {
new Noty({
type: 'alert',
theme: theme,
timeout: notificationTimeout,
layout: notificationPosition,
text: text
}).show();
}
}
if (configRepository.getBool('VRCX_notificationTTS')) {
switch (noty.type) {
case 'OnPlayerJoined':
this.speak(`${noty.data} has joined`);
break;
case 'OnPlayerLeft':
this.speak(`${noty.data} has left`);
break;
case 'Online':
this.speak(`${noty.displayName} has logged in`);
break;
case 'Offline':
this.speak(`${noty.displayName} has logged out`);
break;
case 'invite':
this.speak(`${noty.senderUsername} has invited you to ${noty.details.worldName}`);
break;
case 'requestInvite':
this.speak(`${noty.senderUsername} has requested an invite`);
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} has unfriended you`);
break;
}
}
}
});
if ((this.lastFeedEntry !== undefined) &&
(feeds[0].created_at === this.lastFeedEntry.created_at)) {
return;
}
this.lastFeedEntry = feeds[0];
// OnPlayerJoining
var bias = new Date(Date.now() - 120000).toJSON();
for (i = 0; i < feeds.length; i++) {
var ctx = feeds[i];
if ((ctx.created_at < bias) || (ctx.type === 'Location')) {
break;
}
if ((ctx.type === 'GPS') && (ctx.location[0] === this.lastLocation)) {
var joining = true;
for (var k = 0; k < feeds.length; k++) {
var feedItem = feeds[k];
if ((feedItem.type === 'OnPlayerJoined') && (feedItem.data === ctx.displayName)) {
joining = false;
break;
}
if ((feedItem.created_at < bias) || (feedItem.type === 'Location') ||
((feedItem.type === 'GPS') && (feedItem.location !== ctx.location[0]) &&
(feedItem.displayName === ctx.displayName))) {
break;
}
}
if (joining) {
var onPlayerJoining = {};
onPlayerJoining.created_at = ctx.created_at;
onPlayerJoining.data = ctx.displayName;
onPlayerJoining.isFavorite = ctx.isFavorite;
onPlayerJoining.isFriend = ctx.isFriend;
onPlayerJoining.type = 'OnPlayerJoining';
feeds.splice(i, 0, onPlayerJoining);
i++;
}
}
}
if (this.hidePrivateFromFeed) {
for (var i = 0; i < feeds.length; i++) {
var feed = feeds[i];
if ((feed.type === 'GPS') && (feed.location[0] === 'private')) {
feeds.splice(i, 1);
i--;
}
}
}
if (this.appType === '1') {
this.updateSharedFeedWrist(feeds);
}
if (this.appType === '2') {
this.updateSharedFeedNoty(feeds);
}
};
$app.methods.updateSharedFeedWrist = async function (feeds) {
var filter = this.feedFilters.wrist;
var filtered = [];
feeds.forEach((feed) => {
if (filter[feed.type]) {
if ((filter[feed.type] !== 'Off') &&
((filter[feed.type] === 'Everyone') || (filter[feed.type] === 'On') ||
((filter[feed.type] === 'Friends') && (feed.isFriend)) ||
((filter[feed.type] === 'VIP') && (feed.isFavorite)))) {
filtered.push(feed);
}
} else {
console.error(`missing feed filter for ${feed.type}`);
filtered.push(feed);
}
});
this.wristFeed = filtered;
};
$app.methods.updateSharedFeedNoty = async function (feeds) {
var filter = this.feedFilters.noty;
var filtered = [];
feeds.forEach((feed) => {
if (filter[feed.type]) {
if ((filter[feed.type] !== 'Off') &&
((filter[feed.type] === 'Everyone') || (filter[feed.type] === 'On') ||
((filter[feed.type] === 'Friends') && (feed.isFriend)) ||
((filter[feed.type] === 'VIP') && (feed.isFavorite)))) {
filtered.push(feed);
}
}
});
var notyToPlay = [];
filtered.forEach((feed) => {
var displayName = '';
if (feed.displayName) {
displayName = feed.displayName;
} else if (feed.senderUsername) {
displayName = feed.senderUsername;
} 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 or game isn't running
if ((this.currentUserStatus === 'busy') || (!this.isGameRunning)) {
return;
}
notyToPlay.forEach(async (noty) => {
if (this.overlayNotificationsToggle) {
var text = '';
switch (noty.type) {
case 'OnPlayerJoined':
text = `<strong>${noty.data}</strong> has joined`;
break;
case 'OnPlayerLeft':
text = `<strong>${noty.data}</strong> has left`;
break;
case 'OnPlayerJoining':
text = `<strong>${noty.data}</strong> is joining`;
break;
case 'GPS':
text = '<strong>' + noty.displayName + '</strong> is in ' + await this.displayLocation(noty.location[0]);
break;
case 'Online':
text = `<strong>${noty.displayName}</strong> has logged in`;
break;
case 'Offline':
text = `<strong>${noty.displayName}</strong> has logged out`;
break;
case 'Status':
text = `<strong>${noty.displayName}</strong> status is now <i>${noty.status[0].status}</i> ${noty.status[0].statusDescription}`;
break;
case 'invite':
text = `<strong>${noty.senderUsername}</strong> has invited you to ${noty.details.worldName}`;
break;
case 'requestInvite':
text = `<strong>${noty.senderUsername}</strong> has requested an invite`;
break;
case 'friendRequest':
text = `<strong>${noty.senderUsername}</strong> has sent you a friend request`;
break;
case 'Friend':
text = `<strong>${noty.displayName}</strong> is now your friend`;
break;
case 'Unfriend':
text = `<strong>${noty.displayName}</strong> has unfriended you`;
break;
case 'TrustLevel':
text = `<strong>${noty.displayName}</strong> trust level is now ${noty.trustLevel}`;
break;
case 'DisplayName':
text = `<strong>${noty.previousDisplayName}</strong> changed their name to ${noty.displayName}`;
break;
}
if (text) {
new Noty({
type: 'alert',
theme: this.notificationTheme,
timeout: this.notificationTimeout,
layout: this.notificationPosition,
text: text
}).show();
}
}
if (this.notificationTTSToggle) {
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.data} 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}`);
break;
case 'requestInvite':
this.speak(`${noty.senderUsername} has requested an invite`);
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} has unfriended you`);
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;
}
}
});
};
$app.methods.userStatusClass = function (user) {
@@ -842,10 +946,40 @@ speechSynthesis.getVoices();
return style;
};
$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 (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.speak = function (text) {
var tts = new SpeechSynthesisUtterance();
var voices = speechSynthesis.getVoices();
var voiceIndex = configRepository.getString('VRCX_notificationTTSVoice');
var voiceIndex = this.notificationTTSVoice;
tts.voice = voices[voiceIndex];
tts.text = text;
speechSynthesis.speak(tts);

View File

@@ -12,11 +12,11 @@ html
link(rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+JP|Noto+Sans+KR&display=swap")
link(rel="stylesheet" href="vr.css")
body
.x-app#x-app(style="display:none" :class="{ 'x-app-type': appType === '1' }")
.x-app#x-app(v-if="appType === '1'" class="x-app-type")
.x-container(style="flex:1")
.x-friend-list(ref="list" style="color:#aaa")
template(v-if="isMinimalFeed === true")
template(v-for="feed in feeds")
template(v-if="isMinimalFeed")
template(v-for="feed in wristFeed")
.x-friend-item(v-if="feed.type === 'GPS'" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
@@ -47,6 +47,12 @@ html
span.extra
span.time {{ feed.created_at | formatDate('HH:MI') }}
| ◀️ #[span.name(v-text="feed.data")]
div(v-else-if="feed.type === 'OnPlayerJoining'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate('HH:MI') }}
span.spin ▶️
span.name(v-text="feed.data" style="margin-left:20px")
div(v-else-if="feed.type === 'Location'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
@@ -88,7 +94,7 @@ html
span.time {{ feed.created_at | formatDate('HH:MI') }}
| 🤝 #[span.name(v-text="feed.displayName")] {{ feed.previousTrustLevel }} #[i.el-icon-right] {{ feed.trustLevel }}
template(v-else)
template(v-for="feed in feeds")
template(v-for="feed in wristFeed")
.x-friend-item(v-if="feed.type === 'GPS'" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
@@ -119,6 +125,11 @@ html
span.extra
span.time {{ feed.created_at | formatDate('HH:MI') }}
| #[span.name(v-text="feed.data")] has left
div(v-else-if="feed.type === 'OnPlayerJoining'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate('HH:MI') }}
| #[span.name(v-text="feed.data")] is joining
div(v-else-if="feed.type === 'Location'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra

View File

@@ -274,3 +274,19 @@ i.x-user-status.joinme {
i.x-user-status.busy {
background: #f56c6c;
}
.spin {
animation: rotation 2.5s infinite linear;
position: absolute;
width: 14px;
height: 28px;
}
@keyframes rotation {
from {
transform: rotate(0deg);
}
to {
transform: rotate(359deg);
}
}