refactor: app.js (#1291)

* refactor: frontend

* Fix avatar gallery sort

* Update .NET dependencies

* Update npm dependencies

electron v37.1.0

* bulkRefreshFriends

* fix dark theme

* Remove crowdin

* Fix config.json dialog not updating

* VRCX log file fixes & add Cef log

* Remove SharedVariable, fix startup

* Revert init theme change

* Logging date not working? Fix WinformThemer designer error

* Add Cef request hander, no more escaping main page

* clean

* fix

* fix

* clean

* uh

* Apply thememode at startup, fixes random user colours

* Split database into files

* Instance info remove empty lines

* Open external VRC links with VRCX

* Electron fixes

* fix userdialog style

* ohhhh

* fix store

* fix store

* fix: load all group members after kicking a user

* fix: world dialog favorite button style

* fix: Clear VRCX Cache Timer input value

* clean

* Fix VR overlay

* Fix VR overlay 2

* Fix Discord discord rich presence for RPC worlds

* Clean up age verified user tags

* Fix playerList being occupied after program reload

* no `this`

* Fix login stuck loading

* writable: false

* Hide dialogs on logout

* add flush sync option

* rm LOGIN event

* rm LOGOUT event

* remove duplicate event listeners

* remove duplicate event listeners

* clean

* remove duplicate event listeners

* clean

* fix theme style

* fix t

* clearable

* clean

* fix ipcEvent

* Small changes

* Popcorn Palace support

* Remove checkActiveFriends

* Clean up

* Fix dragEnterCef

* Block API requests when not logged in

* Clear state on login & logout

* Fix worldDialog instances not updating

* use <script setup>

* Fix avatar change event, CheckGameRunning at startup

* Fix image dragging

* fix

* Remove PWI

* fix updateLoop

* add webpack-dev-server to dev environment

* rm unnecessary chunks

* use <script setup>

* webpack-dev-server changes

* use <script setup>

* use <script setup>

* Fix UGC text size

* Split login event

* t

* use <script setup>

* fix

* Update .gitignore and enable checkJs in jsconfig

* fix i18n t

* use <script setup>

* use <script setup>

* clean

* global types

* fix

* use checkJs for debugging

* Add watchState for login watchers

* fix .vue template

* type fixes

* rm Vue.filter

* Cef v138.0.170, VC++ 2022

* Settings fixes

* Remove 'USER:CURRENT'

* clean up 2FA callbacks

* remove userApply

* rm i18n import

* notification handling to use notification store methods

* refactor favorite handling to use favorite store methods and clean up event emissions

* refactor moderation handling to use dedicated functions for player moderation events

* refactor friend handling to use dedicated functions for friend events

* Fix program startup, move lang init

* Fix friend state

* Fix status change error

* Fix user notes diff

* fix

* rm group event

* rm auth event

* rm avatar event

* clean

* clean

* getUser

* getFriends

* getFavoriteWorlds, getFavoriteAvatars

* AvatarGalleryUpload btn style & package.json update

* Fix friend requests

* Apply user

* Apply world

* Fix note diff

* Fix VR overlay

* Fixes

* Update build scripts

* Apply avatar

* Apply instance

* Apply group

* update hidden VRC+ badge

* Fix sameInstance "private"

* fix 502/504 API errors

* fix 502/504 API errors

* clean

* Fix friend in same instance on orange showing twice in friends list

* Add back in broken friend state repair methods

* add types

---------

Co-authored-by: Natsumi <cmcooper123@hotmail.com>
This commit is contained in:
pa
2025-07-14 12:00:08 +09:00
committed by GitHub
parent 952fd77ed5
commit f4f78bb5ec
323 changed files with 47745 additions and 43326 deletions

View File

@@ -1,5 +1,5 @@
<template>
<div v-show="menuActiveIndex === 'notification'" v-loading="API.isNotificationsLoading" class="x-container">
<div v-show="menuActiveIndex === 'notification'" v-loading="isNotificationsLoading" class="x-container">
<data-tables v-bind="notificationTable" ref="notificationTableRef" class="notification-table">
<template #tool>
<div style="margin: 0 0 10px; display: flex; align-items: center">
@@ -45,11 +45,11 @@
:disabled="hideTooltips">
<el-button
type="default"
:loading="API.isNotificationsLoading"
:loading="isNotificationsLoading"
icon="el-icon-refresh"
circle
style="flex: none"
@click="API.refreshNotifications()" />
@click="refreshNotifications()" />
</el-tooltip>
</div>
</template>
@@ -58,9 +58,9 @@
<template #default="scope">
<el-tooltip placement="right">
<template #content>
<span>{{ scope.row.created_at | formatDate('long') }}</span>
<span>{{ formatDateFilter(scope.row.created_at, 'long') }}</span>
</template>
<span>{{ scope.row.created_at | formatDate('short') }}</span>
<span>{{ formatDateFilter(scope.row.created_at, 'short') }}</span>
</el-tooltip>
</template>
</el-table-column>
@@ -76,7 +76,7 @@
v-else-if="scope.row.type === 'group.queueReady' || scope.row.type === 'instance.closed'"
placement="top">
<template #content>
<location
<Location
v-if="scope.row.location"
:location="scope.row.location"
:hint="scope.row.worldName"
@@ -169,7 +169,7 @@
<el-table-column :label="t('table.notification.message')" prop="message">
<template #default="scope">
<span v-if="scope.row.type === 'invite'" style="display: flex">
<location
<Location
v-if="scope.row.details"
:location="scope.row.details.worldId"
:hint="scope.row.details.worldName"
@@ -213,7 +213,7 @@
<el-table-column :label="t('table.notification.action')" width="100" align="right">
<template #default="scope">
<template v-if="scope.row.senderUserId !== API.currentUser.id && !scope.row.$isExpired">
<template v-if="scope.row.senderUserId !== currentUser.id && !scope.row.$isExpired">
<template v-if="scope.row.type === 'friendRequest'">
<el-tooltip placement="top" content="Accept" :disabled="hideTooltips">
<el-button
@@ -257,7 +257,11 @@
<template v-if="scope.row.responses">
<template v-for="response in scope.row.responses">
<el-tooltip placement="top" :content="response.text" :disabled="hideTooltips">
<el-tooltip
placement="top"
:content="response.text"
:disabled="hideTooltips"
:key="response.text">
<el-button
v-if="response.icon === 'check'"
type="text"
@@ -400,85 +404,62 @@
</data-tables>
<SendInviteResponseDialog
:send-invite-response-dialog="sendInviteResponseDialog"
:send-invite-response-dialog-visible.sync="sendInviteResponseDialogVisible"
:invite-response-message-table="inviteResponseMessageTable"
:upload-image="uploadImage" />
:send-invite-response-dialog-visible.sync="sendInviteResponseDialogVisible" />
<SendInviteRequestResponseDialog
:send-invite-response-dialog="sendInviteResponseDialog"
:send-invite-request-response-dialog-visible.sync="sendInviteRequestResponseDialogVisible"
:invite-request-response-message-table="inviteRequestResponseMessageTable"
:upload-image="uploadImage" />
:send-invite-request-response-dialog-visible.sync="sendInviteRequestResponseDialogVisible" />
</div>
</template>
<script>
export default {
name: 'NotificationTab'
};
</script>
<script setup>
import { getCurrentInstance, inject, ref } from 'vue';
import { storeToRefs } from 'pinia';
import { getCurrentInstance, ref } from 'vue';
import { useI18n } from 'vue-i18n-bridge';
import { friendRequest, inviteMessagesRequest, notificationRequest, worldRequest } from '../../api';
import utils from '../../classes/utils';
import { parseLocation } from '../../composables/instance/utils';
import { convertFileUrlToImageUrl } from '../../composables/shared/utils';
import { friendRequest, notificationRequest, worldRequest } from '../../api';
import {
checkCanInvite,
convertFileUrlToImageUrl,
escapeTag,
formatDateFilter,
parseLocation,
removeFromArray
} from '../../shared/utils';
import configRepository from '../../service/config';
import database from '../../service/database';
import { database } from '../../service/database';
import {
useAppearanceSettingsStore,
useGalleryStore,
useGameStore,
useGroupStore,
useInviteStore,
useLocationStore,
useNotificationStore,
useUiStore,
useUserStore,
useWorldStore
} from '../../stores';
import SendInviteRequestResponseDialog from './dialogs/SendInviteRequestResponseDialog.vue';
import SendInviteResponseDialog from './dialogs/SendInviteResponseDialog.vue';
import Location from '../../components/Location.vue';
import Noty from 'noty';
const { hideTooltips } = storeToRefs(useAppearanceSettingsStore());
const { showUserDialog } = useUserStore();
const { showWorldDialog } = useWorldStore();
const { showGroupDialog } = useGroupStore();
const { lastLocation, lastLocationDestination } = storeToRefs(useLocationStore());
const { refreshInviteMessageTableData } = useInviteStore();
const { clearInviteImageUpload } = useGalleryStore();
const { notificationTable, isNotificationsLoading } = storeToRefs(useNotificationStore());
const { refreshNotifications, handleNotificationHide } = useNotificationStore();
const { menuActiveIndex, shiftHeld } = storeToRefs(useUiStore());
const { isGameRunning } = storeToRefs(useGameStore());
const { showFullscreenImageDialog } = useGalleryStore();
const { currentUser } = storeToRefs(useUserStore());
const { t } = useI18n();
const { $confirm, $message } = getCurrentInstance().proxy;
const API = inject('API');
const showWorldDialog = inject('showWorldDialog');
const showGroupDialog = inject('showGroupDialog');
const showUserDialog = inject('showUserDialog');
const showFullscreenImageDialog = inject('showFullscreenImageDialog');
const clearInviteImageUpload = inject('clearInviteImageUpload');
const props = defineProps({
menuActiveIndex: {
type: String,
default: ''
},
notificationTable: {
type: Object,
default: () => ({})
},
shiftHeld: { type: Boolean, default: false },
hideTooltips: { type: Boolean, default: false },
lastLocation: { type: Object, default: () => ({}) },
inviteResponseMessageTable: {
type: Object,
default: () => ({})
},
uploadImage: {
type: String,
default: ''
},
lastLocationDestination: {
type: String,
default: ''
},
isGameRunning: {
type: Boolean,
default: false
},
checkCanInvite: {
type: Function,
default: () => true
},
inviteRequestResponseMessageTable: {
type: Object,
default: () => ({})
}
});
const sendInviteResponseDialog = ref({
messageSlot: {},
invite: {}
@@ -491,7 +472,7 @@
function saveTableFilters() {
configRepository.setString(
'VRCX_notificationTableFilters',
JSON.stringify(props.notificationTable.filters[0].value)
JSON.stringify(notificationTable.value.filters[0].value)
);
}
@@ -536,7 +517,7 @@
function showSendInviteResponseDialog(invite) {
sendInviteResponseDialog.value.invite = invite;
sendInviteResponseDialog.value.messageSlot = {};
inviteMessagesRequest.refreshInviteMessageTableData('response');
refreshInviteMessageTableData('response');
clearInviteImageUpload();
sendInviteResponseDialogVisible.value = true;
}
@@ -548,10 +529,9 @@
type: 'info',
callback: (action) => {
if (action === 'confirm') {
let currentLocation = props.lastLocation.location;
// todo
if (props.lastLocation.location === 'traveling') {
currentLocation = props.lastLocationDestination;
let currentLocation = lastLocation.value.location;
if (lastLocation.value.location === 'traveling') {
currentLocation = lastLocationDestination.value;
}
const L = parseLocation(currentLocation);
worldRequest
@@ -585,14 +565,14 @@
function showSendInviteRequestResponseDialog(invite) {
sendInviteResponseDialog.value.invite = invite;
sendInviteResponseDialog.value.messageSlot = {};
inviteMessagesRequest.refreshInviteMessageTableData('requestResponse');
refreshInviteMessageTableData('requestResponse');
clearInviteImageUpload();
sendInviteRequestResponseDialogVisible.value = true;
}
function sendNotificationResponse(notificationId, responses, responseType) {
if (!Array.isArray(responses) || responses.length === 0) {
return null;
return;
}
let responseData = '';
for (let i = 0; i < responses.length; i++) {
@@ -601,21 +581,41 @@
break;
}
}
return notificationRequest.sendNotificationResponse({
const params = {
notificationId,
responseType,
responseData
});
};
notificationRequest
.sendNotificationResponse(params)
.then((json) => {
const args = {
json,
params
};
handleNotificationHide(args);
new Noty({
type: 'success',
text: escapeTag(args.json)
}).show();
console.log('NOTIFICATION:RESPONSE', args);
})
.catch((err) => {
handleNotificationHide({ params });
notificationRequest.hideNotificationV2(params.notificationId);
throw err;
});
}
function hideNotification(row) {
async function hideNotification(row) {
if (row.type === 'ignoredFriendRequest') {
friendRequest.deleteHiddenFriendRequest(
const args = await friendRequest.deleteHiddenFriendRequest(
{
notificationId: row.id
},
row.senderUserId
);
useNotificationStore().handleNotificationHide(args);
} else {
notificationRequest.hideNotification({
notificationId: row.id
@@ -637,7 +637,7 @@
}
function deleteNotificationLog(row) {
utils.removeFromArray(props.notificationTable.data, row);
removeFromArray(notificationTable.value.data, row);
if (row.type !== 'friendRequest' && row.type !== 'ignoredFriendRequest') {
database.deleteNotification(row.id);
}