refactor store

This commit is contained in:
pa
2026-03-06 22:42:43 +09:00
parent e665b3815d
commit 8ddedb2d2d
29 changed files with 3269 additions and 888 deletions
+6 -33
View File
@@ -5,17 +5,19 @@ import { useI18n } from 'vue-i18n';
import {
checkVRChatCache,
createDefaultAvatarRef,
extractFileId,
getAvailablePlatforms,
getBundleDateSize,
getPlatformInfo,
replaceBioSymbols,
sanitizeEntityJson,
storeAvatarImage
} from '../shared/utils';
import { avatarRequest, miscRequest } from '../api';
import { patchAvatarFromEvent } from '../query';
import { AppDebug } from '../service/appConfig';
import { database } from '../service/database';
import { patchAvatarFromEvent } from '../query';
import { processBulk } from '../service/request';
import { useAdvancedSettingsStore } from './settings/advanced';
import { useAvatarProviderStore } from './avatarProvider';
@@ -92,40 +94,10 @@ export const useAvatarStore = defineStore('Avatar', () => {
* @returns {object} ref
*/
function applyAvatar(json) {
json.name = replaceBioSymbols(json.name);
json.description = replaceBioSymbols(json.description);
sanitizeEntityJson(json, ['name', 'description']);
let ref = cachedAvatars.get(json.id);
if (typeof ref === 'undefined') {
ref = {
acknowledgements: '',
authorId: '',
authorName: '',
created_at: '',
description: '',
featured: false,
highestPrice: null,
id: '',
imageUrl: '',
listingDate: null,
lock: false,
lowestPrice: null,
name: '',
pendingUpload: false,
performance: {},
productId: null,
publishedListings: [],
releaseStatus: '',
searchable: false,
styles: [],
tags: [],
thumbnailImageUrl: '',
unityPackageUrl: '',
unityPackageUrlObject: {},
unityPackages: [],
updated_at: '',
version: 0,
...json
};
ref = createDefaultAvatarRef(json);
cachedAvatars.set(ref.id, ref);
} else {
const { unityPackages } = ref;
@@ -178,6 +150,7 @@ export const useAvatarStore = defineStore('Avatar', () => {
/**
*
* @param {string} avatarId
* @param options
* @returns
*/
function showAvatarDialog(avatarId, options = {}) {
+92 -22
View File
@@ -5,6 +5,8 @@ import { useI18n } from 'vue-i18n';
import {
compareByName,
createDefaultFavoriteCachedRef,
createDefaultFavoriteGroupRef,
removeFromArray,
replaceReactiveObject
} from '../shared/utils';
@@ -209,6 +211,11 @@ export const useFavoriteStore = defineStore('Favorite', () => {
return favoriteGroup.length;
});
/**
*
* @param list
* @param selectionRef
*/
function syncFavoriteSelection(list, selectionRef) {
if (!Array.isArray(list)) {
selectionRef.value = [];
@@ -255,6 +262,9 @@ export const useFavoriteStore = defineStore('Favorite', () => {
{ flush: 'sync' }
);
/**
*
*/
function getCachedFavoriteGroupsByTypeName() {
const group = {};
@@ -274,10 +284,18 @@ export const useFavoriteStore = defineStore('Favorite', () => {
return group;
}
/**
*
* @param objectId
*/
function getCachedFavoritesByObjectId(objectId) {
return cachedFavoritesByObjectId.get(objectId);
}
/**
*
* @param args
*/
function handleFavoriteAdd(args) {
handleFavorite({
json: args.json,
@@ -310,6 +328,10 @@ export const useFavoriteStore = defineStore('Favorite', () => {
updateFavoriteDialog(args.params.objectId);
}
/**
*
* @param args
*/
function handleFavorite(args) {
args.ref = applyFavoriteCached(args.json);
applyFavorite(args.ref.type, args.ref.favoriteId);
@@ -329,6 +351,10 @@ export const useFavoriteStore = defineStore('Favorite', () => {
}
}
/**
*
* @param objectId
*/
function handleFavoriteDelete(objectId) {
const ref = getCachedFavoritesByObjectId(objectId);
if (typeof ref === 'undefined') {
@@ -337,10 +363,18 @@ export const useFavoriteStore = defineStore('Favorite', () => {
handleFavoriteAtDelete(ref);
}
/**
*
* @param args
*/
function handleFavoriteGroup(args) {
args.ref = applyFavoriteGroup(args.json);
}
/**
*
* @param args
*/
function handleFavoriteGroupClear(args) {
const key = `${args.params.type}:${args.params.group}`;
for (const ref of cachedFavorites.values()) {
@@ -351,6 +385,10 @@ export const useFavoriteStore = defineStore('Favorite', () => {
}
}
/**
*
* @param args
*/
function handleFavoriteWorldList(args) {
for (const json of args.json) {
if (json.id === '???') {
@@ -360,6 +398,10 @@ export const useFavoriteStore = defineStore('Favorite', () => {
}
}
/**
*
* @param args
*/
function handleFavoriteAvatarList(args) {
for (const json of args.json) {
if (json.releaseStatus === 'hidden') {
@@ -369,6 +411,10 @@ export const useFavoriteStore = defineStore('Favorite', () => {
}
}
/**
*
* @param ref
*/
function handleFavoriteAtDelete(ref) {
const favorite = state.favoriteObjects.get(ref.favoriteId);
removeFromArray(state.favoriteFriends_, favorite);
@@ -536,6 +582,9 @@ export const useFavoriteStore = defineStore('Favorite', () => {
}
}
/**
*
*/
function refreshFavoriteGroups() {
if (isFavoriteGroupLoading.value) {
return;
@@ -567,6 +616,9 @@ export const useFavoriteStore = defineStore('Favorite', () => {
});
}
/**
*
*/
function buildFavoriteGroups() {
let group;
let groups;
@@ -683,6 +735,9 @@ export const useFavoriteStore = defineStore('Favorite', () => {
countFavoriteGroups();
}
/**
*
*/
function countFavoriteGroups() {
const cachedFavoriteGroups = getCachedFavoriteGroupsByTypeName();
for (const key in cachedFavoriteGroups) {
@@ -764,17 +819,7 @@ export const useFavoriteStore = defineStore('Favorite', () => {
function applyFavoriteGroup(json) {
let ref = cachedFavoriteGroups.value[json.id];
if (typeof ref === 'undefined') {
ref = {
id: '',
ownerId: '',
ownerDisplayName: '',
name: '',
displayName: '',
type: '',
visibility: '',
tags: [],
...json
};
ref = createDefaultFavoriteGroupRef(json);
cachedFavoriteGroups.value[ref.id] = ref;
} else {
Object.assign(ref, json);
@@ -790,19 +835,9 @@ export const useFavoriteStore = defineStore('Favorite', () => {
function applyFavoriteCached(json) {
let ref = cachedFavorites.get(json.id);
if (typeof ref === 'undefined') {
ref = {
id: '',
type: '',
favoriteId: '',
tags: [],
// VRCX
$groupKey: '',
//
...json
};
ref = createDefaultFavoriteCachedRef(json);
cachedFavorites.set(ref.id, ref);
cachedFavoritesByObjectId.set(ref.favoriteId, ref);
ref.$groupKey = `${ref.type}:${String(ref.tags[0])}`;
if (
ref.type === 'friend' &&
(!generalSettingsStore.localFavoriteFriendsGroups.some(
@@ -893,14 +928,23 @@ export const useFavoriteStore = defineStore('Favorite', () => {
}
}
/**
*
*/
function showWorldImportDialog() {
worldImportDialogVisible.value = true;
}
/**
*
*/
function showAvatarImportDialog() {
avatarImportDialogVisible.value = true;
}
/**
*
*/
function showFriendImportDialog() {
friendImportDialogVisible.value = true;
}
@@ -1016,6 +1060,10 @@ export const useFavoriteStore = defineStore('Favorite', () => {
return false;
}
/**
*
* @param objectId
*/
function updateFavoriteDialog(objectId) {
const D = favoriteDialog.value;
if (!D.visible || D.objectId !== objectId) {
@@ -1108,6 +1156,9 @@ export const useFavoriteStore = defineStore('Favorite', () => {
});
}
/**
*
*/
function sortLocalAvatarFavorites() {
if (!appearanceSettingsStore.sortFavorites) {
for (let i = 0; i < localAvatarFavoriteGroups.value.length; ++i) {
@@ -1294,6 +1345,9 @@ export const useFavoriteStore = defineStore('Favorite', () => {
});
}
/**
*
*/
function sortLocalWorldFavorites() {
if (!appearanceSettingsStore.sortFavorites) {
for (let i = 0; i < localWorldFavoriteGroups.value.length; ++i) {
@@ -1718,6 +1772,11 @@ export const useFavoriteStore = defineStore('Favorite', () => {
});
}
/**
*
* @param type
* @param objectId
*/
function showFavoriteDialog(type, objectId) {
const D = favoriteDialog.value;
D.type = type;
@@ -1726,12 +1785,18 @@ export const useFavoriteStore = defineStore('Favorite', () => {
updateFavoriteDialog(objectId);
}
/**
*
*/
async function saveSortFavoritesOption() {
getLocalWorldFavorites();
getLocalFriendFavorites();
appearanceSettingsStore.setSortFavorites();
}
/**
*
*/
async function initFavorites() {
refreshFavorites();
getLocalWorldFavorites();
@@ -1739,6 +1804,11 @@ export const useFavoriteStore = defineStore('Favorite', () => {
getLocalFriendFavorites();
}
/**
*
* @param a
* @param b
*/
function compareByFavoriteSortOrder(a, b) {
const indexA = favoritesSortOrder.value.indexOf(a.id);
const indexB = favoritesSortOrder.value.indexOf(b.id);
+106 -71
View File
@@ -8,11 +8,17 @@ import dayjs from 'dayjs';
import {
compareGameLogRows,
createJoinLeaveEntry,
createLocationEntry,
createPortalSpawnEntry,
createResourceLoadEntry,
findUserByDisplayName,
formatSeconds,
gameLogSearchFilter,
getGroupName,
parseInventoryFromUrl,
parseLocation,
parsePrintFromUrl,
replaceBioSymbols
} from '../../shared/utils';
import { AppDebug } from '../../service/appConfig';
@@ -131,6 +137,9 @@ export const useGameLogStore = defineStore('GameLog', () => {
{ flush: 'sync' }
);
/**
*
*/
async function init() {
gameLogTable.value.filter = JSON.parse(
await configRepository.getString('VRCX_gameLogTableFilters', '[]')
@@ -143,6 +152,10 @@ export const useGameLogStore = defineStore('GameLog', () => {
init();
/**
*
* @param entry
*/
function insertGameLogSorted(entry) {
const arr = gameLogTableData.value;
if (arr.length === 0) {
@@ -170,6 +183,9 @@ export const useGameLogStore = defineStore('GameLog', () => {
gameLogTableData.value = [...arr, entry];
}
/**
*
*/
function clearNowPlaying() {
nowPlaying.value = {
url: '',
@@ -186,6 +202,10 @@ export const useGameLogStore = defineStore('GameLog', () => {
vrStore.updateVrNowPlaying();
}
/**
*
* @param data
*/
function setNowPlaying(data) {
const ctx = structuredClone(data);
if (nowPlaying.value.url !== ctx.videoUrl) {
@@ -257,6 +277,9 @@ export const useGameLogStore = defineStore('GameLog', () => {
advancedSettingsStore
});
/**
*
*/
function updateNowPlaying() {
const np = nowPlaying.value;
if (!nowPlaying.value.playing) {
@@ -275,6 +298,9 @@ export const useGameLogStore = defineStore('GameLog', () => {
workerTimers.setTimeout(() => updateNowPlaying(), 1000);
}
/**
*
*/
async function tryLoadPlayerList() {
// TODO: make this work again
if (!gameStore.isGameRunning) {
@@ -355,6 +381,10 @@ export const useGameLogStore = defineStore('GameLog', () => {
}
}
/**
*
* @param row
*/
function gameLogIsFriend(row) {
if (typeof row.isFriend !== 'undefined') {
return row.isFriend;
@@ -365,6 +395,10 @@ export const useGameLogStore = defineStore('GameLog', () => {
return friendStore.friends.has(row.userId);
}
/**
*
* @param row
*/
function gameLogIsFavorite(row) {
if (typeof row.isFavorite !== 'undefined') {
return row.isFavorite;
@@ -375,6 +409,9 @@ export const useGameLogStore = defineStore('GameLog', () => {
return friendStore.localFavoriteFriends.has(row.userId);
}
/**
*
*/
async function gameLogTableLookup() {
await configRepository.setString(
'VRCX_gameLogTableFilters',
@@ -416,6 +453,10 @@ export const useGameLogStore = defineStore('GameLog', () => {
}
}
/**
*
* @param entry
*/
function addGameLog(entry) {
entry.isFriend = gameLogIsFriend(entry);
entry.isFavorite = gameLogIsFavorite(entry);
@@ -456,6 +497,10 @@ export const useGameLogStore = defineStore('GameLog', () => {
uiStore.notifyMenu('game-log');
}
/**
*
* @param input
*/
async function addGamelogLocationToDatabase(input) {
const groupName = await getGroupName(input.location);
const entry = {
@@ -465,10 +510,17 @@ export const useGameLogStore = defineStore('GameLog', () => {
database.addGamelogLocationToDatabase(entry);
}
/**
*
* @param row
*/
function gameLogSearch(row) {
return gameLogSearchFilter(row, gameLogTable.value.search);
}
/**
*
*/
function sweepGameLog() {
const j = gameLogTableData.value.length;
if (j > vrcxStore.maxTableSize + 50) {
@@ -476,6 +528,11 @@ export const useGameLogStore = defineStore('GameLog', () => {
}
}
/**
*
* @param gameLog
* @param location
*/
function addGameLogEntry(gameLog, location) {
let entry = undefined;
if (advancedSettingsStore.gameLogDisabled) {
@@ -543,15 +600,12 @@ export const useGameLogStore = defineStore('GameLog', () => {
gameLog.dt
);
const L = parseLocation(gameLog.location);
entry = {
created_at: gameLog.dt,
type: 'Location',
location: gameLog.location,
worldId: L.worldId,
worldName,
groupName: '',
time: 0
};
entry = createLocationEntry(
gameLog.dt,
gameLog.location,
L.worldId,
worldName
);
getGroupName(gameLog.location).then((groupName) => {
entry.groupName = groupName;
});
@@ -595,14 +649,13 @@ export const useGameLogStore = defineStore('GameLog', () => {
}
vrStore.updateVRLastLocation();
instanceStore.getCurrentInstanceUserList();
entry = {
created_at: gameLog.dt,
type: 'OnPlayerJoined',
displayName: gameLog.displayName,
entry = createJoinLeaveEntry(
'OnPlayerJoined',
gameLog.dt,
gameLog.displayName,
location,
userId,
time: 0
};
userId
);
database.addGamelogJoinLeaveToDatabase(entry);
break;
case 'player-left':
@@ -617,29 +670,21 @@ export const useGameLogStore = defineStore('GameLog', () => {
photonStore.photonLobbyAvatars.delete(userId);
vrStore.updateVRLastLocation();
instanceStore.getCurrentInstanceUserList();
entry = {
created_at: gameLog.dt,
type: 'OnPlayerLeft',
displayName: gameLog.displayName,
entry = createJoinLeaveEntry(
'OnPlayerLeft',
gameLog.dt,
gameLog.displayName,
location,
userId,
time
};
);
database.addGamelogJoinLeaveToDatabase(entry);
break;
case 'portal-spawn':
if (vrcxStore.ipcEnabled && gameStore.isGameRunning) {
break;
}
entry = {
created_at: gameLog.dt,
type: 'PortalSpawn',
location,
displayName: '',
userId: '',
instanceId: '',
worldName: ''
};
entry = createPortalSpawnEntry(gameLog.dt, location);
database.addGamelogPortalSpawnToDatabase(entry);
break;
case 'video-play':
@@ -665,15 +710,12 @@ export const useGameLogStore = defineStore('GameLog', () => {
break;
}
lastResourceloadUrl.value = gameLog.resourceUrl;
entry = {
created_at: gameLog.dt,
type:
gameLog.type === 'resource-load-string'
? 'StringLoad'
: 'ImageLoad',
resourceUrl: gameLog.resourceUrl,
entry = createResourceLoadEntry(
gameLog.type,
gameLog.dt,
gameLog.resourceUrl,
location
};
);
database.addGamelogResourceLoadToDatabase(entry);
break;
case 'screenshot':
@@ -711,42 +753,18 @@ export const useGameLogStore = defineStore('GameLog', () => {
// }
if (advancedSettingsStore.saveInstanceEmoji) {
try {
// https://api.vrchat.cloud/api/1/user/usr_032383a7-748c-4fb2-94e4-bcb928e5de6b/inventory/inv_75781d65-92fe-4a80-a1ff-27ee6e843b08
const url = new URL(gameLog.url);
if (
url.pathname.substring(0, 12) === '/api/1/user/' &&
url.pathname.includes('/inventory/inv_')
) {
const pathArray = url.pathname.split('/');
const userId = pathArray[4];
const inventoryId = pathArray[6];
if (userId && inventoryId.length === 40) {
galleryStore.queueCheckInstanceInventory(
inventoryId,
userId
);
}
}
} catch (err) {
console.error(err);
const inv = parseInventoryFromUrl(gameLog.url);
if (inv) {
galleryStore.queueCheckInstanceInventory(
inv.inventoryId,
inv.userId
);
}
}
if (advancedSettingsStore.saveInstancePrints) {
try {
let printId = '';
const url1 = new URL(gameLog.url);
if (
url1.pathname.substring(0, 14) === '/api/1/prints/'
) {
const pathArray = url1.pathname.split('/');
printId = pathArray[4];
}
if (printId && printId.length === 41) {
galleryStore.queueSavePrintToFile(printId);
}
} catch (err) {
console.error(err);
const printId = parsePrintFromUrl(gameLog.url);
if (printId) {
galleryStore.queueSavePrintToFile(printId);
}
}
break;
@@ -902,12 +920,19 @@ export const useGameLogStore = defineStore('GameLog', () => {
}
}
/**
*
*/
async function getGameLogTable() {
await database.initTables();
const dateTill = await database.getLastDateGameLogDatabase();
updateGameLog(dateTill);
}
/**
*
* @param dateTill
*/
async function updateGameLog(dateTill) {
await gameLogService.setDateTill(dateTill);
await new Promise((resolve) => {
@@ -923,6 +948,10 @@ export const useGameLogStore = defineStore('GameLog', () => {
}
// use in C#
/**
*
* @param json
*/
function addGameLogEvent(json) {
const rawLogs = JSON.parse(json);
const gameLog = gameLogService.parseRawGameLog(
@@ -941,6 +970,9 @@ export const useGameLogStore = defineStore('GameLog', () => {
addGameLogEntry(gameLog, locationStore.lastLocation.location);
}
/**
*
*/
async function disableGameLogDialog() {
if (gameStore.isGameRunning) {
toast.error(t('message.gamelog.vrchat_must_be_closed'));
@@ -962,6 +994,9 @@ export const useGameLogStore = defineStore('GameLog', () => {
}
}
/**
*
*/
async function initGameLogTable() {
gameLogTable.value.loading = true;
const rows = await database.lookupGameLogDatabase(
+137 -96
View File
@@ -3,20 +3,22 @@ import { defineStore } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
import {
convertFileUrlToImageUrl,
createDefaultGroupRef,
hasGroupPermission,
replaceBioSymbols,
sanitizeEntityJson
} from '../shared/utils';
import {
groupRequest,
instanceRequest,
userRequest,
worldRequest
} from '../api';
import { patchGroupFromEvent } from '../query';
import {
convertFileUrlToImageUrl,
hasGroupPermission,
replaceBioSymbols
} from '../shared/utils';
import { database } from '../service/database';
import { groupDialogFilterOptions } from '../shared/constants/';
import { patchGroupFromEvent } from '../query';
import { useGameStore } from './game';
import { useInstanceStore } from './instance';
import { useModalStore } from './modal';
@@ -128,6 +130,11 @@ export const useGroupStore = defineStore('Group', () => {
{ flush: 'sync' }
);
/**
*
* @param groupId
* @param options
*/
function showGroupDialog(groupId, options = {}) {
if (!groupId) {
return;
@@ -232,6 +239,11 @@ export const useGroupStore = defineStore('Group', () => {
);
}
/**
*
* @param ref
* @param message
*/
function groupChange(ref, message) {
if (!currentUserGroupsInit.value) {
return;
@@ -260,6 +272,9 @@ export const useGroupStore = defineStore('Group', () => {
workerTimers.setTimeout(saveCurrentUserGroups, 100);
}
/**
*
*/
function saveCurrentUserGroups() {
if (!currentUserGroupsInit.value) {
return;
@@ -284,10 +299,10 @@ export const useGroupStore = defineStore('Group', () => {
/**
*
* @param {object} ref
* @param {array} oldRoles
* @param {array} newRoles
* @param {array} oldRoleIds
* @param {array} newRoleIds
* @param {Array} oldRoles
* @param {Array} newRoles
* @param {Array} oldRoleIds
* @param {Array} newRoleIds
*/
function groupRoleChange(ref, oldRoles, newRoles, oldRoleIds, newRoleIds) {
// check for removed/added roleIds
@@ -401,7 +416,7 @@ export const useGroupStore = defineStore('Group', () => {
/**
*
* @param {{ groupId: string }} params
* @return { Promise<{posts: any, params}> }
* @returns { Promise<{posts: any, params}> }
*/
async function getAllGroupPosts(params) {
const n = 100;
@@ -442,6 +457,10 @@ export const useGroupStore = defineStore('Group', () => {
return returnArgs;
}
/**
*
* @param groupId
*/
function getGroupDialogGroup(groupId) {
const D = groupDialog.value;
D.isGetGroupDialogGroupLoading = false;
@@ -497,32 +516,38 @@ export const useGroupStore = defineStore('Group', () => {
});
}
});
groupRequest.getCachedGroupCalendar(groupId).then((args) => {
if (groupDialog.value.id === args.params.groupId) {
D.calendar = args.json.results;
for (const event of D.calendar) {
applyGroupEvent(event);
// fetch again for isFollowing
groupRequest
.getCachedGroupCalendarEvent({
groupId,
eventId: event.id
})
.then((args) => {
Object.assign(
event,
applyGroupEvent(args.json)
);
});
groupRequest
.getCachedGroupCalendar(groupId)
.then((args) => {
if (groupDialog.value.id === args.params.groupId) {
D.calendar = args.json.results;
for (const event of D.calendar) {
applyGroupEvent(event);
// fetch again for isFollowing
groupRequest
.getCachedGroupCalendarEvent({
groupId,
eventId: event.id
})
.then((args) => {
Object.assign(
event,
applyGroupEvent(args.json)
);
});
}
}
}
});
});
}
nextTick(() => (D.isGetGroupDialogGroupLoading = false));
return args;
});
}
/**
*
* @param event
*/
function applyGroupEvent(event) {
return {
userInterest: {
@@ -536,6 +561,9 @@ export const useGroupStore = defineStore('Group', () => {
};
}
/**
*
*/
async function updateInGameGroupOrder() {
inGameGroupOrder.value = [];
try {
@@ -551,6 +579,11 @@ export const useGroupStore = defineStore('Group', () => {
}
}
/**
*
* @param a
* @param b
*/
function sortGroupInstancesByInGame(a, b) {
const aIndex = inGameGroupOrder.value.indexOf(a?.group?.id);
const bIndex = inGameGroupOrder.value.indexOf(b?.group?.id);
@@ -566,6 +599,10 @@ export const useGroupStore = defineStore('Group', () => {
return aIndex - bIndex;
}
/**
*
* @param groupId
*/
function leaveGroup(groupId) {
groupRequest
.leaveGroup({
@@ -590,6 +627,10 @@ export const useGroupStore = defineStore('Group', () => {
});
}
/**
*
* @param groupId
*/
function leaveGroupPrompt(groupId) {
modalStore
.confirm({
@@ -603,6 +644,9 @@ export const useGroupStore = defineStore('Group', () => {
.catch(() => {});
}
/**
*
*/
function updateGroupPostSearch() {
const D = groupDialog.value;
const search = D.postsSearch.toLowerCase();
@@ -620,6 +664,11 @@ export const useGroupStore = defineStore('Group', () => {
});
}
/**
*
* @param groupId
* @param visibility
*/
function setGroupVisibility(groupId, visibility) {
return groupRequest
.setGroupMemberProps(userStore.currentUser.id, groupId, {
@@ -632,6 +681,11 @@ export const useGroupStore = defineStore('Group', () => {
});
}
/**
*
* @param groupId
* @param subscribe
*/
function setGroupSubscription(groupId, subscribe) {
return groupRequest
.setGroupMemberProps(userStore.currentUser.id, groupId, {
@@ -651,73 +705,9 @@ export const useGroupStore = defineStore('Group', () => {
*/
function applyGroup(json) {
let ref = cachedGroups.get(json.id);
if (json.rules) {
json.rules = replaceBioSymbols(json.rules);
}
if (json.name) {
json.name = replaceBioSymbols(json.name);
}
if (json.description) {
json.description = replaceBioSymbols(json.description);
}
sanitizeEntityJson(json, ['rules', 'name', 'description']);
if (typeof ref === 'undefined') {
ref = {
id: '',
name: '',
shortCode: '',
description: '',
bannerId: '',
bannerUrl: '',
createdAt: '',
discriminator: '',
galleries: [],
iconId: '',
iconUrl: '',
isVerified: false,
joinState: '',
languages: [],
links: [],
memberCount: 0,
memberCountSyncedAt: '',
membershipStatus: '',
onlineMemberCount: 0,
ownerId: '',
privacy: '',
rules: null,
tags: [],
// in group
initialRoleIds: [],
myMember: {
bannedAt: null,
groupId: '',
has2FA: false,
id: '',
isRepresenting: false,
isSubscribedToAnnouncements: false,
joinedAt: '',
managerNotes: '',
membershipStatus: '',
permissions: [],
roleIds: [],
userId: '',
visibility: '',
_created_at: '',
_id: '',
_updated_at: ''
},
updatedAt: '',
// includeRoles: true
roles: [],
// group list
$memberId: '',
groupId: '',
isRepresenting: false,
memberVisibility: false,
mutualGroup: false,
// VRCX
$languages: [],
...json
};
ref = createDefaultGroupRef(json);
cachedGroups.set(ref.id, ref);
} else {
if (currentUserGroups.has(ref.id)) {
@@ -796,6 +786,10 @@ export const useGroupStore = defineStore('Group', () => {
return ref;
}
/**
*
* @param args
*/
function handleGroupRepresented(args) {
const D = userStore.userDialog;
const json = args.json;
@@ -819,6 +813,10 @@ export const useGroupStore = defineStore('Group', () => {
applyGroup(json);
}
/**
*
* @param args
*/
function handleGroupList(args) {
for (const json of args.json) {
json.$memberId = json.id;
@@ -827,6 +825,10 @@ export const useGroupStore = defineStore('Group', () => {
}
}
/**
*
* @param args
*/
function handleGroupMemberProps(args) {
if (args.userId === userStore.currentUser.id) {
const json = args.json;
@@ -873,6 +875,10 @@ export const useGroupStore = defineStore('Group', () => {
}
}
/**
*
* @param args
*/
function handleGroupPermissions(args) {
if (args.params.userId !== userStore.currentUser.id) {
return;
@@ -919,10 +925,18 @@ export const useGroupStore = defineStore('Group', () => {
updateGroupPostSearch();
}
/**
*
* @param args
*/
function handleGroupMember(args) {
args.ref = applyGroupMember(args.json);
}
/**
*
* @param args
*/
async function handleGroupUserInstances(args) {
groupInstances.value = [];
for (const json of args.json.instances) {
@@ -990,6 +1004,10 @@ export const useGroupStore = defineStore('Group', () => {
return json;
}
/**
*
* @param ref
*/
function applyGroupLanguage(ref) {
ref.$languages = [];
const { languages } = ref;
@@ -1008,6 +1026,11 @@ export const useGroupStore = defineStore('Group', () => {
}
}
/**
*
* @param userId
* @param groups
*/
async function loadCurrentUserGroups(userId, groups) {
const savedGroups = JSON.parse(
await configRepository.getString(
@@ -1063,6 +1086,9 @@ export const useGroupStore = defineStore('Group', () => {
getCurrentUserGroups();
}
/**
*
*/
async function getCurrentUserGroups() {
const args = await groupRequest.getGroups({
userId: userStore.currentUser.id
@@ -1082,6 +1108,9 @@ export const useGroupStore = defineStore('Group', () => {
saveCurrentUserGroups();
}
/**
*
*/
function getCurrentUserRepresentedGroup() {
return groupRequest
.getRepresentedGroup({
@@ -1093,6 +1122,9 @@ export const useGroupStore = defineStore('Group', () => {
});
}
/**
*
*/
async function initUserGroups() {
updateInGameGroupOrder();
loadCurrentUserGroups(
@@ -1101,6 +1133,10 @@ export const useGroupStore = defineStore('Group', () => {
);
}
/**
*
* @param userId
*/
function showModerateGroupDialog(userId) {
const D = moderateGroupDialog.value;
D.userId = userId;
@@ -1108,6 +1144,11 @@ export const useGroupStore = defineStore('Group', () => {
D.visible = true;
}
/**
*
* @param groupId
* @param userId
*/
function showGroupMemberModerationDialog(groupId, userId = '') {
const D = groupMemberModeration.value;
D.id = groupId;
+93 -82
View File
@@ -8,8 +8,11 @@ import {
compareByDisplayName,
compareById,
compareByLocationAt,
computeDisabledContentSettings,
createDefaultInstanceRef,
debounce,
displayLocation,
evictMapCache,
getAvailablePlatforms,
getBundleDateSize,
getGroupName,
@@ -25,12 +28,12 @@ import {
userRequest,
worldRequest
} from '../api';
import { patchInstanceFromEvent } from '../query';
import {
accessTypeLocaleKeyMap,
instanceContentSettings
} from '../shared/constants';
import { database } from '../service/database';
import { patchInstanceFromEvent } from '../query';
import { resolveRef } from '../shared/utils/resolveRef';
import { useAppearanceSettingsStore } from './settings/appearance';
import { useFriendStore } from './friend';
@@ -66,30 +69,26 @@ export const useInstanceStore = defineStore('Instance', () => {
let cachedInstances = new Map();
/**
*
*/
function cleanInstanceCache() {
const maxSize = 200;
if (cachedInstances.size <= maxSize) {
return;
}
const removable = [];
cachedInstances.forEach((ref, id) => {
if (
[...friendStore.friends.values()].some(
(f) => f.$location?.tag === id
)
) {
return;
const friendLocationTags = new Set(
[...friendStore.friends.values()]
.map((f) => f.$location?.tag)
.filter(Boolean)
);
evictMapCache(
cachedInstances,
200,
(_value, key) => friendLocationTags.has(key),
{
sortFn: (a, b) =>
(Date.parse(a.value.$fetchedAt) || 0) -
(Date.parse(b.value.$fetchedAt) || 0),
logLabel: 'Instance cache cleanup'
}
removable.push({
id,
fetchedAt: Date.parse(ref.$fetchedAt) || 0
});
});
removable.sort((a, b) => a.fetchedAt - b.fetchedAt);
const overBy = cachedInstances.size - maxSize;
for (let i = 0; i < overBy && i < removable.length; i++) {
cachedInstances.delete(removable[i].id);
}
);
}
const lastInstanceApplied = ref('');
@@ -183,6 +182,9 @@ export const useInstanceStore = defineStore('Instance', () => {
{ flush: 'sync' }
);
/**
*
*/
async function getInstanceJoinHistory() {
try {
const data = await database.getInstanceJoinHistory();
@@ -195,6 +197,11 @@ export const useInstanceStore = defineStore('Instance', () => {
}
}
/**
*
* @param location
* @param dateTime
*/
function addInstanceJoinHistory(location, dateTime) {
if (!location || !dateTime) {
return;
@@ -208,11 +215,18 @@ export const useInstanceStore = defineStore('Instance', () => {
instanceJoinHistory.set(location, epoch);
}
/**
*
*/
function hidePreviousInstancesDialogs() {
previousInstancesInfoDialog.value.visible = false;
previousInstancesListDialog.value.visible = false;
}
/**
*
* @param input
*/
function resolveUserRef(input) {
return resolveRef(input, {
emptyDefault: { id: '', displayName: '' },
@@ -222,6 +236,10 @@ export const useInstanceStore = defineStore('Instance', () => {
});
}
/**
*
* @param input
*/
function resolveWorldRef(input) {
return resolveRef(input, {
emptyDefault: { id: '', name: '' },
@@ -231,6 +249,10 @@ export const useInstanceStore = defineStore('Instance', () => {
});
}
/**
*
* @param input
*/
function resolveGroupRef(input) {
return resolveRef(input, {
emptyDefault: { id: '', name: '' },
@@ -240,6 +262,10 @@ export const useInstanceStore = defineStore('Instance', () => {
});
}
/**
*
* @param accessTypeNameRaw
*/
function translateAccessType(accessTypeNameRaw) {
const key = accessTypeLocaleKeyMap[accessTypeNameRaw];
if (!key) {
@@ -255,6 +281,11 @@ export const useInstanceStore = defineStore('Instance', () => {
return t(key);
}
/**
*
* @param instanceId
* @param worldNameOverride
*/
function formatPreviousInstancesInfoLabel(
instanceId,
worldNameOverride = ''
@@ -275,6 +306,10 @@ export const useInstanceStore = defineStore('Instance', () => {
return `${baseLabel} · ${accessTypeLabel}`;
}
/**
*
* @param instanceId
*/
function showPreviousInstancesInfoDialog(instanceId) {
previousInstancesInfoDialog.value.visible = true;
previousInstancesInfoDialog.value.instanceId = instanceId;
@@ -308,6 +343,11 @@ export const useInstanceStore = defineStore('Instance', () => {
}
}
/**
*
* @param variant
* @param targetRef
*/
async function showPreviousInstancesListDialog(variant, targetRef) {
previousInstancesListDialog.value.variant = variant;
let resolved = null;
@@ -335,6 +375,9 @@ export const useInstanceStore = defineStore('Instance', () => {
});
}
/**
*
*/
function updateCurrentInstanceWorld() {
let L;
let instanceId = locationStore.lastLocation.location;
@@ -472,53 +515,7 @@ export const useInstanceStore = defineStore('Instance', () => {
}
let ref = cachedInstances.get(json.id);
if (typeof ref === 'undefined') {
ref = {
id: '',
location: '',
instanceId: '',
name: '',
worldId: '',
type: '',
ownerId: '',
tags: [],
active: false,
full: false,
n_users: 0,
hasCapacityForYou: true, // not present depending on endpoint
capacity: 0,
recommendedCapacity: 0,
userCount: 0,
queueEnabled: false, // only present with group instance type
queueSize: 0, // only present when queuing is enabled
platforms: {},
gameServerVersion: 0,
hardClose: null, // boolean or null
closedAt: null, // string or null
secureName: '',
shortName: '',
world: {},
users: [], // only present when you're the owner
clientNumber: '',
contentSettings: {},
photonRegion: '',
region: '',
canRequestInvite: false,
permanent: false,
private: '', // part of instance tag
hidden: '', // part of instance tag
nonce: '', // only present when you're the owner
strict: false, // deprecated
displayName: null,
groupAccessType: null, // only present with group instance type
roleRestricted: false, // only present with group instance type
instancePersistenceEnabled: null,
playerPersistenceEnabled: null,
ageGate: null,
// VRCX
$fetchedAt: '',
$disabledContentSettings: [],
...json
};
ref = createDefaultInstanceRef(json);
cachedInstances.set(ref.id, ref);
cleanInstanceCache();
} else {
@@ -535,18 +532,10 @@ export const useInstanceStore = defineStore('Instance', () => {
return args;
});
}
ref.$disabledContentSettings = [];
if (json.contentSettings && Object.keys(json.contentSettings).length) {
for (const setting of instanceContentSettings) {
if (
typeof json.contentSettings[setting] === 'undefined' ||
json.contentSettings[setting] === true
) {
continue;
}
ref.$disabledContentSettings.push(setting);
}
}
ref.$disabledContentSettings = computeDisabledContentSettings(
json.contentSettings,
instanceContentSettings
);
if (ref.displayName) {
ref.displayName = replaceBioSymbols(ref.displayName);
}
@@ -578,6 +567,10 @@ export const useInstanceStore = defineStore('Instance', () => {
return ref;
}
/**
*
* @param location
*/
async function getInstanceName(location) {
let instanceName = '';
@@ -701,10 +694,16 @@ export const useInstanceStore = defineStore('Instance', () => {
}
}
/**
*
*/
function applyWorldDialogInstances() {
debounce(applyWorldDialogInstancesDebounced, 100)();
}
/**
*
*/
function applyWorldDialogInstancesDebounced() {
let ref;
let instance;
@@ -1079,6 +1078,9 @@ export const useInstanceStore = defineStore('Instance', () => {
D.instances = rooms;
}
/**
*
*/
function removeAllQueuedInstances() {
queuedInstances.forEach((ref) => {
toast.info(`Removed instance ${ref.$worldName} from queue`);
@@ -1233,6 +1235,9 @@ export const useInstanceStore = defineStore('Instance', () => {
// workerTimers.setTimeout(this.instanceQueueTimeout, 3600000);
}
/**
*
*/
function getCurrentInstanceUserList() {
if (!watchState.isFriendsLoaded) {
return;
@@ -1250,6 +1255,9 @@ export const useInstanceStore = defineStore('Instance', () => {
}
}
/**
*
*/
function updatePlayerListExecute() {
try {
updatePlayerListDebounce();
@@ -1260,6 +1268,9 @@ export const useInstanceStore = defineStore('Instance', () => {
state.updatePlayerListPending = false;
}
/**
*
*/
function updatePlayerListDebounce() {
const users = [];
const pushUser = function (ref) {
+125 -84
View File
@@ -7,14 +7,18 @@ import Noty from 'noty';
import dayjs from 'dayjs';
import {
applyBoopLegacyHandling,
checkCanInvite,
createDefaultNotificationRef,
createDefaultNotificationV2Ref,
escapeTag,
executeWithBackoff,
findUserByDisplayName,
getUserMemo,
parseLocation,
parseNotificationDetails,
removeFromArray,
replaceBioSymbols
sanitizeNotificationJson
} from '../../shared/utils';
import {
friendRequest,
@@ -163,6 +167,9 @@ export const useNotificationStore = defineStore('Notification', () => {
{ flush: 'sync' }
);
/**
*
*/
async function init() {
notificationTable.value.filters[0].value = JSON.parse(
await configRepository.getString(
@@ -174,6 +181,10 @@ export const useNotificationStore = defineStore('Notification', () => {
init();
/**
*
* @param args
*/
function handleNotification(args) {
args.ref = applyNotification(args.json);
const { ref } = args;
@@ -234,6 +245,10 @@ export const useNotificationStore = defineStore('Notification', () => {
D.incomingRequest = true;
}
/**
*
* @param notificationId
*/
function handleNotificationHide(notificationId) {
const ref = notificationTable.value.data.find(
(n) => n.id === notificationId
@@ -259,6 +274,10 @@ export const useNotificationStore = defineStore('Notification', () => {
});
}
/**
*
* @param args
*/
function handlePipelineNotification(args) {
const ref = args.json;
if (
@@ -373,6 +392,10 @@ export const useNotificationStore = defineStore('Notification', () => {
});
}
/**
*
* @param notificationId
*/
function handleNotificationSee(notificationId) {
removeFromArray(unseenNotifications.value, notificationId);
if (unseenNotifications.value.length === 0) {
@@ -392,6 +415,9 @@ export const useNotificationStore = defineStore('Notification', () => {
let seeProcessing = false;
const SEE_CONCURRENCY = 2;
/**
*
*/
async function processSeeQueue() {
if (seeProcessing) return;
seeProcessing = true;
@@ -443,7 +469,7 @@ export const useNotificationStore = defineStore('Notification', () => {
/**
* Queue a notification to be marked as seen.
* @param {string} notificationId
* @param {number} [version=1]
* @param {number} [version]
*/
function queueMarkAsSeen(notificationId, version = 1) {
if (seenIds.has(notificationId)) return;
@@ -452,6 +478,10 @@ export const useNotificationStore = defineStore('Notification', () => {
processSeeQueue();
}
/**
*
* @param args
*/
function handleNotificationAccept(args) {
let ref;
const array = notificationTable.value.data;
@@ -490,6 +520,10 @@ export const useNotificationStore = defineStore('Notification', () => {
D.isFriend = true;
}
/**
*
* @param args
*/
function handleNotificationExpire(args) {
const { ref } = args;
const D = userStore.userDialog;
@@ -509,10 +543,7 @@ export const useNotificationStore = defineStore('Notification', () => {
* @returns {object}
*/
function applyNotification(data) {
const json = { ...data };
if (json.message) {
json.message = replaceBioSymbols(json.message);
}
const json = sanitizeNotificationJson({ ...data });
let ref;
const array = notificationTable.value.data;
for (let i = array.length - 1; i >= 0; i--) {
@@ -521,102 +552,37 @@ export const useNotificationStore = defineStore('Notification', () => {
break;
}
}
// delete any null in json
for (const key in json) {
if (json[key] === null) {
delete json[key];
}
}
if (typeof ref === 'undefined') {
ref = {
id: '',
senderUserId: '',
senderUsername: '',
type: '',
message: '',
details: {},
seen: false,
created_at: '',
// VRCX
$isExpired: false,
//
...json
};
ref = createDefaultNotificationRef(json);
} else {
Object.assign(ref, json);
ref.$isExpired = false;
}
if (ref.details !== Object(ref.details)) {
let details = {};
if (ref.details !== '{}') {
try {
const object = JSON.parse(ref.details);
if (object === Object(object)) {
details = object;
}
} catch (err) {
console.log(err);
}
}
ref.details = details;
}
ref.details = parseNotificationDetails(ref.details);
return ref;
}
/**
*
* @param data
*/
function applyNotificationV2(data) {
const json = { ...data };
// delete any null in json
for (const key in json) {
if (json[key] === null || typeof json[key] === 'undefined') {
delete json[key];
}
}
if (json.message) {
json.message = replaceBioSymbols(json.message);
}
if (json.title) {
json.title = replaceBioSymbols(json.title);
}
const json = sanitizeNotificationJson({ ...data });
let ref = notificationTable.value.data.find((n) => n.id === json.id);
if (typeof ref === 'undefined') {
ref = {
id: '',
createdAt: '',
updatedAt: '',
expiresAt: '',
type: '',
link: '',
linkText: '',
message: '',
title: '',
imageUrl: '',
seen: false,
senderUserId: '',
senderUsername: '',
data: {},
responses: [],
details: {},
version: 2,
...json
};
ref = createDefaultNotificationV2Ref(json);
} else {
Object.assign(ref, json);
}
ref.created_at = ref.createdAt; // for table
// legacy handling of boops
if (ref.type === 'boop' && ref.title) {
ref.message = ref.title;
ref.title = '';
if (ref.details?.emojiId?.startsWith('default_')) {
ref.imageUrl = ref.details.emojiId;
ref.message += ` ${ref.details.emojiId.replace('default_', '')}`;
} else {
ref.imageUrl = `${AppDebug.endpointDomain}/file/${ref.details.emojiId}/${ref.details.emojiVersion}`;
}
}
applyBoopLegacyHandling(ref, AppDebug.endpointDomain);
return ref;
}
/**
*
* @param args
*/
function handleNotificationV2(args) {
const ref = applyNotificationV2(args.json);
if (ref.seen) {
@@ -645,6 +611,10 @@ export const useNotificationStore = defineStore('Notification', () => {
sharedFeedStore.addEntry(ref);
}
/**
*
* @param args
*/
function handleNotificationV2Update(args) {
const notificationId = args.params.notificationId;
const json = { ...args.json };
@@ -663,6 +633,10 @@ export const useNotificationStore = defineStore('Notification', () => {
}
}
/**
*
* @param notificationId
*/
function handleNotificationV2Hide(notificationId) {
database.expireNotificationV2(notificationId);
const ref = notificationTable.value.data.find(
@@ -674,6 +648,9 @@ export const useNotificationStore = defineStore('Notification', () => {
}
}
/**
*
*/
function expireFriendRequestNotifications() {
const array = notificationTable.value.data;
for (let i = array.length - 1; i >= 0; i--) {
@@ -813,6 +790,10 @@ export const useNotificationStore = defineStore('Notification', () => {
}
}
/**
*
* @param noty
*/
function playNoty(noty) {
if (
userStore.currentUser.status === 'busy' ||
@@ -1014,6 +995,10 @@ export const useNotificationStore = defineStore('Notification', () => {
return '';
}
/**
*
* @param gamelog
*/
function queueGameLogNoty(gamelog) {
const noty = structuredClone(gamelog);
let bias;
@@ -1090,6 +1075,10 @@ export const useNotificationStore = defineStore('Notification', () => {
}
}
/**
*
* @param feed
*/
function queueFeedNoty(feed) {
const noty = { ...feed };
if (noty.type === 'Avatar') {
@@ -1116,6 +1105,10 @@ export const useNotificationStore = defineStore('Notification', () => {
}
}
/**
*
* @param noty
*/
function queueFriendLogNoty(noty) {
if (noty.type === 'FriendRequest') {
return;
@@ -1133,6 +1126,10 @@ export const useNotificationStore = defineStore('Notification', () => {
}
}
/**
*
* @param noty
*/
function queueModerationNoty(noty) {
noty.isFriend = false;
noty.isFavorite = false;
@@ -1146,6 +1143,9 @@ export const useNotificationStore = defineStore('Notification', () => {
}
}
/**
*
*/
async function initNotifications() {
notificationInitStatus.value = false;
let tableData = await database.getNotificationsV2();
@@ -1161,6 +1161,9 @@ export const useNotificationStore = defineStore('Notification', () => {
refreshNotifications();
}
/**
*
*/
function testNotification() {
playNoty({
type: 'Event',
@@ -1169,6 +1172,10 @@ export const useNotificationStore = defineStore('Notification', () => {
});
}
/**
*
* @param row
*/
function acceptFriendRequestNotification(row) {
modalStore
.confirm({
@@ -1193,6 +1200,10 @@ export const useNotificationStore = defineStore('Notification', () => {
.catch(() => {});
}
/**
*
* @param row
*/
async function hideNotification(row) {
if (row.type === 'ignoredFriendRequest') {
await friendRequest.deleteHiddenFriendRequest(
@@ -1211,6 +1222,10 @@ export const useNotificationStore = defineStore('Notification', () => {
}
}
/**
*
* @param row
*/
function hideNotificationPrompt(row) {
modalStore
.confirm({
@@ -1223,6 +1238,10 @@ export const useNotificationStore = defineStore('Notification', () => {
.catch(() => {});
}
/**
*
* @param row
*/
function acceptRequestInvite(row) {
modalStore
.confirm({
@@ -1268,6 +1287,12 @@ export const useNotificationStore = defineStore('Notification', () => {
.catch(() => {});
}
/**
*
* @param notificationId
* @param responses
* @param responseType
*/
function sendNotificationResponse(notificationId, responses, responseType) {
if (!Array.isArray(responses) || responses.length === 0) return;
let responseData = '';
@@ -1295,6 +1320,10 @@ export const useNotificationStore = defineStore('Notification', () => {
});
}
/**
*
* @param row
*/
function deleteNotificationLog(row) {
const idx = notificationTable.value.data.findIndex(
(e) => e.id === row.id
@@ -1314,6 +1343,10 @@ export const useNotificationStore = defineStore('Notification', () => {
}
}
/**
*
* @param row
*/
function deleteNotificationLogPrompt(row) {
modalStore
.confirm({
@@ -1327,6 +1360,10 @@ export const useNotificationStore = defineStore('Notification', () => {
.catch(() => {});
}
/**
*
* @param notification
*/
function isNotificationExpired(notification) {
if (notification.$isExpired !== undefined) {
return notification.$isExpired;
@@ -1338,6 +1375,10 @@ export const useNotificationStore = defineStore('Notification', () => {
return expiresAt.isValid() && dayjs().isSameOrAfter(expiresAt);
}
/**
*
* @param link
*/
function openNotificationLink(link) {
if (!link) {
return;
+133 -51
View File
@@ -20,8 +20,8 @@ import {
getThemeMode,
updateTrustColorClasses
} from '../../shared/utils/base/ui';
import { computeTrustLevel, getNameColour } from '../../shared/utils';
import { database } from '../../service/database';
import { getNameColour } from '../../shared/utils';
import { languageCodes } from '../../localization';
import { loadLocalizedStrings } from '../../plugin';
import { useFeedStore } from '../feed';
@@ -127,6 +127,9 @@ export const useAppearanceSettingsStore = defineStore(
: fallback;
};
/**
*
*/
async function initAppearanceSettings() {
const { initThemeMode, isDarkMode: initDarkMode } =
await getThemeMode(configRepository);
@@ -410,6 +413,10 @@ export const useAppearanceSettingsStore = defineStore(
updateTrustColorClasses(trustColor.value);
}
/**
*
* @param customFunc
*/
async function userColourInit(customFunc) {
let dictObject = null;
if (typeof customFunc === 'function') {
@@ -440,55 +447,13 @@ export const useAppearanceSettingsStore = defineStore(
* @param {object} ref
*/
function applyUserTrustLevel(ref) {
ref.$isModerator =
ref.developerType && ref.developerType !== 'none';
ref.$isTroll = false;
ref.$isProbableTroll = false;
let trustColorTemp = '';
const { tags } = ref;
if (tags.includes('admin_moderator')) {
ref.$isModerator = true;
}
if (tags.includes('system_troll')) {
ref.$isTroll = true;
}
if (tags.includes('system_probable_troll') && !ref.$isTroll) {
ref.$isProbableTroll = true;
}
if (tags.includes('system_trust_veteran')) {
ref.$trustLevel = 'Trusted User';
ref.$trustClass = 'x-tag-veteran';
trustColorTemp = 'veteran';
ref.$trustSortNum = 5;
} else if (tags.includes('system_trust_trusted')) {
ref.$trustLevel = 'Known User';
ref.$trustClass = 'x-tag-trusted';
trustColorTemp = 'trusted';
ref.$trustSortNum = 4;
} else if (tags.includes('system_trust_known')) {
ref.$trustLevel = 'User';
ref.$trustClass = 'x-tag-known';
trustColorTemp = 'known';
ref.$trustSortNum = 3;
} else if (tags.includes('system_trust_basic')) {
ref.$trustLevel = 'New User';
ref.$trustClass = 'x-tag-basic';
trustColorTemp = 'basic';
ref.$trustSortNum = 2;
} else {
ref.$trustLevel = 'Visitor';
ref.$trustClass = 'x-tag-untrusted';
trustColorTemp = 'untrusted';
ref.$trustSortNum = 1;
}
if (ref.$isTroll || ref.$isProbableTroll) {
trustColorTemp = 'troll';
ref.$trustSortNum += 0.1;
}
if (ref.$isModerator) {
trustColorTemp = 'vip';
ref.$trustSortNum += 0.3;
}
const trust = computeTrustLevel(ref.tags, ref.developerType);
ref.$isModerator = trust.isModerator;
ref.$isTroll = trust.isTroll;
ref.$isProbableTroll = trust.isProbableTroll;
ref.$trustLevel = trust.trustLevel;
ref.$trustClass = trust.trustClass;
ref.$trustSortNum = trust.trustSortNum;
if (randomUserColours.value && watchState.isFriendsLoaded) {
if (!ref.$userColour) {
getNameColour(ref.id).then((colour) => {
@@ -496,7 +461,7 @@ export const useAppearanceSettingsStore = defineStore(
});
}
} else {
ref.$userColour = trustColor.value[trustColorTemp];
ref.$userColour = trustColor.value[trust.trustColorKey];
}
}
@@ -525,6 +490,9 @@ export const useAppearanceSettingsStore = defineStore(
updateTrustColor(undefined, undefined);
}
/**
*
*/
function toggleThemeMode() {
const nextMode = isDarkMode.value
? 'light'
@@ -532,12 +500,20 @@ export const useAppearanceSettingsStore = defineStore(
setThemeMode(nextMode);
}
/**
*
* @param value
*/
function normalizeAppFontFamily(value) {
return APP_FONT_FAMILIES.includes(value)
? value
: APP_FONT_DEFAULT_KEY;
}
/**
*
* @param value
*/
function setAppFontFamily(value) {
const normalized = normalizeAppFontFamily(value);
appFontFamily.value = normalized;
@@ -545,6 +521,9 @@ export const useAppearanceSettingsStore = defineStore(
applyAppFontFamily(normalized);
}
/**
*
*/
function setDisplayVRCPlusIconsAsAvatar() {
displayVRCPlusIconsAsAvatar.value =
!displayVRCPlusIconsAsAvatar.value;
@@ -553,6 +532,9 @@ export const useAppearanceSettingsStore = defineStore(
displayVRCPlusIconsAsAvatar.value
);
}
/**
*
*/
function setNotificationIconDot() {
notificationIconDot.value = !notificationIconDot.value;
configRepository.setBool(
@@ -561,10 +543,16 @@ export const useAppearanceSettingsStore = defineStore(
);
uiStore.updateTrayIconNotify();
}
/**
*
*/
function setHideNicknames() {
hideNicknames.value = !hideNicknames.value;
configRepository.setBool('VRCX_hideNicknames', hideNicknames.value);
}
/**
*
*/
function setShowInstanceIdInLocation() {
showInstanceIdInLocation.value = !showInstanceIdInLocation.value;
configRepository.setBool(
@@ -572,6 +560,9 @@ export const useAppearanceSettingsStore = defineStore(
showInstanceIdInLocation.value
);
}
/**
*
*/
function setIsAgeGatedInstancesVisible() {
isAgeGatedInstancesVisible.value =
!isAgeGatedInstancesVisible.value;
@@ -580,10 +571,16 @@ export const useAppearanceSettingsStore = defineStore(
isAgeGatedInstancesVisible.value
);
}
/**
*
*/
function setSortFavorites() {
sortFavorites.value = !sortFavorites.value;
configRepository.setBool('VRCX_sortFavorites', sortFavorites.value);
}
/**
*
*/
function setInstanceUsersSortAlphabetical() {
instanceUsersSortAlphabetical.value =
!instanceUsersSortAlphabetical.value;
@@ -593,6 +590,10 @@ export const useAppearanceSettingsStore = defineStore(
);
}
/**
*
* @param size
*/
function setTablePageSize(size) {
const processedSize = clampInt(size, 1, MAX_TABLE_PAGE_SIZE);
tablePageSize.value = processedSize;
@@ -601,6 +602,10 @@ export const useAppearanceSettingsStore = defineStore(
return processedSize;
}
/**
*
* @param input
*/
function normalizeTablePageSizes(input) {
const values = (
Array.isArray(input) ? input : DEFAULT_TABLE_PAGE_SIZES
@@ -629,10 +634,16 @@ export const useAppearanceSettingsStore = defineStore(
setTablePageSize(tablePageSizes.value[0]);
}
}
/**
*
*/
function setDtHour12() {
dtHour12.value = !dtHour12.value;
configRepository.setBool('VRCX_dtHour12', dtHour12.value);
}
/**
*
*/
function setDtIsoFormat() {
dtIsoFormat.value = !dtIsoFormat.value;
configRepository.setBool('VRCX_dtIsoFormat', dtIsoFormat.value);
@@ -668,13 +679,24 @@ export const useAppearanceSettingsStore = defineStore(
JSON.stringify(methods)
);
}
/**
*
* @param collapsed
*/
function setNavCollapsed(collapsed) {
isNavCollapsed.value = collapsed;
configRepository.setBool('VRCX_navIsCollapsed', collapsed);
}
/**
*
*/
function toggleNavCollapsed() {
setNavCollapsed(!isNavCollapsed.value);
}
/**
*
* @param widthOrArray
*/
function setNavWidth(widthOrArray) {
let width = null;
if (Array.isArray(widthOrArray) && widthOrArray.length) {
@@ -692,6 +714,9 @@ export const useAppearanceSettingsStore = defineStore(
});
}
}
/**
*
*/
function setIsSidebarGroupByInstance() {
isSidebarGroupByInstance.value = !isSidebarGroupByInstance.value;
configRepository.setBool(
@@ -699,6 +724,9 @@ export const useAppearanceSettingsStore = defineStore(
isSidebarGroupByInstance.value
);
}
/**
*
*/
function setIsHideFriendsInSameInstance() {
isHideFriendsInSameInstance.value =
!isHideFriendsInSameInstance.value;
@@ -707,6 +735,9 @@ export const useAppearanceSettingsStore = defineStore(
isHideFriendsInSameInstance.value
);
}
/**
*
*/
function setIsSidebarDivideByFriendGroup() {
isSidebarDivideByFriendGroup.value =
!isSidebarDivideByFriendGroup.value;
@@ -735,18 +766,30 @@ export const useAppearanceSettingsStore = defineStore(
JSON.stringify(value)
);
}
/**
*
*/
function setHideUserNotes() {
hideUserNotes.value = !hideUserNotes.value;
configRepository.setBool('VRCX_hideUserNotes', hideUserNotes.value);
}
/**
*
*/
function setHideUserMemos() {
hideUserMemos.value = !hideUserMemos.value;
configRepository.setBool('VRCX_hideUserMemos', hideUserMemos.value);
}
/**
*
*/
function setHideUnfriends() {
hideUnfriends.value = !hideUnfriends.value;
configRepository.setBool('VRCX_hideUnfriends', hideUnfriends.value);
}
/**
*
*/
function setRandomUserColours() {
randomUserColours.value = !randomUserColours.value;
configRepository.setBool(
@@ -754,6 +797,10 @@ export const useAppearanceSettingsStore = defineStore(
randomUserColours.value
);
}
/**
*
* @param value
*/
function normalizeTableDensity(value) {
if (
value === 'compact' ||
@@ -765,6 +812,10 @@ export const useAppearanceSettingsStore = defineStore(
return 'standard';
}
/**
*
* @param density
*/
function setTableDensity(density) {
const normalized = normalizeTableDensity(density);
tableDensity.value = normalized;
@@ -772,6 +823,9 @@ export const useAppearanceSettingsStore = defineStore(
configRepository.setString('VRCX_tableDensity', tableDensity.value);
}
/**
*
*/
function toggleStripedDataTable() {
isDataTableStriped.value = !isDataTableStriped.value;
configRepository.setBool(
@@ -781,6 +835,9 @@ export const useAppearanceSettingsStore = defineStore(
}
// FIXME: this is nasty, there should be a better way of doing this
/**
*
*/
function applyPointerHoverClass() {
const classList = document.documentElement.classList;
classList.remove('force-pointer-on-hover');
@@ -790,6 +847,9 @@ export const useAppearanceSettingsStore = defineStore(
}
}
/**
*
*/
function togglePointerOnHover() {
showPointerOnHover.value = !showPointerOnHover.value;
configRepository.setBool(
@@ -811,6 +871,9 @@ export const useAppearanceSettingsStore = defineStore(
);
}
/**
*
*/
function handleSaveSidebarSortOrder() {
if (sidebarSortMethod1.value === sidebarSortMethod2.value) {
sidebarSortMethod2.value = '';
@@ -835,6 +898,9 @@ export const useAppearanceSettingsStore = defineStore(
setSidebarSortMethods(sidebarSortMethods);
}
/**
*
*/
async function mergeOldSortMethodsSettings() {
const orderFriendsGroupPrivate = await configRepository.getBool(
'orderFriendGroupPrivate'
@@ -897,6 +963,9 @@ export const useAppearanceSettingsStore = defineStore(
return n;
};
/**
*
*/
function showTableLimitsDialog() {
tableLimitsDialog.value.maxTableSize = Number(
vrcxStore.maxTableSize ?? 500
@@ -907,10 +976,16 @@ export const useAppearanceSettingsStore = defineStore(
tableLimitsDialog.value.visible = true;
}
/**
*
*/
function closeTableLimitsDialog() {
tableLimitsDialog.value.visible = false;
}
/**
*
*/
async function saveTableLimitsDialog() {
const nextMaxTableSize = clampLimit(
tableLimitsDialog.value.maxTableSize,
@@ -949,6 +1024,9 @@ export const useAppearanceSettingsStore = defineStore(
tableLimitsDialog.value.visible = false;
}
/**
*
*/
async function tryInitUserColours() {
if (!randomUserColours.value) {
return;
@@ -958,6 +1036,10 @@ export const useAppearanceSettingsStore = defineStore(
await userColourInit();
}
/**
*
* @param density
*/
function applyTableDensity(density) {
const classList = document.documentElement.classList;
classList.remove('is-compact-table', 'is-comfortable-table');
+71 -113
View File
@@ -9,6 +9,12 @@ import {
isRpcWorld,
parseLocation
} from '../../shared/utils';
import {
getPlatformLabel,
getRpcWorldConfig,
getStatusInfo,
isPopcornPalaceWorld
} from '../../shared/utils/discordPresence';
import {
ActivityType,
StatusDisplayType
@@ -59,14 +65,23 @@ export const useDiscordPresenceSettingsStore = defineStore(
const discordWorldIntegration = ref(true);
const discordWorldNameAsDiscordStatus = ref(false);
/**
*
*/
function setDiscordActive() {
discordActive.value = !discordActive.value;
configRepository.setBool('discordActive', discordActive.value);
}
/**
*
*/
function setDiscordInstance() {
discordInstance.value = !discordInstance.value;
configRepository.setBool('discordInstance', discordInstance.value);
}
/**
*
*/
function setDiscordHideInvite() {
discordHideInvite.value = !discordHideInvite.value;
configRepository.setBool(
@@ -74,6 +89,9 @@ export const useDiscordPresenceSettingsStore = defineStore(
discordHideInvite.value
);
}
/**
*
*/
function setDiscordJoinButton() {
discordJoinButton.value = !discordJoinButton.value;
configRepository.setBool(
@@ -81,6 +99,9 @@ export const useDiscordPresenceSettingsStore = defineStore(
discordJoinButton.value
);
}
/**
*
*/
function setDiscordHideImage() {
discordHideImage.value = !discordHideImage.value;
configRepository.setBool(
@@ -88,6 +109,9 @@ export const useDiscordPresenceSettingsStore = defineStore(
discordHideImage.value
);
}
/**
*
*/
function setDiscordShowPlatform() {
discordShowPlatform.value = !discordShowPlatform.value;
configRepository.setBool(
@@ -95,6 +119,9 @@ export const useDiscordPresenceSettingsStore = defineStore(
discordShowPlatform.value
);
}
/**
*
*/
function setDiscordWorldIntegration() {
discordWorldIntegration.value = !discordWorldIntegration.value;
configRepository.setBool(
@@ -102,6 +129,9 @@ export const useDiscordPresenceSettingsStore = defineStore(
discordWorldIntegration.value
);
}
/**
*
*/
function setDiscordWorldNameAsDiscordStatus() {
discordWorldNameAsDiscordStatus.value =
!discordWorldNameAsDiscordStatus.value;
@@ -111,6 +141,9 @@ export const useDiscordPresenceSettingsStore = defineStore(
);
}
/**
*
*/
async function initDiscordPresenceSettings() {
const [
discordActiveConfig,
@@ -148,6 +181,9 @@ export const useDiscordPresenceSettingsStore = defineStore(
initDiscordPresenceSettings();
/**
*
*/
async function updateDiscord() {
let currentLocation = locationStore.lastLocation.location;
let startTime = locationStore.lastLocation.date;
@@ -204,27 +240,12 @@ export const useDiscordPresenceSettingsStore = defineStore(
let platform = '';
if (discordShowPlatform.value) {
if (gameStore.isGameRunning) {
platform = gameStore.isGameNoVR
? ` (${t('view.settings.discord_presence.rpc.desktop')})`
: ` (${t('view.settings.discord_presence.rpc.vr')})`;
} else {
switch (userStore.currentUser.presence.platform) {
case 'web':
break;
case 'standalonewindows':
platform = ` (PC)`;
break;
case 'android':
platform = ` (Android)`;
break;
case 'ios':
platform = ` (iOS)`;
break;
default:
platform = ` (${userStore.currentUser.presence.platform})`;
}
}
platform = getPlatformLabel(
userStore.currentUser.presence.platform,
gameStore.isGameRunning,
gameStore.isGameNoVR,
t
);
}
state.lastLocationDetails.groupAccessType = L.groupAccessType;
if (L.groupAccessType) {
@@ -281,34 +302,14 @@ export const useDiscordPresenceSettingsStore = defineStore(
) {
hidePrivate = true;
}
let statusName = '';
let statusImage = '';
switch (userStore.currentUser.status) {
case 'active':
statusName = t('dialog.user.status.active');
statusImage = 'active';
break;
case 'join me':
statusName = t('dialog.user.status.join_me');
statusImage = 'joinme';
break;
case 'ask me':
statusName = t('dialog.user.status.ask_me');
statusImage = 'askme';
if (discordHideInvite.value) {
hidePrivate = true;
}
break;
case 'busy':
statusName = t('dialog.user.status.busy');
statusImage = 'busy';
hidePrivate = true;
break;
default:
statusName = t('dialog.user.status.offline');
statusImage = 'offline';
hidePrivate = true;
break;
const statusInfo = getStatusInfo(
userStore.currentUser.status,
discordHideInvite.value,
t
);
const { statusName, statusImage } = statusInfo;
if (statusInfo.hidePrivate) {
hidePrivate = true;
}
let details = state.lastLocationDetails.worldName;
let stateText = state.lastLocationDetails.accessName;
@@ -345,74 +346,23 @@ export const useDiscordPresenceSettingsStore = defineStore(
buttonUrl = '';
}
if (
const rpcConfig =
isRpcWorld(state.lastLocationDetails.tag) &&
discordWorldIntegration.value
) {
// custom world rpc
? getRpcWorldConfig(state.lastLocationDetails.worldId)
: null;
if (rpcConfig) {
activityType = rpcConfig.activityType;
statusDisplayType = rpcConfig.statusDisplayType;
appId = rpcConfig.appId;
bigIcon = rpcConfig.bigIcon;
if (
state.lastLocationDetails.worldId ===
'wrld_f20326da-f1ac-45fc-a062-609723b097b1' ||
state.lastLocationDetails.worldId ===
'wrld_10e5e467-fc65-42ed-8957-f02cace1398c' ||
state.lastLocationDetails.worldId ===
'wrld_04899f23-e182-4a8d-b2c7-2c74c7c15534'
isPopcornPalaceWorld(state.lastLocationDetails.worldId) &&
!discordHideImage.value &&
gameLogStore.nowPlaying.thumbnailUrl
) {
activityType = ActivityType.Listening;
statusDisplayType = StatusDisplayType.Details;
appId = '784094509008551956';
bigIcon = 'pypy';
} else if (
state.lastLocationDetails.worldId ===
'wrld_42377cf1-c54f-45ed-8996-5875b0573a83' ||
state.lastLocationDetails.worldId ===
'wrld_dd6d2888-dbdc-47c2-bc98-3d631b2acd7c'
) {
activityType = ActivityType.Listening;
statusDisplayType = StatusDisplayType.Details;
appId = '846232616054030376';
bigIcon = 'vr_dancing';
} else if (
state.lastLocationDetails.worldId ===
'wrld_52bdcdab-11cd-4325-9655-0fb120846945' ||
state.lastLocationDetails.worldId ===
'wrld_2d40da63-8f1f-4011-8a9e-414eb8530acd'
) {
activityType = ActivityType.Listening;
statusDisplayType = StatusDisplayType.Details;
appId = '939473404808007731';
bigIcon = 'zuwa_zuwa_dance';
} else if (
state.lastLocationDetails.worldId ===
'wrld_74970324-58e8-4239-a17b-2c59dfdf00db' ||
state.lastLocationDetails.worldId ===
'wrld_db9d878f-6e76-4776-8bf2-15bcdd7fc445' ||
state.lastLocationDetails.worldId ===
'wrld_435bbf25-f34f-4b8b-82c6-cd809057eb8e' ||
state.lastLocationDetails.worldId ===
'wrld_f767d1c8-b249-4ecc-a56f-614e433682c8'
) {
activityType = ActivityType.Watching;
statusDisplayType = StatusDisplayType.Details;
appId = '968292722391785512';
bigIcon = 'ls_media';
} else if (
state.lastLocationDetails.worldId ===
'wrld_266523e8-9161-40da-acd0-6bd82e075833' ||
state.lastLocationDetails.worldId ===
'wrld_27c7e6b2-d938-447e-a270-3d1a873e2cf3'
) {
activityType = ActivityType.Watching;
statusDisplayType = StatusDisplayType.Details;
appId = '1095440531821170820';
if (
!discordHideImage.value &&
gameLogStore.nowPlaying.thumbnailUrl
) {
bigIcon = gameLogStore.nowPlaying.thumbnailUrl;
} else {
bigIcon = 'popcorn_palace';
}
bigIcon = gameLogStore.nowPlaying.thumbnailUrl;
}
if (gameLogStore.nowPlaying.name) {
details = gameLogStore.nowPlaying.name;
@@ -476,12 +426,20 @@ export const useDiscordPresenceSettingsStore = defineStore(
);
}
/**
*
* @param active
*/
async function setIsDiscordActive(active) {
if (active !== state.isDiscordActive) {
state.isDiscordActive = await Discord.SetActive(active);
}
}
/**
*
* @param configLabel
*/
async function saveDiscordOption(configLabel = '') {
state.lastLocationDetails.tag = '';
updateLoopStore.nextDiscordUpdate = 3;
+71 -176
View File
@@ -12,6 +12,10 @@ import {
compareByLocationAt,
compareByName,
compareByUpdatedAt,
computeUserPlatform,
createDefaultUserRef,
diffObjectProps,
evictMapCache,
extractFileId,
findUserByDisplayName,
getAllUserMemos,
@@ -20,8 +24,8 @@ import {
getWorldName,
isRealInstance,
parseLocation,
removeEmojis,
replaceBioSymbols
replaceBioSymbols,
sanitizeUserJson
} from '../shared/utils';
import {
avatarRequest,
@@ -29,10 +33,10 @@ import {
instanceRequest,
userRequest
} from '../api';
import { patchUserFromEvent } from '../query';
import { processBulk, request } from '../service/request';
import { AppDebug } from '../service/appConfig';
import { database } from '../service/database';
import { patchUserFromEvent } from '../query';
import { useAppearanceSettingsStore } from './settings/appearance';
import { useAuthStore } from './auth';
import { useAvatarStore } from './avatar';
@@ -344,6 +348,10 @@ export const useUserStore = defineStore('User', () => {
{ flush: 'sync' }
);
/**
*
* @param args
*/
function handleConfig(args) {
const authStore = useAuthStore();
const ref = {
@@ -419,143 +427,18 @@ export const useUserStore = defineStore('User', () => {
}
const robotUrl = `${AppDebug.endpointDomain}/file/file_0e8c4e32-7444-44ea-ade4-313c010d4bae/1/file`;
/**
*
* @param {Map<string, any>} userCache
* @param {Map<string, any>} friendMap
*/
function cleanupUserCache(userCache, friendMap) {
const bufferSize = 300;
const currentFriendCount = friendMap.size;
const currentTotalSize = userCache.size;
const effectiveMaxSize = currentFriendCount + bufferSize;
if (currentTotalSize <= effectiveMaxSize) {
return;
}
const targetDeleteCount = currentTotalSize - effectiveMaxSize;
let deletedCount = 0;
const keysToDelete = [];
for (const userId of userCache.keys()) {
if (friendMap.has(userId)) {
continue;
}
if (deletedCount >= targetDeleteCount) {
break;
}
keysToDelete.push(userId);
deletedCount++;
}
for (const id of keysToDelete) {
userCache.delete(id);
}
console.log(
`User cache cleanup: Deleted ${deletedCount}. Current cache size: ${userCache.size}`
);
}
/**
*
* @param {import('../types/api/user').GetUserResponse} json
* @returns {import('../types/api/user').VrcxUser}
*/
function applyUser(json) {
let hasPropChanged = false;
const changedProps = {};
let ref = cachedUsers.get(json.id);
if (json.statusDescription) {
json.statusDescription = replaceBioSymbols(json.statusDescription);
json.statusDescription = removeEmojis(json.statusDescription);
}
if (json.bio) {
json.bio = replaceBioSymbols(json.bio);
}
if (json.note) {
json.note = replaceBioSymbols(json.note);
}
if (json.currentAvatarImageUrl === robotUrl) {
delete json.currentAvatarImageUrl;
delete json.currentAvatarThumbnailImageUrl;
}
let hasPropChanged = false;
let changedProps = {};
sanitizeUserJson(json, robotUrl);
if (typeof ref === 'undefined') {
ref = reactive({
ageVerificationStatus: '',
ageVerified: false,
allowAvatarCopying: false,
badges: [],
bio: '',
bioLinks: [],
currentAvatarImageUrl: '',
currentAvatarTags: [],
currentAvatarThumbnailImageUrl: '',
date_joined: '',
developerType: '',
discordId: '',
displayName: '',
friendKey: '',
friendRequestStatus: '',
id: '',
instanceId: '',
isFriend: false,
last_activity: '',
last_login: '',
last_mobile: null,
last_platform: '',
location: '',
platform: '',
note: null,
profilePicOverride: '',
profilePicOverrideThumbnail: '',
pronouns: '',
state: '',
status: '',
statusDescription: '',
tags: [],
travelingToInstance: '',
travelingToLocation: '',
travelingToWorld: '',
userIcon: '',
worldId: '',
// only in bulk request
fallbackAvatar: '',
// VRCX
$location: {},
$location_at: Date.now(),
$online_for: Date.now(),
$travelingToTime: Date.now(),
$offline_for: null,
$active_for: Date.now(),
$isVRCPlus: false,
$isModerator: false,
$isTroll: false,
$isProbableTroll: false,
$trustLevel: 'Visitor',
$trustClass: 'x-tag-untrusted',
$userColour: '',
$trustSortNum: 1,
$languages: [],
$joinCount: 0,
$timeSpent: 0,
$lastSeen: '',
$mutualCount: 0,
$nickName: '',
$previousLocation: '',
$customTag: '',
$customTagColour: '',
$friendNumber: 0,
$platform: '',
$moderations: {},
//
...json
});
ref = reactive(createDefaultUserRef(json));
if (locationStore.lastLocation.playerList.has(json.id)) {
// update $location_at from instance join time
const player = locationStore.lastLocation.playerList.get(
@@ -581,7 +464,12 @@ export const useUserStore = defineStore('User', () => {
ref.$customTag = '';
ref.$customTagColour = '';
}
cleanupUserCache(cachedUsers, friendStore.friends);
evictMapCache(
cachedUsers,
friendStore.friends.size + 300,
(_value, key) => friendStore.friends.has(key),
{ logLabel: 'User cache cleanup' }
);
cachedUsers.set(ref.id, ref);
friendStore.updateFriend(ref.id);
} else {
@@ -589,59 +477,23 @@ export const useUserStore = defineStore('User', () => {
// offline event before GPS to offline location
friendStore.updateFriend(ref.id, json.state);
}
for (const prop in ref) {
if (typeof json[prop] === 'undefined') {
continue;
}
// Only compare primitive values
if (ref[prop] === null || typeof ref[prop] !== 'object') {
changedProps[prop] = true;
}
}
for (const prop in json) {
if (typeof ref[prop] === 'undefined') {
continue;
}
if (Array.isArray(json[prop]) && Array.isArray(ref[prop])) {
if (!arraysMatch(json[prop], ref[prop])) {
changedProps[prop] = true;
}
} else if (
json[prop] === null ||
typeof json[prop] !== 'object'
) {
changedProps[prop] = true;
}
}
for (const prop in changedProps) {
const asIs = ref[prop];
const toBe = json[prop];
if (asIs === toBe) {
delete changedProps[prop];
} else {
hasPropChanged = true;
changedProps[prop] = [toBe, asIs];
}
}
const {
hasPropChanged: _hasPropChanged,
changedProps: _changedProps
} = diffObjectProps(ref, json, arraysMatch);
for (const prop in json) {
if (typeof json[prop] !== 'undefined') {
ref[prop] = json[prop];
}
}
hasPropChanged = _hasPropChanged;
changedProps = _changedProps;
}
ref.$moderations = moderationStore.getUserModerations(ref.id);
ref.$isVRCPlus = ref.tags.includes('system_supporter');
appearanceSettingsStore.applyUserTrustLevel(ref);
applyUserLanguage(ref);
if (
ref.platform &&
ref.platform !== 'offline' &&
ref.platform !== 'web'
) {
ref.$platform = ref.platform;
} else {
ref.$platform = ref.last_platform;
}
ref.$platform = computeUserPlatform(ref.platform, ref.last_platform);
// traveling
if (ref.location === 'traveling') {
ref.$location = parseLocation(ref.travelingToLocation);
@@ -1180,6 +1032,10 @@ export const useUserStore = defineStore('User', () => {
D.instance.friendCount = friendCount;
}
/**
*
* @param array
*/
function sortUserDialogAvatars(array) {
const D = userDialog.value;
if (D.avatarSorting === 'update') {
@@ -1192,6 +1048,10 @@ export const useUserStore = defineStore('User', () => {
D.avatars = array;
}
/**
*
* @param fileId
*/
async function refreshUserDialogAvatars(fileId) {
const D = userDialog.value;
const userId = D.id;
@@ -1248,6 +1108,10 @@ export const useUserStore = defineStore('User', () => {
});
}
/**
*
* @param ref
*/
async function lookupUser(ref) {
let ctx;
if (ref.userId) {
@@ -1577,6 +1441,9 @@ export const useUserStore = defineStore('User', () => {
}
}
/**
*
*/
function updateAutoStateChange() {
if (
!generalSettingsStore.autoStateChangeEnabled ||
@@ -1683,6 +1550,10 @@ export const useUserStore = defineStore('User', () => {
});
}
/**
*
* @param data
*/
function addCustomTag(data) {
if (data.Tag) {
customUserTags.set(data.UserId, {
@@ -1708,6 +1579,9 @@ export const useUserStore = defineStore('User', () => {
sharedFeedStore.addTag(data.UserId, data.TagColour);
}
/**
*
*/
async function initUserNotes() {
state.lastNoteCheck = new Date();
state.lastDbNoteDate = null;
@@ -1735,6 +1609,9 @@ export const useUserStore = defineStore('User', () => {
}
}
/**
*
*/
async function getLatestUserNotes() {
state.lastNoteCheck = new Date();
const params = {
@@ -1793,6 +1670,11 @@ export const useUserStore = defineStore('User', () => {
}
}
/**
*
* @param userId
* @param newNote
*/
async function checkNote(userId, newNote) {
// last check was more than than 5 minutes ago
if (
@@ -1814,6 +1696,9 @@ export const useUserStore = defineStore('User', () => {
}
}
/**
*
*/
function getCurrentUser() {
return request('auth/user', {
method: 'GET'
@@ -2079,11 +1964,18 @@ export const useUserStore = defineStore('User', () => {
return ref;
}
/**
*
* @param userId
*/
function showSendBoopDialog(userId) {
sendBoopDialog.value.userId = userId;
sendBoopDialog.value.visible = true;
}
/**
*
*/
function toggleSharedConnectionsOptOut() {
userRequest.saveCurrentUser({
hasSharedConnectionsOptOut:
@@ -2091,6 +1983,9 @@ export const useUserStore = defineStore('User', () => {
});
}
/**
*
*/
function toggleDiscordFriendsOptOut() {
userRequest.saveCurrentUser({
hasDiscordFriendsOptOut: !currentUser.value.hasDiscordFriendsOptOut
+10 -64
View File
@@ -5,16 +5,18 @@ import { useI18n } from 'vue-i18n';
import {
checkVRChatCache,
createDefaultWorldRef,
evictMapCache,
getAvailablePlatforms,
getBundleDateSize,
getWorldMemo,
isRealInstance,
parseLocation,
replaceBioSymbols
sanitizeEntityJson
} from '../shared/utils';
import { instanceRequest, miscRequest, worldRequest } from '../api';
import { patchWorldFromEvent } from '../query';
import { database } from '../service/database';
import { patchWorldFromEvent } from '../query';
import { processBulk } from '../service/request';
import { useFavoriteStore } from './favorite';
import { useInstanceStore } from './instance';
@@ -76,6 +78,7 @@ export const useWorldStore = defineStore('World', () => {
*
* @param {string} tag
* @param {string} shortName
* @param options
*/
function showWorldDialog(tag, shortName = null, options = {}) {
const D = worldDialog;
@@ -204,7 +207,6 @@ export const useWorldStore = defineStore('World', () => {
args.json !== false;
}
});
}
});
}
@@ -235,20 +237,9 @@ export const useWorldStore = defineStore('World', () => {
* @param WorldCache
*/
function cleanupWorldCache(WorldCache) {
const maxCacheSize = 10000;
if (WorldCache.size <= maxCacheSize) {
return;
}
const deletedCount = WorldCache.size - maxCacheSize;
while (WorldCache.size > maxCacheSize) {
const deletedKey = WorldCache.keys().next().value;
WorldCache.delete(deletedKey);
}
console.log(
`World cache cleanup: Deleted ${deletedCount}. Current cache size: ${WorldCache.size}`
);
evictMapCache(WorldCache, 10000, () => false, {
logLabel: 'World cache cleanup'
});
}
/**
@@ -257,55 +248,10 @@ export const useWorldStore = defineStore('World', () => {
* @returns {object} ref
*/
function applyWorld(json) {
if (json.name) {
json.name = replaceBioSymbols(json.name);
}
if (json.description) {
json.description = replaceBioSymbols(json.description);
}
sanitizeEntityJson(json, ['name', 'description']);
let ref = cachedWorlds.get(json.id);
if (typeof ref === 'undefined') {
ref = {
id: '',
name: '',
description: '',
defaultContentSettings: {},
authorId: '',
authorName: '',
capacity: 0,
recommendedCapacity: 0,
tags: [],
releaseStatus: '',
imageUrl: '',
thumbnailImageUrl: '',
assetUrl: '',
assetUrlObject: {},
pluginUrl: '',
pluginUrlObject: {},
unityPackageUrl: '',
unityPackageUrlObject: {},
unityPackages: [],
version: 0,
favorites: 0,
created_at: '',
updated_at: '',
publicationDate: '',
labsPublicationDate: '',
visits: 0,
popularity: 0,
heat: 0,
publicOccupants: 0,
privateOccupants: 0,
occupants: 0,
instances: [],
featured: false,
organization: '',
previewYoutubeId: '',
// VRCX
$isLabs: false,
//
...json
};
ref = createDefaultWorldRef(json);
cleanupWorldCache(cachedWorlds);
cachedWorlds.set(ref.id, ref);
} else {