refactor store

This commit is contained in:
pa
2026-03-10 15:25:23 +09:00
parent d7220baaf6
commit 95c4a1d3e6
82 changed files with 3243 additions and 3066 deletions

View File

@@ -16,6 +16,7 @@ import { escapeTag } from '../shared/utils';
import { initWebsocket } from '../service/websocket';
import { request } from '../service/request';
import { runHandleAutoLoginFlow } from '../coordinators/authAutoLoginCoordinator';
import { getCurrentUser } from '../coordinators/userCoordinator';
import { useAdvancedSettingsStore } from './settings/advanced';
import { useGeneralSettingsStore } from './settings/general';
import { useModalStore } from './modal';
@@ -197,8 +198,7 @@ export const useAuthStore = defineStore('Auth', () => {
throw err;
})
.then(() => {
userStore
.getCurrentUser()
getCurrentUser()
.finally(() => {
loginForm.value.loading = false;
})
@@ -671,7 +671,7 @@ export const useAuthStore = defineStore('Auth', () => {
clearCookiesTryLogin();
})
.then(() => {
userStore.getCurrentUser();
getCurrentUser();
});
})
.catch(() => {
@@ -713,7 +713,7 @@ export const useAuthStore = defineStore('Auth', () => {
clearCookiesTryLogin();
})
.then(() => {
userStore.getCurrentUser();
getCurrentUser();
});
})
.catch(() => {
@@ -756,7 +756,7 @@ export const useAuthStore = defineStore('Auth', () => {
promptEmailOTP();
})
.then(() => {
userStore.getCurrentUser();
getCurrentUser();
});
})
.catch(() => {

View File

@@ -1,46 +1,13 @@
import { nextTick, ref, watch } from 'vue';
import { ref, watch } from 'vue';
import { defineStore } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
import {
checkVRChatCache,
createDefaultAvatarRef,
extractFileId,
getAvailablePlatforms,
getBundleDateSize,
getPlatformInfo,
replaceBioSymbols,
sanitizeEntityJson,
storeAvatarImage
checkVRChatCache
} from '../shared/utils';
import { avatarRequest, miscRequest, queryRequest } from '../api';
import { AppDebug } from '../service/appConfig';
import { database } from '../service/database';
import { patchAvatarFromEvent } from '../queries';
import { processBulk } from '../service/request';
import { applyFavorite } from '../coordinators/favoriteCoordinator';
import { useAdvancedSettingsStore } from './settings/advanced';
import { useAvatarProviderStore } from './avatarProvider';
import { useFavoriteStore } from './favorite';
import { useModalStore } from './modal';
import { useUiStore } from './ui';
import { useUserStore } from './user';
import { useVRCXUpdaterStore } from './vrcxUpdater';
import { watchState } from '../service/watchState';
import webApiService from '../service/webapi';
export const useAvatarStore = defineStore('Avatar', () => {
const favoriteStore = useFavoriteStore();
const avatarProviderStore = useAvatarProviderStore();
const vrcxUpdaterStore = useVRCXUpdaterStore();
const advancedSettingsStore = useAdvancedSettingsStore();
const userStore = useUserStore();
const modalStore = useModalStore();
const uiStore = useUiStore();
const { t } = useI18n();
let cachedAvatarModerations = new Map();
let cachedAvatars = new Map();
let cachedAvatarNames = new Map();
@@ -83,145 +50,17 @@ export const useAvatarStore = defineStore('Avatar', () => {
cachedAvatarModerations.clear();
avatarHistory.value = [];
if (isLoggedIn) {
getAvatarHistory();
preloadOwnAvatars();
import('../coordinators/avatarCoordinator').then(
({ getAvatarHistory, preloadOwnAvatars }) => {
getAvatarHistory();
preloadOwnAvatars();
}
);
}
},
{ flush: 'sync' }
);
/**
* @param {object} json
* @returns {object} ref
*/
function applyAvatar(json) {
sanitizeEntityJson(json, ['name', 'description']);
let ref = cachedAvatars.get(json.id);
if (typeof ref === 'undefined') {
ref = createDefaultAvatarRef(json);
cachedAvatars.set(ref.id, ref);
} else {
const { unityPackages } = ref;
Object.assign(ref, json);
if (
json.unityPackages?.length > 0 &&
unityPackages.length > 0 &&
!json.unityPackages[0].assetUrl
) {
ref.unityPackages = unityPackages;
}
}
for (const listing of ref.publishedListings) {
listing.displayName = replaceBioSymbols(listing.displayName);
listing.description = replaceBioSymbols(listing.description);
}
applyFavorite('avatar', ref.id);
if (favoriteStore.localAvatarFavoritesList.includes(ref.id)) {
const avatarRef = ref;
favoriteStore.syncLocalAvatarFavoriteRef(avatarRef);
// update db cache
database.addAvatarToCache(avatarRef);
}
patchAvatarFromEvent(ref);
return ref;
}
/**
*
* @param {string} avatarId
* @param options
* @returns
*/
function showAvatarDialog(avatarId, options = {}) {
const D = avatarDialog.value;
const forceRefresh = Boolean(options?.forceRefresh);
const isMainDialogOpen = uiStore.openDialog({
type: 'avatar',
id: avatarId
});
D.visible = true;
if (isMainDialogOpen && D.id === avatarId && !forceRefresh) {
uiStore.setDialogCrumbLabel('avatar', D.id, D.ref?.name || D.id);
nextTick(() => (D.loading = false));
return;
}
D.loading = true;
D.id = avatarId;
D.inCache = false;
D.cacheSize = '';
D.cacheLocked = false;
D.cachePath = '';
D.fileAnalysis = {};
D.isQuestFallback = false;
D.isPC = false;
D.isQuest = false;
D.isIos = false;
D.hasImposter = false;
D.imposterVersion = '';
D.platformInfo = {};
D.galleryImages = [];
D.galleryLoading = true;
D.isFavorite =
favoriteStore.getCachedFavoritesByObjectId(avatarId) ||
(userStore.isLocalUserVrcPlusSupporter &&
favoriteStore.localAvatarFavoritesList.includes(avatarId));
D.isBlocked = cachedAvatarModerations.has(avatarId);
const ref2 = cachedAvatars.get(avatarId);
if (typeof ref2 !== 'undefined') {
D.ref = ref2;
uiStore.setDialogCrumbLabel('avatar', D.id, D.ref?.name || D.id);
nextTick(() => (D.loading = false));
}
const loadAvatarRequest = forceRefresh
? avatarRequest.getAvatar({ avatarId })
: queryRequest.fetch('avatar', { avatarId });
loadAvatarRequest
.then((args) => {
const ref = applyAvatar(args.json);
D.ref = ref;
uiStore.setDialogCrumbLabel(
'avatar',
D.id,
D.ref?.name || D.id
);
getAvatarGallery(avatarId);
updateVRChatAvatarCache();
if (/quest/.test(ref.tags)) {
D.isQuestFallback = true;
}
const { isPC, isQuest, isIos } = getAvailablePlatforms(
ref.unityPackages
);
D.isPC = isPC;
D.isQuest = isQuest;
D.isIos = isIos;
D.platformInfo = getPlatformInfo(ref.unityPackages);
for (let i = ref.unityPackages.length - 1; i > -1; i--) {
const unityPackage = ref.unityPackages[i];
if (unityPackage.variant === 'impostor') {
D.hasImposter = true;
D.imposterVersion = unityPackage.impostorizerVersion;
break;
}
}
if (Object.keys(D.fileAnalysis).length === 0) {
getBundleDateSize(ref);
}
})
.catch((err) => {
D.loading = false;
D.id = null;
D.visible = false;
uiStore.jumpBackDialogCrumb();
toast.error(t('message.api_handler.avatar_private_or_deleted'));
throw err;
})
.finally(() => {
nextTick(() => (D.loading = false));
});
}
/**
* @param {boolean} value
*/
@@ -249,6 +88,7 @@ export const useAvatarStore = defineStore('Avatar', () => {
* @returns {Promise<string[]>}
*/
async function getAvatarGallery(avatarId) {
const { queryRequest } = await import('../api');
const D = avatarDialog.value;
const args = await queryRequest
.fetch('avatarGallery', { avatarId })
@@ -341,54 +181,6 @@ export const useAvatarStore = defineStore('Avatar', () => {
}
}
/**
*
* @returns {Promise<void>}
*/
async function getAvatarHistory() {
const historyArray = await database.getAvatarHistory(
userStore.currentUser.id
);
for (let i = 0; i < historyArray.length; i++) {
const avatar = historyArray[i];
if (avatar.authorId === userStore.currentUser.id) {
continue;
}
applyAvatar(avatar);
}
avatarHistory.value = historyArray;
}
/**
* @param {string} avatarId
*/
function addAvatarToHistory(avatarId) {
avatarRequest
.getAvatar({ avatarId })
.then((args) => {
const ref = applyAvatar(args.json);
database.addAvatarToCache(ref);
database.addAvatarToHistory(ref.id);
if (ref.authorId === userStore.currentUser.id) {
return;
}
const historyArray = avatarHistory.value;
for (let i = 0; i < historyArray.length; ++i) {
if (historyArray[i].id === ref.id) {
historyArray.splice(i, 1);
}
}
avatarHistory.value.unshift(ref);
})
.catch((err) => {
console.error('Failed to add avatar to history:', err);
});
}
/**
*
*/
@@ -397,423 +189,21 @@ export const useAvatarStore = defineStore('Avatar', () => {
database.clearAvatarHistory();
}
/**
*
*/
function promptClearAvatarHistory() {
modalStore
.confirm({
description: t('confirm.clear_avatar_history'),
title: 'Confirm'
})
.then(({ ok }) => {
if (!ok) return;
clearAvatarHistory();
})
.catch(() => {});
}
/**
*
* @param {string} imageUrl
* @returns {Promise<object>}
*/
async function getAvatarName(imageUrl) {
const fileId = extractFileId(imageUrl);
if (!fileId) {
return {
ownerId: '',
avatarName: '-'
};
}
if (cachedAvatarNames.has(fileId)) {
return cachedAvatarNames.get(fileId);
}
try {
const args = await miscRequest.getFile({ fileId });
return storeAvatarImage(args, cachedAvatarNames);
} catch (error) {
console.error('Failed to get avatar images:', error);
return {
ownerId: '',
avatarName: '-'
};
}
}
/**
*
* @param type
* @param search
*/
async function lookupAvatars(type, search) {
const avatars = new Map();
if (type === 'search') {
try {
const url = `${
avatarProviderStore.avatarRemoteDatabaseProvider
}?${type}=${encodeURIComponent(search)}&n=5000`;
const response = await webApiService.execute({
url,
method: 'GET',
headers: {
Referer: 'https://vrcx.app',
'VRCX-ID': vrcxUpdaterStore.vrcxId
}
});
const json = JSON.parse(response.data);
if (AppDebug.debugWebRequests) {
console.log(url, json, response);
}
if (response.status === 200 && typeof json === 'object') {
json.forEach((avatar) => {
if (!avatars.has(avatar.Id)) {
const ref = {
authorId: '',
authorName: '',
name: '',
description: '',
id: '',
imageUrl: '',
thumbnailImageUrl: '',
created_at: '0001-01-01T00:00:00.0000000Z',
updated_at: '0001-01-01T00:00:00.0000000Z',
releaseStatus: 'public',
...avatar
};
avatars.set(ref.id, ref);
}
});
} else {
throw new Error(`Error: ${response.data}`);
}
} catch (err) {
const msg = `Avatar search failed for ${search} with ${avatarProviderStore.avatarRemoteDatabaseProvider}\n${err}`;
console.error(msg);
toast.error(msg);
}
} else if (type === 'authorId') {
const length =
avatarProviderStore.avatarRemoteDatabaseProviderList.length;
for (let i = 0; i < length; ++i) {
const url =
avatarProviderStore.avatarRemoteDatabaseProviderList[i];
const avatarArray = await lookupAvatarsByAuthor(url, search);
avatarArray.forEach((avatar) => {
if (!avatars.has(avatar.id)) {
avatars.set(avatar.id, avatar);
}
});
}
}
return avatars;
}
/**
*
* @param authorId
* @param fileId
*/
async function lookupAvatarByImageFileId(authorId, fileId) {
for (const providerUrl of avatarProviderStore.avatarRemoteDatabaseProviderList) {
const avatar = await lookupAvatarByFileId(providerUrl, fileId);
if (avatar?.id) {
return avatar.id;
}
}
for (const providerUrl of avatarProviderStore.avatarRemoteDatabaseProviderList) {
const avatarArray = await lookupAvatarsByAuthor(
providerUrl,
authorId
);
for (const avatar of avatarArray) {
if (extractFileId(avatar.imageUrl) === fileId) {
return avatar.id;
}
}
}
return null;
}
/**
*
* @param providerUrl
* @param fileId
*/
async function lookupAvatarByFileId(providerUrl, fileId) {
try {
const url = `${providerUrl}?fileId=${encodeURIComponent(fileId)}`;
const response = await webApiService.execute({
url,
method: 'GET',
headers: {
Referer: 'https://vrcx.app',
'VRCX-ID': vrcxUpdaterStore.vrcxId
}
});
const json = JSON.parse(response.data);
if (AppDebug.debugWebRequests) {
console.log(url, json, response);
}
if (response.status === 200 && typeof json === 'object') {
const ref = {
authorId: '',
authorName: '',
name: '',
description: '',
id: '',
imageUrl: '',
thumbnailImageUrl: '',
created_at: '0001-01-01T00:00:00.0000000Z',
updated_at: '0001-01-01T00:00:00.0000000Z',
releaseStatus: 'public',
...json
};
return ref;
} else {
return null;
}
} catch (err) {
// ignore errors for now, not all providers support this lookup type
return null;
}
}
/**
*
* @param providerUrl
* @param authorId
*/
async function lookupAvatarsByAuthor(providerUrl, authorId) {
const avatars = [];
if (!providerUrl || !authorId) {
return avatars;
}
const url = `${providerUrl}?authorId=${encodeURIComponent(authorId)}`;
try {
const response = await webApiService.execute({
url,
method: 'GET',
headers: {
Referer: 'https://vrcx.app',
'VRCX-ID': vrcxUpdaterStore.vrcxId
}
});
const json = JSON.parse(response.data);
if (AppDebug.debugWebRequests) {
console.log(url, json, response);
}
if (response.status === 200 && typeof json === 'object') {
json.forEach((avatar) => {
const ref = {
authorId: '',
authorName: '',
name: '',
description: '',
id: '',
imageUrl: '',
thumbnailImageUrl: '',
created_at: '0001-01-01T00:00:00.0000000Z',
updated_at: '0001-01-01T00:00:00.0000000Z',
releaseStatus: 'public',
...avatar
};
avatars.push(ref);
});
} else {
throw new Error(`Error: ${response.data}`);
}
} catch (err) {
const msg = `Avatar lookup failed for ${authorId} with ${url}\n${err}`;
console.error(msg);
toast.error(msg);
}
return avatars;
}
/**
*
* @param id
*/
function selectAvatarWithConfirmation(id) {
modalStore
.confirm({
description: t('confirm.select_avatar'),
title: 'Confirm'
})
.then(({ ok }) => {
if (!ok) return;
selectAvatarWithoutConfirmation(id);
})
.catch(() => {});
}
/**
*
* @param id
*/
async function selectAvatarWithoutConfirmation(id) {
if (userStore.currentUser.currentAvatar === id) {
toast.info('Avatar already selected');
return;
}
return avatarRequest
.selectAvatar({
avatarId: id
})
.then(() => {
toast.success('Avatar changed');
});
}
/**
*
* @param fileId
*/
function checkAvatarCache(fileId) {
let avatarId = '';
for (let ref of cachedAvatars.values()) {
if (extractFileId(ref.imageUrl) === fileId) {
avatarId = ref.id;
}
}
return avatarId;
}
/**
*
* @param fileId
* @param ownerUserId
*/
async function checkAvatarCacheRemote(fileId, ownerUserId) {
if (advancedSettingsStore.avatarRemoteDatabase) {
try {
toast.dismiss(loadingToastId.value);
loadingToastId.value = toast.loading(
t('message.avatar_lookup.loading')
);
const avatarId = await lookupAvatarByImageFileId(
ownerUserId,
fileId
);
return avatarId;
} catch (err) {
console.error('Failed to lookup avatar by image file id:', err);
} finally {
toast.dismiss(loadingToastId.value);
}
}
return null;
}
/**
*
* @param refUserId
* @param ownerUserId
* @param currentAvatarImageUrl
*/
async function showAvatarAuthorDialog(
refUserId,
ownerUserId,
currentAvatarImageUrl
) {
const fileId = extractFileId(currentAvatarImageUrl);
if (!fileId) {
toast.error(t('message.avatar_lookup.failed'));
} else if (refUserId === userStore.currentUser.id) {
showAvatarDialog(userStore.currentUser.currentAvatar);
} else {
let avatarId = checkAvatarCache(fileId);
let avatarInfo;
if (!avatarId) {
avatarInfo = await getAvatarName(currentAvatarImageUrl);
if (avatarInfo.ownerId === userStore.currentUser.id) {
await userStore.refreshUserDialogAvatars(fileId);
return;
}
}
if (!avatarId) {
avatarId = await checkAvatarCacheRemote(fileId, ownerUserId);
}
if (!avatarId) {
if (ownerUserId === refUserId) {
toast.warning(
t('message.avatar_lookup.private_or_not_found')
);
} else {
toast.warning(t('message.avatar_lookup.not_found'));
userStore.showUserDialog(avatarInfo.ownerId);
}
}
if (avatarId) {
showAvatarDialog(avatarId);
}
}
}
/**
*
* @param avatarId
*/
function addAvatarWearTime(avatarId) {
if (!userStore.currentUser.$previousAvatarSwapTime || !avatarId) {
return;
}
const timeSpent =
Date.now() - userStore.currentUser.$previousAvatarSwapTime;
database.addAvatarTimeSpent(avatarId, timeSpent);
}
/**
* Preload all own avatars into cache at startup for global search.
*/
async function preloadOwnAvatars() {
const params = {
n: 50,
offset: 0,
sort: 'updated',
order: 'descending',
releaseStatus: 'all',
user: 'me'
};
await processBulk({
fn: avatarRequest.getAvatars,
N: -1,
params,
handle: (args) => {
for (const json of args.json) {
applyAvatar(json);
}
}
});
}
return {
avatarDialog,
avatarHistory,
loadingToastId,
cachedAvatarModerations,
cachedAvatars,
cachedAvatarNames,
showAvatarDialog,
applyAvatarModeration,
resetCachedAvatarModerations,
getAvatarGallery,
updateVRChatAvatarCache,
getAvatarHistory,
addAvatarToHistory,
applyAvatar,
promptClearAvatarHistory,
getAvatarName,
lookupAvatars,
selectAvatarWithConfirmation,
selectAvatarWithoutConfirmation,
clearAvatarHistory,
setAvatarDialogVisible,
setAvatarDialogIsFavorite,
setAvatarDialogLoading,
showAvatarAuthorDialog,
addAvatarWearTime,
preloadOwnAvatars
setAvatarDialogLoading
};
});

View File

@@ -25,6 +25,7 @@ import {
runPendingOfflineTickFlow,
runUpdateFriendFlow
} from '../coordinators/friendPresenceCoordinator';
import { applyUser } from '../coordinators/userCoordinator';
import { AppDebug } from '../service/appConfig';
import { database } from '../service/database';
import { useAppearanceSettingsStore } from './settings/appearance';
@@ -981,7 +982,7 @@ export const useFriendStore = defineStore('Friend', () => {
const sqlValues = [];
const friends = await refreshFriends();
for (const friend of friends) {
const ref = userStore.applyUser(friend);
const ref = applyUser(friend);
const row = {
userId: ref.id,
displayName: ref.displayName,

View File

@@ -13,6 +13,10 @@ import { useAvatarStore } from './avatar';
import { useFavoriteStore } from './favorite';
import { useFriendStore } from './friend';
import { useGroupStore } from './group';
import { showGroupDialog } from '../coordinators/groupCoordinator';
import { showWorldDialog } from '../coordinators/worldCoordinator';
import { showAvatarDialog } from '../coordinators/avatarCoordinator';
import { showUserDialog } from '../coordinators/userCoordinator';
import { useUserStore } from './user';
import { useWorldStore } from './world';
@@ -166,16 +170,16 @@ export const useGlobalSearchStore = defineStore('GlobalSearch', () => {
switch (item.type) {
case 'friend':
userStore.showUserDialog(item.id);
showUserDialog(item.id);
break;
case 'avatar':
avatarStore.showAvatarDialog(item.id);
showAvatarDialog(item.id);
break;
case 'world':
worldStore.showWorldDialog(item.id);
showWorldDialog(item.id);
break;
case 'group':
groupStore.showGroupDialog(item.id);
showGroupDialog(item.id);
break;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -44,6 +44,8 @@ import { useFriendStore } from '../friend';
import { useGameStore } from '../game';
import { useGeneralSettingsStore } from '../settings/general';
import { useGroupStore } from '../group';
import { showGroupDialog } from '../../coordinators/groupCoordinator';
import { showUserDialog } from '../../coordinators/userCoordinator';
import { useInstanceStore } from '../instance';
import { useLocationStore } from '../location';
import { useModalStore } from '../modal';
@@ -1415,10 +1417,10 @@ export const useNotificationStore = defineStore('Notification', () => {
}
switch (data[0]) {
case 'group':
groupStore.showGroupDialog(data[1]);
showGroupDialog(data[1]);
break;
case 'user':
userStore.showUserDialog(data[1]);
showUserDialog(data[1]);
break;
case 'event':
const ids = data[1].split(',');
@@ -1427,7 +1429,7 @@ export const useNotificationStore = defineStore('Notification', () => {
return;
}
groupStore.showGroupDialog(ids[0]);
showGroupDialog(ids[0]);
// ids[1] cal_ is the event id
break;
case 'openNotificationLink':

View File

@@ -20,6 +20,8 @@ import { photonEmojis, photonEventType } from '../shared/constants/photon';
import { AppDebug } from '../service/appConfig';
import { database } from '../service/database';
import { useAvatarStore } from './avatar';
import { applyAvatar } from '../coordinators/avatarCoordinator';
import { showUserDialog, lookupUser, applyUser } from '../coordinators/userCoordinator';
import { useFavoriteStore } from './favorite';
import { useFriendStore } from './friend';
import { useGameLogStore } from './gameLog';
@@ -424,9 +426,9 @@ export const usePhotonStore = defineStore('Photon', () => {
const ref = photonLobby.value.get(photonId);
if (typeof ref !== 'undefined') {
if (typeof ref.id !== 'undefined') {
userStore.showUserDialog(ref.id);
showUserDialog(ref.id);
} else if (typeof ref.displayName !== 'undefined') {
userStore.lookupUser(ref);
lookupUser(ref);
}
} else {
toast.error('No user info available');
@@ -1475,7 +1477,7 @@ export const usePhotonStore = defineStore('Photon', () => {
typeof ref.id !== 'undefined' &&
ref.currentAvatarImageUrl !== user.currentAvatarImageUrl
) {
userStore.applyUser({
applyUser({
...ref,
currentAvatarImageUrl: user.currentAvatarImageUrl,
currentAvatarThumbnailImageUrl:
@@ -1803,7 +1805,7 @@ export const usePhotonStore = defineStore('Photon', () => {
}
}
}
avatarStore.applyAvatar({
applyAvatar({
id: avatar.id,
authorId: avatar.authorId,
authorName: avatar.authorName,

View File

@@ -12,6 +12,10 @@ import { useAppearanceSettingsStore } from './settings/appearance';
import { useAvatarStore } from './avatar';
import { useFriendStore } from './friend';
import { useGroupStore } from './group';
import { showGroupDialog } from '../coordinators/groupCoordinator';
import { showWorldDialog } from '../coordinators/worldCoordinator';
import { showAvatarDialog } from '../coordinators/avatarCoordinator';
import { applyUser, showUserDialog, lookupUser } from '../coordinators/userCoordinator';
import { useModalStore } from './modal';
import { useUserStore } from './user';
import { useWorldStore } from './world';
@@ -93,7 +97,7 @@ export const useSearchStore = defineStore('Search', () => {
console.error('getUsers gave us garbage', json);
continue;
}
userStore.applyUser(json);
applyUser(json);
}
const map = new Map();
@@ -210,10 +214,10 @@ export const useSearchStore = defineStore('Search', () => {
} else {
router.push({ name: 'search' });
searchText.value = searchTerm;
userStore.lookupUser({ displayName: searchTerm });
lookupUser({ displayName: searchTerm });
}
} else {
userStore.showUserDialog(value);
showUserDialog(value);
}
}
@@ -273,15 +277,15 @@ export const useSearchStore = defineStore('Search', () => {
const type = urlPathSplit[2];
if (type === 'user') {
const userId = urlPathSplit[3];
userStore.showUserDialog(userId);
showUserDialog(userId);
return true;
} else if (type === 'avatar') {
const avatarId = urlPathSplit[3];
avatarStore.showAvatarDialog(avatarId);
showAvatarDialog(avatarId);
return true;
} else if (type === 'group') {
const groupId = urlPathSplit[3];
groupStore.showGroupDialog(groupId);
showGroupDialog(groupId);
return true;
}
} else if (input.startsWith('https://vrc.group/')) {
@@ -295,16 +299,16 @@ export const useSearchStore = defineStore('Search', () => {
input.substring(0, 4) === 'usr_' ||
/^[A-Za-z0-9]{10}$/g.test(input)
) {
userStore.showUserDialog(input);
showUserDialog(input);
return true;
} else if (
input.substring(0, 5) === 'avtr_' ||
input.substring(0, 2) === 'b_'
) {
avatarStore.showAvatarDialog(input);
showAvatarDialog(input);
return true;
} else if (input.substring(0, 4) === 'grp_') {
groupStore.showGroupDialog(input);
showGroupDialog(input);
return true;
}
return false;
@@ -331,7 +335,7 @@ export const useSearchStore = defineStore('Search', () => {
const urlPathSplit = urlPath.split('/');
if (urlPathSplit.length >= 4 && urlPathSplit[2] === 'world') {
worldId = urlPathSplit[3];
worldStore.showWorldDialog(worldId);
showWorldDialog(worldId);
return true;
} else if (urlPath.substring(5, 12) === '/launch') {
const urlParams = new URLSearchParams(url.search);
@@ -343,10 +347,10 @@ export const useSearchStore = defineStore('Search', () => {
if (shortName) {
return verifyShortName(location, shortName);
}
worldStore.showWorldDialog(location);
showWorldDialog(location);
return true;
} else if (worldId) {
worldStore.showWorldDialog(worldId);
showWorldDialog(worldId);
return true;
}
}
@@ -360,7 +364,7 @@ export const useSearchStore = defineStore('Search', () => {
input = `https://vrchat.com/home/launch?worldId=${input}`;
return directAccessWorld(input);
}
worldStore.showWorldDialog(input.trim());
showWorldDialog(input.trim());
return true;
}
return false;
@@ -399,7 +403,7 @@ export const useSearchStore = defineStore('Search', () => {
groupRequest.groupStrictsearch({ query: shortCode }).then((args) => {
for (const group of args.json) {
if (`${group.shortCode}.${group.discriminator}` === shortCode) {
groupStore.showGroupDialog(group.id);
showGroupDialog(group.id);
break;
}
}
@@ -414,11 +418,11 @@ export const useSearchStore = defineStore('Search', () => {
const newLocation = args.json.location;
const newShortName = args.json.shortName;
if (newShortName) {
worldStore.showWorldDialog(newLocation, newShortName);
showWorldDialog(newLocation, newShortName);
} else if (newLocation) {
worldStore.showWorldDialog(newLocation);
showWorldDialog(newLocation);
} else {
worldStore.showWorldDialog(location);
showWorldDialog(location);
}
return args;
});

View File

@@ -10,6 +10,10 @@ import { updateLocalizedStrings } from '../plugin/i18n';
import { useAppearanceSettingsStore } from './settings/appearance';
import { useAvatarStore } from './avatar';
import { useGroupStore } from './group';
import { showGroupDialog } from '../coordinators/groupCoordinator';
import { showWorldDialog } from '../coordinators/worldCoordinator';
import { showAvatarDialog } from '../coordinators/avatarCoordinator';
import { showUserDialog } from '../coordinators/userCoordinator';
import { useInstanceStore } from './instance';
import { useNotificationStore } from './notification';
import { useSearchStore } from './search';
@@ -142,19 +146,19 @@ export const useUiStore = defineStore('Ui', () => {
}
jumpDialogCrumb(index);
if (item.type === 'user') {
userStore.showUserDialog(item.id);
showUserDialog(item.id);
return;
}
if (item.type === 'world') {
worldStore.showWorldDialog(item.tag, item.shortName);
showWorldDialog(item.tag, item.shortName);
return;
}
if (item.type === 'avatar') {
avatarStore.showAvatarDialog(item.id);
showAvatarDialog(item.id);
return;
}
if (item.type === 'group') {
groupStore.showGroupDialog(item.id);
showGroupDialog(item.id);
return;
}
if (item.type === 'previous-instances-user') {

View File

@@ -12,6 +12,8 @@ import { useFriendStore } from './friend';
import { useGameLogStore } from './gameLog';
import { useGameStore } from './game';
import { useGroupStore } from './group';
import { handleGroupUserInstances } from '../coordinators/groupCoordinator';
import { getCurrentUser, updateAutoStateChange } from '../coordinators/userCoordinator';
import { useModerationStore } from './moderation';
import { useUserStore } from './user';
import { useVRCXUpdaterStore } from './vrcxUpdater';
@@ -73,7 +75,7 @@ export const useUpdateLoopStore = defineStore('UpdateLoop', () => {
if (watchState.isLoggedIn) {
if (--state.nextCurrentUserRefresh <= 0) {
state.nextCurrentUserRefresh = 300; // 5min
userStore.getCurrentUser();
getCurrentUser();
}
if (--state.nextFriendsRefresh <= 0) {
state.nextFriendsRefresh = 3600; // 1hour
@@ -92,7 +94,7 @@ export const useUpdateLoopStore = defineStore('UpdateLoop', () => {
state.nextGroupInstanceRefresh = 300; // 5min
const args =
await groupRequest.getUsersGroupInstances();
groupStore.handleGroupUserInstances(args);
handleGroupUserInstances(args);
}
AppApi.CheckGameRunning();
}
@@ -122,7 +124,7 @@ export const useUpdateLoopStore = defineStore('UpdateLoop', () => {
}
if (--state.nextAutoStateChange <= 0) {
state.nextAutoStateChange = 3;
userStore.updateAutoStateChange();
updateAutoStateChange();
}
if (LINUX && --state.nextGetLogCheck <= 0) {
state.nextGetLogCheck = 0.5;

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,10 @@ import { useGalleryStore } from './gallery';
import { useGameLogStore } from './gameLog';
import { useGameStore } from './game';
import { useGroupStore } from './group';
import { showGroupDialog } from '../coordinators/groupCoordinator';
import { showWorldDialog } from '../coordinators/worldCoordinator';
import { showAvatarDialog, selectAvatarWithConfirmation, selectAvatarWithoutConfirmation } from '../coordinators/avatarCoordinator';
import { showUserDialog, addCustomTag } from '../coordinators/userCoordinator';
import { useInstanceStore } from './instance';
import { useLocationStore } from './location';
import { useModalStore } from './modal';
@@ -335,7 +339,7 @@ export const useVrcxStore = defineStore('Vrcx', () => {
let entry;
switch (data.MsgType) {
case 'CustomTag':
userStore.addCustomTag(data);
addCustomTag(data);
break;
case 'ClearCustomTags':
userStore.customUserTags.forEach((value, key) => {
@@ -669,17 +673,17 @@ export const useVrcxStore = defineStore('Vrcx', () => {
!searchStore.directAccessWorld(input.replace('world/', ''))
) {
// fallback for mangled world ids
worldStore.showWorldDialog(commandArg);
showWorldDialog(commandArg);
}
break;
case 'avatar':
avatarStore.showAvatarDialog(commandArg);
showAvatarDialog(commandArg);
break;
case 'user':
userStore.showUserDialog(commandArg);
showUserDialog(commandArg);
break;
case 'group':
groupStore.showGroupDialog(commandArg);
showGroupDialog(commandArg);
break;
case 'local-favorite-world':
console.log('local-favorite-world', commandArg);
@@ -701,7 +705,7 @@ export const useVrcxStore = defineStore('Vrcx', () => {
break;
}
avatarRequest.getAvatar({ avatarId: avatarIdFav }).then(() => {
avatarStore.showAvatarDialog(avatarIdFav);
showAvatarDialog(avatarIdFav);
addLocalAvatarFavorite(
avatarIdFav,
avatarGroup
@@ -722,12 +726,11 @@ export const useVrcxStore = defineStore('Vrcx', () => {
break;
}
if (advancedSettingsStore.showConfirmationOnSwitchAvatar) {
avatarStore.selectAvatarWithConfirmation(avatarId);
selectAvatarWithConfirmation(avatarId);
// Makes sure the window is focused
shouldFocusWindow = true;
} else {
avatarStore
.selectAvatarWithoutConfirmation(avatarId)
selectAvatarWithoutConfirmation(avatarId)
.then(() => {
toast.success('Avatar changed via launch command');
});

View File

@@ -1,39 +1,12 @@
import { nextTick, reactive, shallowReactive, watch } from 'vue';
import { reactive, shallowReactive, watch } from 'vue';
import { defineStore } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
import {
checkVRChatCache,
createDefaultWorldRef,
evictMapCache,
getAvailablePlatforms,
getBundleDateSize,
getWorldMemo,
isRealInstance,
parseLocation,
sanitizeEntityJson
checkVRChatCache
} from '../shared/utils';
import { instanceRequest, queryRequest, worldRequest } from '../api';
import { database } from '../service/database';
import { patchWorldFromEvent } from '../queries';
import { processBulk } from '../service/request';
import { applyFavorite } from '../coordinators/favoriteCoordinator';
import { useFavoriteStore } from './favorite';
import { useInstanceStore } from './instance';
import { useLocationStore } from './location';
import { useUiStore } from './ui';
import { useUserStore } from './user';
import { watchState } from '../service/watchState';
export const useWorldStore = defineStore('World', () => {
const locationStore = useLocationStore();
const favoriteStore = useFavoriteStore();
const instanceStore = useInstanceStore();
const userStore = useUserStore();
const uiStore = useUiStore();
const { t } = useI18n();
const worldDialog = reactive({
visible: false,
loading: false,
@@ -69,145 +42,14 @@ export const useWorldStore = defineStore('World', () => {
worldDialog.visible = false;
cachedWorlds.clear();
if (isLoggedIn) {
preloadOwnWorlds();
import('../coordinators/worldCoordinator').then(
({ preloadOwnWorlds }) => preloadOwnWorlds()
);
}
},
{ flush: 'sync' }
);
/**
*
* @param {string} tag
* @param {string} shortName
* @param options
*/
function showWorldDialog(tag, shortName = null, options = {}) {
const D = worldDialog;
const forceRefresh = Boolean(options?.forceRefresh);
const L = parseLocation(tag);
if (L.worldId === '') {
return;
}
const isMainDialogOpen = uiStore.openDialog({
type: 'world',
id: L.worldId,
tag,
shortName
});
D.visible = true;
if (isMainDialogOpen && D.id === L.worldId && !forceRefresh) {
uiStore.setDialogCrumbLabel('world', D.id, D.ref?.name || D.id);
instanceStore.applyWorldDialogInstances();
nextTick(() => (D.loading = false));
return;
}
L.shortName = shortName;
D.id = L.worldId;
D.$location = L;
D.loading = true;
D.inCache = false;
D.cacheSize = '';
D.cacheLocked = false;
D.cachePath = '';
D.fileAnalysis = {};
D.rooms = [];
D.lastVisit = '';
D.visitCount = 0;
D.timeSpent = 0;
D.isFavorite = false;
D.avatarScalingDisabled = false;
D.focusViewDisabled = false;
D.isPC = false;
D.isQuest = false;
D.isIos = false;
D.hasPersistData = false;
D.memo = '';
const LL = parseLocation(locationStore.lastLocation.location);
let currentWorldMatch = false;
if (LL.worldId === D.id) {
currentWorldMatch = true;
}
getWorldMemo(D.id).then((memo) => {
if (memo.worldId === D.id) {
D.memo = memo.memo;
}
});
database.getLastVisit(D.id, currentWorldMatch).then((ref) => {
if (ref.worldId === D.id) {
D.lastVisit = ref.created_at;
}
});
database.getVisitCount(D.id).then((ref) => {
if (ref.worldId === D.id) {
D.visitCount = ref.visitCount;
}
});
database.getTimeSpentInWorld(D.id).then((ref) => {
if (ref.worldId === D.id) {
D.timeSpent = ref.timeSpent;
}
});
const loadWorldRequest = worldRequest.getWorld({
worldId: L.worldId
});
loadWorldRequest
.catch((err) => {
nextTick(() => (D.loading = false));
D.id = null;
D.visible = false;
uiStore.jumpBackDialogCrumb();
toast.error(t('message.world.load_failed'));
throw err;
})
.then((args) => {
if (D.id === args.ref.id) {
D.ref = args.ref;
uiStore.setDialogCrumbLabel(
'world',
D.id,
D.ref?.name || D.id
);
D.visible = true;
D.loading = false;
D.isFavorite = favoriteStore.getCachedFavoritesByObjectId(
D.id
);
if (!D.isFavorite) {
D.isFavorite =
favoriteStore.localWorldFavoritesList.includes(
D.id
);
}
let { isPC, isQuest, isIos } = getAvailablePlatforms(
args.ref.unityPackages
);
D.avatarScalingDisabled = args.ref?.tags.includes(
'feature_avatar_scaling_disabled'
);
D.focusViewDisabled = args.ref?.tags.includes(
'feature_focus_view_disabled'
);
D.isPC = isPC;
D.isQuest = isQuest;
D.isIos = isIos;
updateVRChatWorldCache();
queryRequest
.fetch('worldPersistData', {
worldId: D.id
})
.then((args) => {
if (
args.params.worldId === worldDialog.id &&
worldDialog.visible
) {
worldDialog.hasPersistData =
args.json !== false;
}
});
}
});
}
/**
* @param {boolean} value
*/
@@ -250,99 +92,12 @@ export const useWorldStore = defineStore('World', () => {
}
}
/**
*
* @param WorldCache
*/
function cleanupWorldCache(WorldCache) {
evictMapCache(WorldCache, 10000, () => false, {
logLabel: 'World cache cleanup'
});
}
/**
*
* @param {object} json
* @returns {object} ref
*/
function applyWorld(json) {
sanitizeEntityJson(json, ['name', 'description']);
let ref = cachedWorlds.get(json.id);
if (typeof ref === 'undefined') {
ref = createDefaultWorldRef(json);
cleanupWorldCache(cachedWorlds);
cachedWorlds.set(ref.id, ref);
} else {
Object.assign(ref, json);
}
ref.$isLabs = ref.tags.includes('system_labs');
applyFavorite('world', ref.id);
const userDialog = userStore.userDialog;
if (userDialog.visible && userDialog.$location.worldId === ref.id) {
userStore.applyUserDialogLocation();
}
if (worldDialog.visible && worldDialog.id === ref.id) {
worldDialog.ref = ref;
worldDialog.avatarScalingDisabled = ref.tags?.includes(
'feature_avatar_scaling_disabled'
);
worldDialog.focusViewDisabled = ref.tags?.includes(
'feature_focus_view_disabled'
);
instanceStore.applyWorldDialogInstances();
for (const room of worldDialog.rooms) {
if (isRealInstance(room.tag)) {
instanceRequest.getInstance({
worldId: worldDialog.id,
instanceId: room.id
});
}
}
if (Object.keys(worldDialog.fileAnalysis).length === 0) {
getBundleDateSize(ref);
}
}
if (favoriteStore.localWorldFavoritesList.includes(ref.id)) {
// update db cache
database.addWorldToCache(ref);
}
patchWorldFromEvent(ref);
return ref;
}
/**
* Preload all own worlds into cache at startup for global search.
*/
async function preloadOwnWorlds() {
const params = {
n: 50,
offset: 0,
sort: 'updated',
order: 'descending',
releaseStatus: 'all',
user: 'me'
};
await processBulk({
fn: (p) => worldRequest.getWorlds(p),
N: -1,
params,
handle: (args) => {
for (const json of args.json) {
applyWorld(json);
}
}
});
}
return {
worldDialog,
cachedWorlds,
showWorldDialog,
setWorldDialogVisible,
setWorldDialogIsFavorite,
setWorldDialogLoading,
updateVRChatWorldCache,
applyWorld,
preloadOwnWorlds
updateVRChatWorldCache
};
});