refactor store

This commit is contained in:
pa
2026-03-10 13:55:03 +09:00
parent 2fffadfbcf
commit d7220baaf6
47 changed files with 1993 additions and 1750 deletions
+2 -1
View File
@@ -26,6 +26,7 @@
import { TooltipProvider } from './components/ui/tooltip'; import { TooltipProvider } from './components/ui/tooltip';
import { createGlobalStores } from './stores'; import { createGlobalStores } from './stores';
import { initNoty } from './plugin/noty'; import { initNoty } from './plugin/noty';
import { runCheckVRChatDebugLoggingFlow } from './coordinators/gameCoordinator';
import AlertDialogModal from './components/ui/alert-dialog/AlertDialogModal.vue'; import AlertDialogModal from './components/ui/alert-dialog/AlertDialogModal.vue';
import MacOSTitleBar from './components/MacOSTitleBar.vue'; import MacOSTitleBar from './components/MacOSTitleBar.vue';
@@ -60,6 +61,6 @@
await store.auth.migrateStoredUsers(); await store.auth.migrateStoredUsers();
store.auth.autoLoginAfterMounted(); store.auth.autoLoginAfterMounted();
store.vrcx.checkAutoBackupRestoreVrcRegistry(); store.vrcx.checkAutoBackupRestoreVrcRegistry();
store.game.checkVRChatDebugLogging(); runCheckVRChatDebugLoggingFlow();
}); });
</script> </script>
+6 -5
View File
@@ -11,15 +11,16 @@ vi.mock('../../service/request', () => ({
})); }));
vi.mock('../../stores', () => ({ vi.mock('../../stores', () => ({
useFavoriteStore: () => ({ useUserStore: () => ({
currentUser: { id: 'usr_me' }
})
}));
vi.mock('../../coordinators/favoriteCoordinator', () => ({
handleFavoriteAdd: (...args) => mockHandleFavoriteAdd(...args), handleFavoriteAdd: (...args) => mockHandleFavoriteAdd(...args),
handleFavoriteDelete: (...args) => mockHandleFavoriteDelete(...args), handleFavoriteDelete: (...args) => mockHandleFavoriteDelete(...args),
handleFavoriteGroupClear: (...args) => handleFavoriteGroupClear: (...args) =>
mockHandleFavoriteGroupClear(...args) mockHandleFavoriteGroupClear(...args)
}),
useUserStore: () => ({
currentUser: { id: 'usr_me' }
})
})); }));
vi.mock('../../queries', () => ({ vi.mock('../../queries', () => ({
+3
View File
@@ -6,6 +6,9 @@ const mockGetWorlds = vi.fn();
const mockGetGroupCalendar = vi.fn(); const mockGetGroupCalendar = vi.fn();
vi.mock('../../queries', () => ({ vi.mock('../../queries', () => ({
queryClient: {
invalidateQueries: vi.fn().mockResolvedValue(undefined)
},
entityQueryPolicies: { entityQueryPolicies: {
user: { staleTime: 20000, gcTime: 90000, retry: 1, refetchOnWindowFocus: false }, user: { staleTime: 20000, gcTime: 90000, retry: 1, refetchOnWindowFocus: false },
worldCollection: { staleTime: 60000, gcTime: 300000, retry: 1, refetchOnWindowFocus: false }, worldCollection: { staleTime: 60000, gcTime: 300000, retry: 1, refetchOnWindowFocus: false },
+8 -3
View File
@@ -1,4 +1,9 @@
import { useFavoriteStore, useUserStore } from '../stores'; import { useFavoriteStore, useUserStore } from '../stores';
import {
handleFavoriteAdd,
handleFavoriteDelete,
handleFavoriteGroupClear
} from '../coordinators/favoriteCoordinator';
import { queryClient } from '../queries'; import { queryClient } from '../queries';
import { request } from '../service/request'; import { request } from '../service/request';
@@ -63,7 +68,7 @@ const favoriteReq = {
json, json,
params params
}; };
useFavoriteStore().handleFavoriteAdd(args); handleFavoriteAdd(args);
refetchActiveFavoriteQueries(); refetchActiveFavoriteQueries();
return args; return args;
}); });
@@ -81,7 +86,7 @@ const favoriteReq = {
json, json,
params params
}; };
useFavoriteStore().handleFavoriteDelete(params.objectId); handleFavoriteDelete(params.objectId);
refetchActiveFavoriteQueries(); refetchActiveFavoriteQueries();
return args; return args;
}); });
@@ -145,7 +150,7 @@ const favoriteReq = {
json, json,
params params
}; };
useFavoriteStore().handleFavoriteGroupClear(args); handleFavoriteGroupClear(args);
refetchActiveFavoriteQueries(); refetchActiveFavoriteQueries();
return args; return args;
}); });
@@ -600,6 +600,7 @@
import { database } from '../../../service/database'; import { database } from '../../../service/database';
import { formatJsonVars } from '../../../shared/utils/base/ui'; import { formatJsonVars } from '../../../shared/utils/base/ui';
import { handleImageUploadInput } from '../../../shared/utils/imageUpload'; import { handleImageUploadInput } from '../../../shared/utils/imageUpload';
import { runDeleteVRChatCacheFlow as deleteVRChatCache } from '../../../coordinators/gameCoordinator';
import { useAvatarDialogCommands } from './useAvatarDialogCommands'; import { useAvatarDialogCommands } from './useAvatarDialogCommands';
import DialogJsonTab from '../DialogJsonTab.vue'; import DialogJsonTab from '../DialogJsonTab.vue';
@@ -617,7 +618,6 @@
avatarStore; avatarStore;
const { showFavoriteDialog } = useFavoriteStore(); const { showFavoriteDialog } = useFavoriteStore();
const { isGameRunning } = storeToRefs(useGameStore()); const { isGameRunning } = storeToRefs(useGameStore());
const { deleteVRChatCache } = useGameStore();
const { showFullscreenImageDialog } = useGalleryStore(); const { showFullscreenImageDialog } = useGalleryStore();
const { isDarkMode } = storeToRefs(useAppearanceSettingsStore()); const { isDarkMode } = storeToRefs(useAppearanceSettingsStore());
const modalStore = useModalStore(); const modalStore = useModalStore();
@@ -108,6 +108,14 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useFavoriteStore, useUserStore } from '../../stores'; import { useFavoriteStore, useUserStore } from '../../stores';
import {
addLocalWorldFavorite,
removeLocalWorldFavorite,
addLocalAvatarFavorite,
removeLocalAvatarFavorite,
addLocalFriendFavorite,
removeLocalFriendFavorite
} from '../../coordinators/favoriteCoordinator';
import { favoriteRequest } from '../../api'; import { favoriteRequest } from '../../api';
const { t } = useI18n(); const { t } = useI18n();
@@ -124,18 +132,12 @@
} = storeToRefs(favoriteStore); } = storeToRefs(favoriteStore);
const { const {
localWorldFavGroupLength, localWorldFavGroupLength,
addLocalWorldFavorite,
hasLocalWorldFavorite, hasLocalWorldFavorite,
hasLocalAvatarFavorite, hasLocalAvatarFavorite,
addLocalAvatarFavorite,
localAvatarFavGroupLength, localAvatarFavGroupLength,
removeLocalAvatarFavorite,
removeLocalWorldFavorite,
deleteFavoriteNoConfirm, deleteFavoriteNoConfirm,
localFriendFavGroupLength, localFriendFavGroupLength,
addLocalFriendFavorite, hasLocalFriendFavorite
hasLocalFriendFavorite,
removeLocalFriendFavorite
} = favoriteStore; } = favoriteStore;
const { isLocalUserVrcPlusSupporter } = storeToRefs(useUserStore()); const { isLocalUserVrcPlusSupporter } = storeToRefs(useUserStore());
@@ -76,13 +76,13 @@
import DeprecationAlert from '@/components/DeprecationAlert.vue'; import DeprecationAlert from '@/components/DeprecationAlert.vue';
import { useFavoriteStore, useUserStore, useWorldStore } from '../../../stores'; import { useFavoriteStore, useUserStore, useWorldStore } from '../../../stores';
import { handleFavoriteWorldList } from '../../../coordinators/favoriteCoordinator';
import { favoriteRequest } from '../../../api'; import { favoriteRequest } from '../../../api';
const { t } = useI18n(); const { t } = useI18n();
const { userDialog, currentUser } = storeToRefs(useUserStore()); const { userDialog, currentUser } = storeToRefs(useUserStore());
const { favoriteLimits } = storeToRefs(useFavoriteStore()); const { favoriteLimits } = storeToRefs(useFavoriteStore());
const { handleFavoriteWorldList } = useFavoriteStore();
const { showWorldDialog } = useWorldStore(); const { showWorldDialog } = useWorldStore();
const favoriteWorldsTab = ref('0'); const favoriteWorldsTab = ref('0');
@@ -405,6 +405,7 @@
import { deleteVRChatCache, openFolderGeneric } from '../../../shared/utils'; import { deleteVRChatCache, openFolderGeneric } from '../../../shared/utils';
import { Badge } from '../../ui/badge'; import { Badge } from '../../ui/badge';
import { formatJsonVars } from '../../../shared/utils/base/ui'; import { formatJsonVars } from '../../../shared/utils/base/ui';
import { runNewInstanceSelfInviteFlow as newInstanceSelfInvite } from '../../../coordinators/inviteCoordinator';
import { useWorldDialogCommands } from './useWorldDialogCommands'; import { useWorldDialogCommands } from './useWorldDialogCommands';
import DialogJsonTab from '../DialogJsonTab.vue'; import DialogJsonTab from '../DialogJsonTab.vue';
@@ -421,7 +422,7 @@
const { worldDialog } = storeToRefs(useWorldStore()); const { worldDialog } = storeToRefs(useWorldStore());
const { cachedWorlds, showWorldDialog } = useWorldStore(); const { cachedWorlds, showWorldDialog } = useWorldStore();
const { lastLocation } = storeToRefs(useLocationStore()); const { lastLocation } = storeToRefs(useLocationStore());
const { newInstanceSelfInvite, canOpenInstanceInGame } = useInviteStore(); const { canOpenInstanceInGame } = useInviteStore();
const { showFavoriteDialog } = useFavoriteStore(); const { showFavoriteDialog } = useFavoriteStore();
const { showPreviousInstancesListDialog: openPreviousInstancesListDialog } = useInstanceStore(); const { showPreviousInstancesListDialog: openPreviousInstancesListDialog } = useInstanceStore();
const { isGameRunning } = storeToRefs(useGameStore()); const { isGameRunning } = storeToRefs(useGameStore());
File diff suppressed because it is too large Load Diff
+10 -2
View File
@@ -3,6 +3,8 @@ import { AppDebug } from '../service/appConfig';
import { database } from '../service/database'; import { database } from '../service/database';
import { useFeedStore } from '../stores/feed'; import { useFeedStore } from '../stores/feed';
import { useFriendStore } from '../stores/friend'; import { useFriendStore } from '../stores/friend';
import { useNotificationStore } from '../stores/notification';
import { useSharedFeedStore } from '../stores/sharedFeed';
import { useUserStore } from '../stores/user'; import { useUserStore } from '../stores/user';
import { userRequest } from '../api'; import { userRequest } from '../api';
import { watchState } from '../service/watchState'; import { watchState } from '../service/watchState';
@@ -25,6 +27,8 @@ export async function runUpdateFriendDelayedCheckFlow(
) { ) {
const friendStore = useFriendStore(); const friendStore = useFriendStore();
const feedStore = useFeedStore(); const feedStore = useFeedStore();
const notificationStore = useNotificationStore();
const sharedFeedStore = useSharedFeedStore();
const { friends, localFavoriteFriends } = friendStore; const { friends, localFavoriteFriends } = friendStore;
let feed; let feed;
@@ -72,7 +76,9 @@ export async function runUpdateFriendDelayedCheckFlow(
groupName, groupName,
time time
}; };
feedStore.addFeed(feed); notificationStore.queueFeedNoty(feed);
sharedFeedStore.addEntry(feed);
feedStore.addFeedEntry(feed);
database.addOnlineOfflineToDatabase(feed); database.addOnlineOfflineToDatabase(feed);
} else if ( } else if (
newState === 'online' && newState === 'online' &&
@@ -96,7 +102,9 @@ export async function runUpdateFriendDelayedCheckFlow(
groupName, groupName,
time: '' time: ''
}; };
feedStore.addFeed(feed); notificationStore.queueFeedNoty(feed);
sharedFeedStore.addEntry(feed);
feedStore.addFeedEntry(feed);
database.addOnlineOfflineToDatabase(feed); database.addOnlineOfflineToDatabase(feed);
} }
if (newState === 'active') { if (newState === 'active') {
@@ -1,5 +1,6 @@
import { database } from '../service/database'; import { database } from '../service/database';
import { friendRequest } from '../api'; import { friendRequest } from '../api';
import { handleFavoriteDelete } from './favoriteCoordinator';
import { useAppearanceSettingsStore } from '../stores/settings/appearance'; import { useAppearanceSettingsStore } from '../stores/settings/appearance';
import { useFavoriteStore } from '../stores/favorite'; import { useFavoriteStore } from '../stores/favorite';
import { useFriendStore } from '../stores/friend'; import { useFriendStore } from '../stores/friend';
@@ -56,7 +57,7 @@ export function runDeleteFriendshipFlow(
sharedFeedStore.addEntry(friendLogHistory); sharedFeedStore.addEntry(friendLogHistory);
friendLog.delete(id); friendLog.delete(id);
database.deleteFriendLogCurrent(id); database.deleteFriendLogCurrent(id);
favoriteStore.handleFavoriteDelete(id); handleFavoriteDelete(id);
if (!appearanceSettingsStore.hideUnfriends) { if (!appearanceSettingsStore.hideUnfriends) {
uiStore.notifyMenu('friend-log'); uiStore.notifyMenu('friend-log');
} }
+210 -4
View File
@@ -1,11 +1,24 @@
import { toast } from 'vue-sonner';
import {
deleteVRChatCache as _deleteVRChatCache,
isRealInstance
} from '../shared/utils';
import { database } from '../service/database';
import { useAdvancedSettingsStore } from '../stores/settings/advanced';
import { useAvatarStore } from '../stores/avatar'; import { useAvatarStore } from '../stores/avatar';
import { useGameLogStore } from '../stores/gameLog'; import { useGameLogStore } from '../stores/gameLog';
import { useGameStore } from '../stores/game'; import { useGameStore } from '../stores/game';
import { useInstanceStore } from '../stores/instance'; import { useInstanceStore } from '../stores/instance';
import { useLaunchStore } from '../stores/launch';
import { useLocationStore } from '../stores/location'; import { useLocationStore } from '../stores/location';
import { runLastLocationResetFlow } from './locationCoordinator';
import { useModalStore } from '../stores/modal';
import { useNotificationStore } from '../stores/notification';
import { useUpdateLoopStore } from '../stores/updateLoop'; import { useUpdateLoopStore } from '../stores/updateLoop';
import { useUserStore } from '../stores/user'; import { useUserStore } from '../stores/user';
import { useVrStore } from '../stores/vr'; import { useVrStore } from '../stores/vr';
import { useWorldStore } from '../stores/world';
import configRepository from '../service/config'; import configRepository from '../service/config';
@@ -31,15 +44,208 @@ export async function runGameRunningChangedFlow(isGameRunning) {
await configRepository.setBool('isGameNoVR', gameStore.isGameNoVR); await configRepository.setBool('isGameNoVR', gameStore.isGameNoVR);
userStore.markCurrentUserGameStopped(); userStore.markCurrentUserGameStopped();
instanceStore.removeAllQueuedInstances(); instanceStore.removeAllQueuedInstances();
gameStore.autoVRChatCacheManagement(); runAutoVRChatCacheManagementFlow();
gameStore.checkIfGameCrashed(); runCheckIfGameCrashedFlow();
updateLoopStore.setIpcTimeout(0); updateLoopStore.setIpcTimeout(0);
avatarStore.addAvatarWearTime(userStore.currentUser.currentAvatar); avatarStore.addAvatarWearTime(userStore.currentUser.currentAvatar);
} }
locationStore.lastLocationReset(); runLastLocationResetFlow();
gameLogStore.clearNowPlaying(); gameLogStore.clearNowPlaying();
vrStore.updateVRLastLocation(); vrStore.updateVRLastLocation();
workerTimers.setTimeout(() => gameStore.checkVRChatDebugLogging(), 60000); workerTimers.setTimeout(() => runCheckVRChatDebugLoggingFlow(), 60000);
updateLoopStore.setNextDiscordUpdate(0); updateLoopStore.setNextDiscordUpdate(0);
} }
/**
* Orchestrates the game running state update from IPC.
* @param {boolean} isGameRunningArg Game running flag from IPC.
* @param {boolean} isSteamVRRunningArg SteamVR running flag from IPC.
*/
export async function runUpdateIsGameRunningFlow(
isGameRunningArg,
isSteamVRRunningArg
) {
const gameStore = useGameStore();
const advancedSettingsStore = useAdvancedSettingsStore();
const vrStore = useVrStore();
if (advancedSettingsStore.gameLogDisabled) {
return;
}
if (isGameRunningArg !== gameStore.isGameRunning) {
gameStore.setIsGameRunning(isGameRunningArg);
await runGameRunningChangedFlow(isGameRunningArg);
console.log(new Date(), 'isGameRunning', isGameRunningArg);
}
if (isSteamVRRunningArg !== gameStore.isSteamVRRunning) {
gameStore.setIsSteamVRRunning(isSteamVRRunningArg);
console.log('isSteamVRRunning:', isSteamVRRunningArg);
}
vrStore.updateOpenVR();
}
/**
* Runs auto cache management if enabled.
*/
function runAutoVRChatCacheManagementFlow() {
const advancedSettingsStore = useAdvancedSettingsStore();
if (advancedSettingsStore.autoSweepVRChatCache) {
runSweepVRChatCacheFlow();
}
}
/**
* Sweeps VRChat cache and refreshes cache size display if config dialog visible.
*/
export async function runSweepVRChatCacheFlow() {
const gameStore = useGameStore();
const advancedSettingsStore = useAdvancedSettingsStore();
try {
const output = await AssetBundleManager.SweepCache();
console.log('SweepCache', output);
} catch (e) {
console.error('SweepCache failed', e);
}
if (advancedSettingsStore.isVRChatConfigDialogVisible) {
gameStore.getVRChatCacheSize();
}
}
/**
* Deletes VRChat cache for a given ref and refreshes related stores.
* @param {object} ref Avatar or world reference payload.
*/
export async function runDeleteVRChatCacheFlow(ref) {
const gameStore = useGameStore();
const worldStore = useWorldStore();
const avatarStore = useAvatarStore();
await _deleteVRChatCache(ref);
gameStore.getVRChatCacheSize();
worldStore.updateVRChatWorldCache();
avatarStore.updateVRChatAvatarCache();
}
/**
* Checks if VRChat crashed and attempts to relaunch.
*/
export function runCheckIfGameCrashedFlow() {
const advancedSettingsStore = useAdvancedSettingsStore();
const locationStore = useLocationStore();
const gameStore = useGameStore();
if (!advancedSettingsStore.relaunchVRChatAfterCrash) {
return;
}
const { location } = locationStore.lastLocation;
AppApi.VrcClosedGracefully().then((result) => {
if (result || !isRealInstance(location)) {
return;
}
// check if relaunched less than 2mins ago (prevent crash loop)
if (
gameStore.state.lastCrashedTime &&
new Date().getTime() -
gameStore.state.lastCrashedTime.getTime() <
120_000
) {
console.log('VRChat was recently crashed, not relaunching');
return;
}
gameStore.setLastCrashedTime(new Date());
// wait a bit for SteamVR to potentially close before deciding to relaunch
let restartDelay = 8000;
if (gameStore.isGameNoVR) {
// wait for game to close before relaunching
restartDelay = 2000;
}
workerTimers.setTimeout(
() => runRestartCrashedGameFlow(location),
restartDelay
);
});
}
/**
* Restarts VRChat after a crash.
* @param {string} location Last known location to relaunch.
*/
function runRestartCrashedGameFlow(location) {
const gameStore = useGameStore();
const notificationStore = useNotificationStore();
const gameLogStore = useGameLogStore();
const launchStore = useLaunchStore();
if (!gameStore.isGameNoVR && !gameStore.isSteamVRRunning) {
console.log("SteamVR isn't running, not relaunching VRChat");
return;
}
AppApi.FocusWindow();
const message = 'VRChat crashed, attempting to rejoin last instance';
toast(message);
const entry = {
created_at: new Date().toJSON(),
type: 'Event',
data: message
};
database.addGamelogEventToDatabase(entry);
notificationStore.queueGameLogNoty(entry);
gameLogStore.addGameLog(entry);
launchStore.launchGame(location, '', gameStore.isGameNoVR);
}
/**
* Checks and re-enables VRChat debug logging if disabled.
*/
export async function runCheckVRChatDebugLoggingFlow() {
const gameStore = useGameStore();
const advancedSettingsStore = useAdvancedSettingsStore();
const modalStore = useModalStore();
if (advancedSettingsStore.gameLogDisabled) {
return;
}
try {
const loggingEnabled = await gameStore.getVRChatRegistryKey(
'LOGGING_ENABLED'
);
if (
loggingEnabled === null ||
typeof loggingEnabled === 'undefined'
) {
// key not found
return;
}
if (parseInt(loggingEnabled, 10) === 1) {
// already enabled
return;
}
const result = await AppApi.SetVRChatRegistryKey(
'LOGGING_ENABLED',
'1',
4
);
if (!result) {
// failed to set key
modalStore.alert({
description:
'VRCX has noticed VRChat debug logging is disabled. VRCX requires debug logging in order to function correctly. Please enable debug logging in VRChat quick menu settings > debug > enable debug logging, then rejoin the instance or restart VRChat.',
title: 'Enable debug logging'
});
console.error('Failed to enable debug logging', result);
return;
}
modalStore.alert({
description:
'VRCX has noticed VRChat debug logging is disabled and automatically re-enabled it. VRCX requires debug logging in order to function correctly.',
title: 'Enabled debug logging'
});
console.log('Enabled debug logging');
} catch (e) {
console.error(e);
}
}
+48
View File
@@ -0,0 +1,48 @@
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
import { instanceRequest } from '../api';
import { parseLocation } from '../shared/utils';
import { useInstanceStore } from '../stores/instance';
import { useInviteStore } from '../stores/invite';
import { useLaunchStore } from '../stores/launch';
/**
* Creates a new instance for the given world and either opens it in-game
* or sends a self-invite, depending on game state.
* @param {string} worldId
*/
export function runNewInstanceSelfInviteFlow(worldId) {
const instanceStore = useInstanceStore();
const launchStore = useLaunchStore();
const inviteStore = useInviteStore();
const { t } = useI18n();
instanceStore.createNewInstance(worldId).then((args) => {
const location = args?.json?.location;
if (!location) {
toast.error(t('message.instance.create_failed'));
return;
}
// self invite
const L = parseLocation(location);
if (!L.isRealInstance) {
return;
}
if (inviteStore.canOpenInstanceInGame) {
const secureOrShortName =
args.json.shortName || args.json.secureName;
launchStore.tryOpenInstanceInVrc(location, secureOrShortName);
return;
}
instanceRequest
.selfInvite({
instanceId: L.instanceId,
worldId: L.worldId
})
.then((args) => {
toast.success(t('message.invite.self_sent'));
return args;
});
});
}
+189
View File
@@ -0,0 +1,189 @@
import {
getGroupName,
getWorldName,
isRealInstance,
parseLocation
} from '../shared/utils';
import { database } from '../service/database';
import { useAdvancedSettingsStore } from '../stores/settings/advanced';
import { useGameLogStore } from '../stores/gameLog';
import { useGameStore } from '../stores/game';
import { useInstanceStore } from '../stores/instance';
import { useLocationStore } from '../stores/location';
import { useNotificationStore } from '../stores/notification';
import { usePhotonStore } from '../stores/photon';
import { useUserStore } from '../stores/user';
import { useVrStore } from '../stores/vr';
export function runUpdateCurrentUserLocationFlow() {
const advancedSettingsStore = useAdvancedSettingsStore();
const userStore = useUserStore();
const instanceStore = useInstanceStore();
const gameStore = useGameStore();
const locationStore = useLocationStore();
const ref = userStore.cachedUsers.get(userStore.currentUser.id);
if (typeof ref === 'undefined') {
return;
}
// update cached user with both gameLog and API locations
let currentLocation = userStore.currentUser.$locationTag;
const L = parseLocation(currentLocation);
if (L.isTraveling) {
currentLocation = userStore.currentUser.$travelingToLocation;
}
ref.location = userStore.currentUser.$locationTag;
ref.travelingToLocation = userStore.currentUser.$travelingToLocation;
if (
gameStore.isGameRunning &&
!advancedSettingsStore.gameLogDisabled &&
locationStore.lastLocation.location !== ''
) {
// use gameLog instead of API when game is running
currentLocation = locationStore.lastLocation.location;
if (locationStore.lastLocation.location === 'traveling') {
currentLocation = locationStore.lastLocationDestination;
}
ref.location = locationStore.lastLocation.location;
ref.travelingToLocation = locationStore.lastLocationDestination;
}
ref.$online_for = userStore.currentUser.$online_for;
ref.$offline_for = userStore.currentUser.$offline_for;
ref.$location = parseLocation(currentLocation);
if (!gameStore.isGameRunning || advancedSettingsStore.gameLogDisabled) {
ref.$location_at = userStore.currentUser.$location_at;
ref.$travelingToTime = userStore.currentUser.$travelingToTime;
userStore.applyUserDialogLocation();
instanceStore.applyWorldDialogInstances();
instanceStore.applyGroupDialogInstances();
} else {
ref.$location_at = locationStore.lastLocation.date;
ref.$travelingToTime = locationStore.lastLocationDestinationTime;
userStore.setCurrentUserTravelingToTime(
locationStore.lastLocationDestinationTime
);
}
}
export async function runSetCurrentUserLocationFlow(location, travelingToLocation) {
const userStore = useUserStore();
const instanceStore = useInstanceStore();
const notificationStore = useNotificationStore();
const gameStore = useGameStore();
const gameLogStore = useGameLogStore();
const locationStore = useLocationStore();
userStore.setCurrentUserLocationState(location, travelingToLocation);
runUpdateCurrentUserLocationFlow();
// janky gameLog support for Quest
if (gameStore.isGameRunning) {
// with the current state of things, lets not run this if we don't need to
return;
}
const lastLocationArray = await database.lookupGameLogDatabase(
['Location'],
[],
1
);
const lastLocationTemp =
lastLocationArray.length > 0 ? lastLocationArray[0].location : '';
if (lastLocationTemp === location) {
return;
}
locationStore.setLastLocationDestination('');
locationStore.setLastLocationDestinationTime(0);
if (isRealInstance(location)) {
const dt = new Date().toJSON();
const L = parseLocation(location);
locationStore.setLastLocation({
...locationStore.lastLocation,
location,
date: Date.now()
});
const entry = {
created_at: dt,
type: 'Location',
location,
worldId: L.worldId,
worldName: await getWorldName(L.worldId),
groupName: await getGroupName(L.groupId),
time: 0
};
database.addGamelogLocationToDatabase(entry);
notificationStore.queueGameLogNoty(entry);
gameLogStore.addGameLog(entry);
instanceStore.addInstanceJoinHistory(location, dt);
userStore.applyUserDialogLocation();
instanceStore.applyWorldDialogInstances();
instanceStore.applyGroupDialogInstances();
} else {
locationStore.setLastLocation({
...locationStore.lastLocation,
location: '',
date: null
});
}
}
export function runLastLocationResetFlow(gameLogDate) {
const photonStore = usePhotonStore();
const instanceStore = useInstanceStore();
const gameLogStore = useGameLogStore();
const vrStore = useVrStore();
const userStore = useUserStore();
const locationStore = useLocationStore();
let dateTime = gameLogDate;
if (!gameLogDate) {
dateTime = new Date().toJSON();
}
const dateTimeStamp = Date.parse(dateTime);
photonStore.resetLocationPhotonState();
const playerList = Array.from(locationStore.lastLocation.playerList.values());
const dataBaseEntries = [];
for (const ref of playerList) {
const entry = {
created_at: dateTime,
type: 'OnPlayerLeft',
displayName: ref.displayName,
location: locationStore.lastLocation.location,
userId: ref.userId,
time: dateTimeStamp - ref.joinTime
};
dataBaseEntries.unshift(entry);
gameLogStore.addGameLog(entry);
}
database.addGamelogJoinLeaveBulk(dataBaseEntries);
if (locationStore.lastLocation.date !== null && locationStore.lastLocation.date > 0) {
const update = {
time: dateTimeStamp - locationStore.lastLocation.date,
created_at: new Date(locationStore.lastLocation.date).toJSON()
};
database.updateGamelogLocationTimeToDatabase(update);
}
locationStore.setLastLocationDestination('');
locationStore.setLastLocationDestinationTime(0);
locationStore.setLastLocation({
date: 0,
location: '',
name: '',
playerList: new Map(),
friendList: new Map()
});
runUpdateCurrentUserLocationFlow();
instanceStore.updateCurrentInstanceWorld();
vrStore.updateVRLastLocation();
instanceStore.getCurrentInstanceUserList();
gameLogStore.resetLastMediaUrls();
userStore.applyUserDialogLocation();
instanceStore.applyWorldDialogInstances();
instanceStore.applyGroupDialogInstances();
}
+45
View File
@@ -0,0 +1,45 @@
import { avatarModerationRequest, playerModerationRequest } from '../api';
import { useAvatarStore } from '../stores/avatar';
import { useModerationStore } from '../stores/moderation';
/**
* Refreshes all player and avatar moderations from the API.
* Orchestrates across moderation store and avatar store.
*/
export async function runRefreshPlayerModerationsFlow() {
const moderationStore = useModerationStore();
const avatarStore = useAvatarStore();
if (moderationStore.playerModerationTable.loading) {
return;
}
moderationStore.playerModerationTable.loading = true;
moderationStore.expirePlayerModerations();
Promise.all([
playerModerationRequest.getPlayerModerations(),
avatarModerationRequest.getAvatarModerations()
])
.finally(() => {
moderationStore.playerModerationTable.loading = false;
})
.then((res) => {
avatarStore.resetCachedAvatarModerations();
if (res[1]?.json) {
for (const json of res[1].json) {
avatarStore.applyAvatarModeration(json);
}
}
if (res[0]?.json) {
for (let json of res[0].json) {
moderationStore.applyPlayerModeration(json);
}
}
moderationStore.deleteExpiredPlayerModerations();
})
.catch((error) => {
console.error(
'Failed to load player/avatar moderations:',
error
);
});
}
+16 -4
View File
@@ -7,6 +7,8 @@ import { useFriendStore } from '../stores/friend';
import { useGeneralSettingsStore } from '../stores/settings/general'; import { useGeneralSettingsStore } from '../stores/settings/general';
import { useGroupStore } from '../stores/group'; import { useGroupStore } from '../stores/group';
import { useInstanceStore } from '../stores/instance'; import { useInstanceStore } from '../stores/instance';
import { useNotificationStore } from '../stores/notification';
import { useSharedFeedStore } from '../stores/sharedFeed';
import { useUserStore } from '../stores/user'; import { useUserStore } from '../stores/user';
import { useWorldStore } from '../stores/world'; import { useWorldStore } from '../stores/world';
@@ -30,6 +32,8 @@ export async function runHandleUserUpdateFlow(
const groupStore = useGroupStore(); const groupStore = useGroupStore();
const instanceStore = useInstanceStore(); const instanceStore = useInstanceStore();
const feedStore = useFeedStore(); const feedStore = useFeedStore();
const notificationStore = useNotificationStore();
const sharedFeedStore = useSharedFeedStore();
const avatarStore = useAvatarStore(); const avatarStore = useAvatarStore();
const generalSettingsStore = useGeneralSettingsStore(); const generalSettingsStore = useGeneralSettingsStore();
@@ -139,7 +143,9 @@ export async function runHandleUserUpdateFlow(
previousLocation, previousLocation,
time time
}; };
feedStore.addFeed(feed); notificationStore.queueFeedNoty(feed);
sharedFeedStore.addEntry(feed);
feedStore.addFeedEntry(feed);
database.addGPSToDatabase(feed); database.addGPSToDatabase(feed);
// clear previousLocation after GPS // clear previousLocation after GPS
ref.$previousLocation = ''; ref.$previousLocation = '';
@@ -249,7 +255,9 @@ export async function runHandleUserUpdateFlow(
currentAvatarTags, currentAvatarTags,
previousCurrentAvatarTags previousCurrentAvatarTags
}; };
feedStore.addFeed(feed); notificationStore.queueFeedNoty(feed);
sharedFeedStore.addEntry(feed);
feedStore.addFeedEntry(feed);
database.addAvatarToDatabase(feed); database.addAvatarToDatabase(feed);
} }
} }
@@ -296,7 +304,9 @@ export async function runHandleUserUpdateFlow(
previousStatus, previousStatus,
previousStatusDescription previousStatusDescription
}; };
feedStore.addFeed(feed); notificationStore.queueFeedNoty(feed);
sharedFeedStore.addEntry(feed);
feedStore.addFeedEntry(feed);
database.addStatusToDatabase(feed); database.addStatusToDatabase(feed);
} }
if (props.bio && props.bio[0] && props.bio[1]) { if (props.bio && props.bio[0] && props.bio[1]) {
@@ -316,7 +326,9 @@ export async function runHandleUserUpdateFlow(
bio, bio,
previousBio previousBio
}; };
feedStore.addFeed(feed); notificationStore.queueFeedNoty(feed);
sharedFeedStore.addEntry(feed);
feedStore.addFeedEntry(feed);
database.addBioToDatabase(feed); database.addBioToDatabase(feed);
} }
if ( if (
+2 -1
View File
@@ -17,6 +17,7 @@ import { AppDebug } from './appConfig';
import { groupRequest } from '../api'; import { groupRequest } from '../api';
import { request } from './request'; import { request } from './request';
import { runUpdateFriendFlow } from '../coordinators/friendPresenceCoordinator'; import { runUpdateFriendFlow } from '../coordinators/friendPresenceCoordinator';
import { runSetCurrentUserLocationFlow } from '../coordinators/locationCoordinator';
import { watchState } from './watchState'; import { watchState } from './watchState';
import * as workerTimers from 'worker-timers'; import * as workerTimers from 'worker-timers';
@@ -397,7 +398,7 @@ function handlePipeline(args) {
// content.worldId // where did worldId go? // content.worldId // where did worldId go?
// content.instance // without worldId, this is useless // content.instance // without worldId, this is useless
locationStore.setCurrentUserLocation( runSetCurrentUserLocationFlow(
content.location, content.location,
content.travelingToLocation content.travelingToLocation
); );
+2 -1
View File
@@ -19,6 +19,7 @@ import { AppDebug } from '../service/appConfig';
import { database } from '../service/database'; import { database } from '../service/database';
import { patchAvatarFromEvent } from '../queries'; import { patchAvatarFromEvent } from '../queries';
import { processBulk } from '../service/request'; import { processBulk } from '../service/request';
import { applyFavorite } from '../coordinators/favoriteCoordinator';
import { useAdvancedSettingsStore } from './settings/advanced'; import { useAdvancedSettingsStore } from './settings/advanced';
import { useAvatarProviderStore } from './avatarProvider'; import { useAvatarProviderStore } from './avatarProvider';
import { useFavoriteStore } from './favorite'; import { useFavoriteStore } from './favorite';
@@ -114,7 +115,7 @@ export const useAvatarStore = defineStore('Avatar', () => {
listing.displayName = replaceBioSymbols(listing.displayName); listing.displayName = replaceBioSymbols(listing.displayName);
listing.description = replaceBioSymbols(listing.description); listing.description = replaceBioSymbols(listing.description);
} }
favoriteStore.applyFavorite('avatar', ref.id); applyFavorite('avatar', ref.id);
if (favoriteStore.localAvatarFavoritesList.includes(ref.id)) { if (favoriteStore.localAvatarFavoritesList.includes(ref.id)) {
const avatarRef = ref; const avatarRef = ref;
favoriteStore.syncLocalAvatarFavoriteRef(avatarRef); favoriteStore.syncLocalAvatarFavoriteRef(avatarRef);
+22 -1188
View File
File diff suppressed because it is too large Load Diff
+7 -8
View File
@@ -3,8 +3,6 @@ import { defineStore } from 'pinia';
import { database } from '../service/database'; import { database } from '../service/database';
import { useFriendStore } from './friend'; import { useFriendStore } from './friend';
import { useNotificationStore } from './notification';
import { useSharedFeedStore } from './sharedFeed';
import { useVrcxStore } from './vrcx'; import { useVrcxStore } from './vrcx';
import { watchState } from '../service/watchState'; import { watchState } from '../service/watchState';
@@ -12,9 +10,7 @@ import configRepository from '../service/config';
export const useFeedStore = defineStore('Feed', () => { export const useFeedStore = defineStore('Feed', () => {
const friendStore = useFriendStore(); const friendStore = useFriendStore();
const notificationStore = useNotificationStore();
const vrcxStore = useVrcxStore(); const vrcxStore = useVrcxStore();
const sharedFeedStore = useSharedFeedStore();
const feedTableData = shallowRef([]); const feedTableData = shallowRef([]);
const feedTable = ref({ const feedTable = ref({
@@ -170,9 +166,12 @@ export const useFeedStore = defineStore('Feed', () => {
} }
} }
function addFeed(feed) { /**
notificationStore.queueFeedNoty(feed); * Appends a feed entry to the local table if it passes filters.
sharedFeedStore.addEntry(feed); * Does NOT trigger notifications or shared feed — that is the caller's responsibility.
* @param {object} feed The feed entry to add.
*/
function addFeedEntry(feed) {
if ( if (
feedTable.value.filter.length > 0 && feedTable.value.filter.length > 0 &&
!feedTable.value.filter.includes(feed.type) !feedTable.value.filter.includes(feed.type)
@@ -222,6 +221,6 @@ export const useFeedStore = defineStore('Feed', () => {
feedTableData, feedTableData,
initFeedTable, initFeedTable,
feedTableLookup, feedTableLookup,
addFeed addFeedEntry
}; };
}); });
+38 -208
View File
@@ -1,38 +1,9 @@
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { toast } from 'vue-sonner';
import {
deleteVRChatCache as _deleteVRChatCache,
isRealInstance
} from '../shared/utils';
import { database } from '../service/database';
import { runGameRunningChangedFlow } from '../coordinators/gameCoordinator';
import { useAdvancedSettingsStore } from './settings/advanced';
import { useAvatarStore } from './avatar';
import { useGameLogStore } from './gameLog';
import { useLaunchStore } from './launch';
import { useLocationStore } from './location';
import { useModalStore } from './modal';
import { useNotificationStore } from './notification';
import { useVrStore } from './vr';
import { useWorldStore } from './world';
import configRepository from '../service/config.js'; import configRepository from '../service/config.js';
import * as workerTimers from 'worker-timers';
export const useGameStore = defineStore('Game', () => { export const useGameStore = defineStore('Game', () => {
const advancedSettingsStore = useAdvancedSettingsStore();
const locationStore = useLocationStore();
const notificationStore = useNotificationStore();
const avatarStore = useAvatarStore();
const launchStore = useLaunchStore();
const worldStore = useWorldStore();
const gameLogStore = useGameLogStore();
const vrStore = useVrStore();
const modalStore = useModalStore();
const state = reactive({ const state = reactive({
lastCrashedTime: null lastCrashedTime: null
}); });
@@ -60,139 +31,13 @@ export const useGameStore = defineStore('Game', () => {
init(); init();
/** // --- Atomic setters ---
* @param {object} ref Avatar or world reference payload.
*/
async function deleteVRChatCache(ref) {
await _deleteVRChatCache(ref);
getVRChatCacheSize();
worldStore.updateVRChatWorldCache();
avatarStore.updateVRChatAvatarCache();
}
/** /**
* * @param {boolean} value Game running flag.
*/ */
function autoVRChatCacheManagement() { function setIsGameRunning(value) {
if (advancedSettingsStore.autoSweepVRChatCache) { isGameRunning.value = value;
sweepVRChatCache();
}
}
/**
*
*/
async function sweepVRChatCache() {
try {
const output = await AssetBundleManager.SweepCache();
console.log('SweepCache', output);
} catch (e) {
console.error('SweepCache failed', e);
}
if (advancedSettingsStore.isVRChatConfigDialogVisible) {
getVRChatCacheSize();
}
}
/**
*
*/
function checkIfGameCrashed() {
if (!advancedSettingsStore.relaunchVRChatAfterCrash) {
return;
}
const { location } = locationStore.lastLocation;
AppApi.VrcClosedGracefully().then((result) => {
if (result || !isRealInstance(location)) {
return;
}
// check if relaunched less than 2mins ago (prvent crash loop)
if (
state.lastCrashedTime &&
new Date().getTime() - state.lastCrashedTime.getTime() < 120_000
) {
console.log('VRChat was recently crashed, not relaunching');
return;
}
state.lastCrashedTime = new Date();
// wait a bit for SteamVR to potentially close before deciding to relaunch
let restartDelay = 8000;
if (isGameNoVR.value) {
// wait for game to close before relaunching
restartDelay = 2000;
}
workerTimers.setTimeout(
() => restartCrashedGame(location),
restartDelay
);
});
}
/**
* @param {string} location Last known location to relaunch.
*/
function restartCrashedGame(location) {
if (!isGameNoVR.value && !isSteamVRRunning.value) {
console.log("SteamVR isn't running, not relaunching VRChat");
return;
}
AppApi.FocusWindow();
const message = 'VRChat crashed, attempting to rejoin last instance';
toast(message);
const entry = {
created_at: new Date().toJSON(),
type: 'Event',
data: message
};
database.addGamelogEventToDatabase(entry);
notificationStore.queueGameLogNoty(entry);
gameLogStore.addGameLog(entry);
launchStore.launchGame(location, '', isGameNoVR.value);
}
/**
*
*/
async function getVRChatCacheSize() {
VRChatCacheSizeLoading.value = true;
const totalCacheSize = 30;
VRChatTotalCacheSize.value = totalCacheSize;
const usedCacheSize = await AssetBundleManager.GetCacheSize();
VRChatUsedCacheSize.value = (usedCacheSize / 1073741824).toFixed(2);
VRChatCacheSizeLoading.value = false;
}
// use in C#
/**
* @param {boolean} isGameRunningArg Game running flag from IPC.
* @param {boolean} isSteamVRRunningArg SteamVR running flag from IPC.
*/
async function updateIsGameRunning(isGameRunningArg, isSteamVRRunningArg) {
if (advancedSettingsStore.gameLogDisabled) {
return;
}
if (isGameRunningArg !== isGameRunning.value) {
isGameRunning.value = isGameRunningArg;
await runGameRunningChangedFlow(isGameRunningArg);
console.log(new Date(), 'isGameRunning', isGameRunningArg);
}
if (isSteamVRRunningArg !== isSteamVRRunning.value) {
isSteamVRRunning.value = isSteamVRRunningArg;
console.log('isSteamVRRunning:', isSteamVRRunningArg);
}
vrStore.updateOpenVR();
}
// use in C#
/**
* @param {boolean} isHmdAfkArg HMD AFK flag from VR polling.
*/
function updateIsHmdAfk(isHmdAfkArg) {
if (isHmdAfkArg !== isHmdAfk.value) {
isHmdAfk.value = isHmdAfkArg;
console.log('isHmdAfk', isHmdAfkArg);
}
} }
/** /**
@@ -203,50 +48,38 @@ export const useGameStore = defineStore('Game', () => {
} }
/** /**
* * @param {boolean} value SteamVR running flag.
*/ */
async function checkVRChatDebugLogging() { function setIsSteamVRRunning(value) {
if (advancedSettingsStore.gameLogDisabled) { isSteamVRRunning.value = value;
return;
} }
try {
const loggingEnabled = /**
await getVRChatRegistryKey('LOGGING_ENABLED'); * @param {boolean} value HMD AFK flag.
if ( */
loggingEnabled === null || function setIsHmdAfk(value) {
typeof loggingEnabled === 'undefined' isHmdAfk.value = value;
) {
// key not found
return;
} }
if (parseInt(loggingEnabled, 10) === 1) {
// already enabled /**
return; * @param {Date | null} value Last crashed time.
} */
const result = await AppApi.SetVRChatRegistryKey( function setLastCrashedTime(value) {
'LOGGING_ENABLED', state.lastCrashedTime = value;
'1',
4
);
if (!result) {
// failed to set key
modalStore.alert({
description:
'VRCX has noticed VRChat debug logging is disabled. VRCX requires debug logging in order to function correctly. Please enable debug logging in VRChat quick menu settings > debug > enable debug logging, then rejoin the instance or restart VRChat.',
title: 'Enable debug logging'
});
console.error('Failed to enable debug logging', result);
return;
}
modalStore.alert({
description:
'VRCX has noticed VRChat debug logging is disabled and automatically re-enabled it. VRCX requires debug logging in order to function correctly.',
title: 'Enabled debug logging'
});
console.log('Enabled debug logging');
} catch (e) {
console.error(e);
} }
// --- Self-contained operations (no cross-store deps) ---
/**
* Fetches VRChat cache size from AssetBundleManager.
*/
async function getVRChatCacheSize() {
VRChatCacheSizeLoading.value = true;
const totalCacheSize = 30;
VRChatTotalCacheSize.value = totalCacheSize;
const usedCacheSize = await AssetBundleManager.GetCacheSize();
VRChatUsedCacheSize.value = (usedCacheSize / 1073741824).toFixed(2);
VRChatCacheSizeLoading.value = false;
} }
/** /**
@@ -271,15 +104,12 @@ export const useGameStore = defineStore('Game', () => {
isSteamVRRunning, isSteamVRRunning,
isHmdAfk, isHmdAfk,
deleteVRChatCache, setIsGameRunning,
sweepVRChatCache,
getVRChatCacheSize,
updateIsGameRunning,
setIsGameNoVR, setIsGameNoVR,
getVRChatRegistryKey, setIsSteamVRRunning,
checkVRChatDebugLogging, setIsHmdAfk,
autoVRChatCacheManagement, setLastCrashedTime,
checkIfGameCrashed, getVRChatCacheSize,
updateIsHmdAfk getVRChatRegistryKey
}; };
}); });
+6 -5
View File
@@ -31,6 +31,7 @@ import { useGameStore } from '../game';
import { useGeneralSettingsStore } from '../settings/general'; import { useGeneralSettingsStore } from '../settings/general';
import { useInstanceStore } from '../instance'; import { useInstanceStore } from '../instance';
import { useLocationStore } from '../location'; import { useLocationStore } from '../location';
import { runLastLocationResetFlow, runUpdateCurrentUserLocationFlow } from '../../coordinators/locationCoordinator';
import { useModalStore } from '../modal'; import { useModalStore } from '../modal';
import { useNotificationStore } from '../notification'; import { useNotificationStore } from '../notification';
import { usePhotonStore } from '../photon'; import { usePhotonStore } from '../photon';
@@ -376,7 +377,7 @@ export const useGameLogStore = defineStore('GameLog', () => {
} }
}); });
locationStore.updateCurrentUserLocation(); runUpdateCurrentUserLocationFlow();
instanceStore.updateCurrentInstanceWorld(); instanceStore.updateCurrentInstanceWorld();
vrStore.updateVRLastLocation(); vrStore.updateVRLastLocation();
instanceStore.getCurrentInstanceUserList(); instanceStore.getCurrentInstanceUserList();
@@ -560,7 +561,7 @@ export const useGameLogStore = defineStore('GameLog', () => {
type: 'LocationDestination', type: 'LocationDestination',
location: gameLog.location location: gameLog.location
}); });
locationStore.lastLocationReset(gameLog.dt); runLastLocationResetFlow(gameLog.dt);
locationStore.setLastLocationLocation('traveling'); locationStore.setLastLocationLocation('traveling');
locationStore.setLastLocationDestination(gameLog.location); locationStore.setLastLocationDestination(gameLog.location);
locationStore.setLastLocationDestinationTime( locationStore.setLastLocationDestinationTime(
@@ -568,7 +569,7 @@ export const useGameLogStore = defineStore('GameLog', () => {
); );
state.lastLocationAvatarList.clear(); state.lastLocationAvatarList.clear();
instanceStore.removeQueuedInstance(gameLog.location); instanceStore.removeQueuedInstance(gameLog.location);
locationStore.updateCurrentUserLocation(); runUpdateCurrentUserLocationFlow();
clearNowPlaying(); clearNowPlaying();
instanceStore.updateCurrentInstanceWorld(); instanceStore.updateCurrentInstanceWorld();
userStore.applyUserDialogLocation(); userStore.applyUserDialogLocation();
@@ -583,7 +584,7 @@ export const useGameLogStore = defineStore('GameLog', () => {
); );
const worldName = replaceBioSymbols(gameLog.worldName); const worldName = replaceBioSymbols(gameLog.worldName);
if (gameStore.isGameRunning) { if (gameStore.isGameRunning) {
locationStore.lastLocationReset(gameLog.dt); runLastLocationResetFlow(gameLog.dt);
clearNowPlaying(); clearNowPlaying();
locationStore.setLastLocation({ locationStore.setLastLocation({
date: Date.parse(gameLog.dt), date: Date.parse(gameLog.dt),
@@ -593,7 +594,7 @@ export const useGameLogStore = defineStore('GameLog', () => {
friendList: new Map() friendList: new Map()
}); });
instanceStore.removeQueuedInstance(gameLog.location); instanceStore.removeQueuedInstance(gameLog.location);
locationStore.updateCurrentUserLocation(); runUpdateCurrentUserLocationFlow();
vrStore.updateVRLastLocation(); vrStore.updateVRLastLocation();
instanceStore.updateCurrentInstanceWorld(); instanceStore.updateCurrentInstanceWorld();
userStore.applyUserDialogLocation(); userStore.applyUserDialogLocation();
+2 -39
View File
@@ -1,22 +1,14 @@
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
import { instanceRequest, inviteMessagesRequest } from '../api'; import { inviteMessagesRequest } from '../api';
import { parseLocation } from '../shared/utils';
import { useAdvancedSettingsStore } from './settings/advanced'; import { useAdvancedSettingsStore } from './settings/advanced';
import { useGameStore } from './game'; import { useGameStore } from './game';
import { useInstanceStore } from './instance';
import { useLaunchStore } from './launch';
import { watchState } from '../service/watchState'; import { watchState } from '../service/watchState';
export const useInviteStore = defineStore('Invite', () => { export const useInviteStore = defineStore('Invite', () => {
const instanceStore = useInstanceStore();
const gameStore = useGameStore(); const gameStore = useGameStore();
const launchStore = useLaunchStore();
const advancedSettingsStore = useAdvancedSettingsStore(); const advancedSettingsStore = useAdvancedSettingsStore();
const { t } = useI18n();
const inviteMessageTable = ref({ const inviteMessageTable = ref({
data: [], data: [],
@@ -93,35 +85,7 @@ export const useInviteStore = defineStore('Invite', () => {
}); });
} }
function newInstanceSelfInvite(worldId) {
instanceStore.createNewInstance(worldId).then((args) => {
const location = args?.json?.location;
if (!location) {
toast.error(t('message.instance.create_failed'));
return;
}
// self invite
const L = parseLocation(location);
if (!L.isRealInstance) {
return;
}
if (canOpenInstanceInGame.value) {
const secureOrShortName =
args.json.shortName || args.json.secureName;
launchStore.tryOpenInstanceInVrc(location, secureOrShortName);
return;
}
instanceRequest
.selfInvite({
instanceId: L.instanceId,
worldId: L.worldId
})
.then((args) => {
toast.success(t('message.invite.self_sent'));
return args;
});
});
}
return { return {
inviteMessageTable, inviteMessageTable,
@@ -129,7 +93,6 @@ export const useInviteStore = defineStore('Invite', () => {
inviteRequestMessageTable, inviteRequestMessageTable,
inviteRequestResponseMessageTable, inviteRequestResponseMessageTable,
refreshInviteMessageTableData, refreshInviteMessageTableData,
newInstanceSelfInvite,
canOpenInstanceInGame canOpenInstanceInGame
}; };
}); });
+1 -175
View File
@@ -1,32 +1,7 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { ref } from 'vue'; import { ref } from 'vue';
import {
getGroupName,
getWorldName,
isRealInstance,
parseLocation
} from '../shared/utils';
import { database } from '../service/database';
import { useAdvancedSettingsStore } from './settings/advanced';
import { useGameLogStore } from './gameLog';
import { useGameStore } from './game';
import { useInstanceStore } from './instance';
import { useNotificationStore } from './notification';
import { usePhotonStore } from './photon';
import { useUserStore } from './user';
import { useVrStore } from './vr';
export const useLocationStore = defineStore('Location', () => { export const useLocationStore = defineStore('Location', () => {
const advancedSettingsStore = useAdvancedSettingsStore();
const userStore = useUserStore();
const instanceStore = useInstanceStore();
const notificationStore = useNotificationStore();
const gameStore = useGameStore();
const vrStore = useVrStore();
const photonStore = usePhotonStore();
const gameLogStore = useGameLogStore();
const lastLocation = ref({ const lastLocation = ref({
date: null, date: null,
location: '', location: '',
@@ -37,153 +12,6 @@ export const useLocationStore = defineStore('Location', () => {
const lastLocationDestination = ref(''); const lastLocationDestination = ref('');
const lastLocationDestinationTime = ref(0); const lastLocationDestinationTime = ref(0);
function updateCurrentUserLocation() {
const ref = userStore.cachedUsers.get(userStore.currentUser.id);
if (typeof ref === 'undefined') {
return;
}
// update cached user with both gameLog and API locations
let currentLocation = userStore.currentUser.$locationTag;
const L = parseLocation(currentLocation);
if (L.isTraveling) {
currentLocation = userStore.currentUser.$travelingToLocation;
}
ref.location = userStore.currentUser.$locationTag;
ref.travelingToLocation = userStore.currentUser.$travelingToLocation;
if (
gameStore.isGameRunning &&
!advancedSettingsStore.gameLogDisabled &&
lastLocation.value.location !== ''
) {
// use gameLog instead of API when game is running
currentLocation = lastLocation.value.location;
if (lastLocation.value.location === 'traveling') {
currentLocation = lastLocationDestination.value;
}
ref.location = lastLocation.value.location;
ref.travelingToLocation = lastLocationDestination.value;
}
ref.$online_for = userStore.currentUser.$online_for;
ref.$offline_for = userStore.currentUser.$offline_for;
ref.$location = parseLocation(currentLocation);
if (!gameStore.isGameRunning || advancedSettingsStore.gameLogDisabled) {
ref.$location_at = userStore.currentUser.$location_at;
ref.$travelingToTime = userStore.currentUser.$travelingToTime;
userStore.applyUserDialogLocation();
instanceStore.applyWorldDialogInstances();
instanceStore.applyGroupDialogInstances();
} else {
ref.$location_at = lastLocation.value.date;
ref.$travelingToTime = lastLocationDestinationTime.value;
userStore.setCurrentUserTravelingToTime(
lastLocationDestinationTime.value
);
}
}
async function setCurrentUserLocation(location, travelingToLocation) {
userStore.setCurrentUserLocationState(location, travelingToLocation);
updateCurrentUserLocation();
// janky gameLog support for Quest
if (gameStore.isGameRunning) {
// with the current state of things, lets not run this if we don't need to
return;
}
const lastLocationArray = await database.lookupGameLogDatabase(
['Location'],
[],
1
);
const lastLocationTemp =
lastLocationArray.length > 0 ? lastLocationArray[0].location : '';
if (lastLocationTemp === location) {
return;
}
lastLocationDestination.value = '';
lastLocationDestinationTime.value = 0;
if (isRealInstance(location)) {
const dt = new Date().toJSON();
const L = parseLocation(location);
lastLocation.value.location = location;
lastLocation.value.date = Date.now();
const entry = {
created_at: dt,
type: 'Location',
location,
worldId: L.worldId,
worldName: await getWorldName(L.worldId),
groupName: await getGroupName(L.groupId),
time: 0
};
database.addGamelogLocationToDatabase(entry);
notificationStore.queueGameLogNoty(entry);
gameLogStore.addGameLog(entry);
instanceStore.addInstanceJoinHistory(location, dt);
userStore.applyUserDialogLocation();
instanceStore.applyWorldDialogInstances();
instanceStore.applyGroupDialogInstances();
} else {
lastLocation.value.location = '';
lastLocation.value.date = null;
}
}
function lastLocationReset(gameLogDate) {
let dateTime = gameLogDate;
if (!gameLogDate) {
dateTime = new Date().toJSON();
}
const dateTimeStamp = Date.parse(dateTime);
photonStore.resetLocationPhotonState();
const playerList = Array.from(lastLocation.value.playerList.values());
const dataBaseEntries = [];
for (const ref of playerList) {
const entry = {
created_at: dateTime,
type: 'OnPlayerLeft',
displayName: ref.displayName,
location: lastLocation.value.location,
userId: ref.userId,
time: dateTimeStamp - ref.joinTime
};
dataBaseEntries.unshift(entry);
gameLogStore.addGameLog(entry);
}
database.addGamelogJoinLeaveBulk(dataBaseEntries);
if (lastLocation.value.date !== null && lastLocation.value.date > 0) {
const update = {
time: dateTimeStamp - lastLocation.value.date,
created_at: new Date(lastLocation.value.date).toJSON()
};
database.updateGamelogLocationTimeToDatabase(update);
}
lastLocationDestination.value = '';
lastLocationDestinationTime.value = 0;
lastLocation.value = {
date: 0,
location: '',
name: '',
playerList: new Map(),
friendList: new Map()
};
updateCurrentUserLocation();
instanceStore.updateCurrentInstanceWorld();
vrStore.updateVRLastLocation();
instanceStore.getCurrentInstanceUserList();
gameLogStore.resetLastMediaUrls();
userStore.applyUserDialogLocation();
instanceStore.applyWorldDialogInstances();
instanceStore.applyGroupDialogInstances();
}
/** /**
* @param {{date: number|null, location: string, name: string, playerList: Map<any, any>, friendList: Map<any, any>}} value * @param {{date: number|null, location: string, name: string, playerList: Map<any, any>, friendList: Map<any, any>}} value
*/ */
@@ -216,12 +44,10 @@ export const useLocationStore = defineStore('Location', () => {
lastLocation, lastLocation,
lastLocationDestination, lastLocationDestination,
lastLocationDestinationTime, lastLocationDestinationTime,
updateCurrentUserLocation,
setCurrentUserLocation,
lastLocationReset,
setLastLocation, setLastLocation,
setLastLocationLocation, setLastLocationLocation,
setLastLocationDestination, setLastLocationDestination,
setLastLocationDestinationTime setLastLocationDestinationTime
}; };
}); });
+4 -42
View File
@@ -1,13 +1,11 @@
import { reactive, ref, watch } from 'vue'; import { reactive, ref, watch } from 'vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { avatarModerationRequest, playerModerationRequest } from '../api'; import { playerModerationRequest } from '../api';
import { useAvatarStore } from './avatar';
import { useUserStore } from './user'; import { useUserStore } from './user';
import { watchState } from '../service/watchState'; import { watchState } from '../service/watchState';
export const useModerationStore = defineStore('Moderation', () => { export const useModerationStore = defineStore('Moderation', () => {
const avatarStore = useAvatarStore();
const userStore = useUserStore(); const userStore = useUserStore();
const cachedPlayerModerations = reactive(new Map()); const cachedPlayerModerations = reactive(new Map());
@@ -37,9 +35,6 @@ export const useModerationStore = defineStore('Moderation', () => {
cachedPlayerModerationsUserIds.clear(); cachedPlayerModerationsUserIds.clear();
playerModerationTable.value.loading = false; playerModerationTable.value.loading = false;
playerModerationTable.value.data = []; playerModerationTable.value.data = [];
if (isLoggedIn) {
refreshPlayerModerations();
}
}, },
{ flush: 'sync' } { flush: 'sync' }
); );
@@ -178,41 +173,7 @@ export const useModerationStore = defineStore('Moderation', () => {
} }
} }
async function refreshPlayerModerations() {
if (playerModerationTable.value.loading) {
return;
}
playerModerationTable.value.loading = true;
expirePlayerModerations();
Promise.all([
playerModerationRequest.getPlayerModerations(),
avatarModerationRequest.getAvatarModerations()
])
.finally(() => {
playerModerationTable.value.loading = false;
})
.then((res) => {
// TODO: compare with cachedAvatarModerations
avatarStore.resetCachedAvatarModerations();
if (res[1]?.json) {
for (const json of res[1].json) {
avatarStore.applyAvatarModeration(json);
}
}
if (res[0]?.json) {
for (let json of res[0].json) {
applyPlayerModeration(json);
}
}
deleteExpiredPlayerModerations();
})
.catch((error) => {
console.error(
'Failed to load player/avatar moderations:',
error
);
});
}
/** /**
* Get user moderations * Get user moderations
@@ -257,7 +218,8 @@ export const useModerationStore = defineStore('Moderation', () => {
cachedPlayerModerationsUserIds, cachedPlayerModerationsUserIds,
playerModerationTable, playerModerationTable,
refreshPlayerModerations, expirePlayerModerations,
deleteExpiredPlayerModerations,
applyPlayerModeration, applyPlayerModeration,
handlePlayerModerationDelete, handlePlayerModerationDelete,
getUserModerations getUserModerations
+2
View File
@@ -1,3 +1,5 @@
// @deprecated
// This store is no longer maintained.
import { computed, reactive, ref } from 'vue'; import { computed, reactive, ref } from 'vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
+4 -2
View File
@@ -4,6 +4,8 @@ import { watch } from 'vue';
import { database } from '../service/database'; import { database } from '../service/database';
import { groupRequest } from '../api'; import { groupRequest } from '../api';
import { runRefreshFriendsListFlow } from '../coordinators/friendSyncCoordinator'; import { runRefreshFriendsListFlow } from '../coordinators/friendSyncCoordinator';
import { runUpdateIsGameRunningFlow } from '../coordinators/gameCoordinator';
import { runRefreshPlayerModerationsFlow } from '../coordinators/moderationCoordinator';
import { useAuthStore } from './auth'; import { useAuthStore } from './auth';
import { useDiscordPresenceSettingsStore } from './settings/discordPresence'; import { useDiscordPresenceSettingsStore } from './settings/discordPresence';
import { useFriendStore } from './friend'; import { useFriendStore } from './friend';
@@ -82,7 +84,7 @@ export const useUpdateLoopStore = defineStore('UpdateLoop', () => {
new Date(userStore.currentUser.last_activity) > new Date(userStore.currentUser.last_activity) >
new Date(Date.now() - 3600 * 1000) // 1hour new Date(Date.now() - 3600 * 1000) // 1hour
) { ) {
moderationStore.refreshPlayerModerations(); runRefreshPlayerModerationsFlow();
} }
} }
if (--state.nextGroupInstanceRefresh <= 0) { if (--state.nextGroupInstanceRefresh <= 0) {
@@ -133,7 +135,7 @@ export const useUpdateLoopStore = defineStore('UpdateLoop', () => {
} }
if (LINUX && --state.nextGameRunningCheck <= 0) { if (LINUX && --state.nextGameRunningCheck <= 0) {
state.nextGameRunningCheck = 1; state.nextGameRunningCheck = 1;
gameStore.updateIsGameRunning( await runUpdateIsGameRunningFlow(
await AppApi.IsGameRunning(), await AppApi.IsGameRunning(),
await AppApi.IsSteamVRRunning() await AppApi.IsSteamVRRunning()
); );
+5 -3
View File
@@ -41,7 +41,9 @@ import { AppDebug } from '../service/appConfig';
import { database } from '../service/database'; import { database } from '../service/database';
import { patchUserFromEvent } from '../queries'; import { patchUserFromEvent } from '../queries';
import { runHandleUserUpdateFlow } from '../coordinators/userEventCoordinator'; import { runHandleUserUpdateFlow } from '../coordinators/userEventCoordinator';
import { runUpdateCurrentUserLocationFlow } from '../coordinators/locationCoordinator';
import { runUpdateFriendFlow } from '../coordinators/friendPresenceCoordinator'; import { runUpdateFriendFlow } from '../coordinators/friendPresenceCoordinator';
import { applyFavorite } from '../coordinators/favoriteCoordinator';
import { useAppearanceSettingsStore } from './settings/appearance'; import { useAppearanceSettingsStore } from './settings/appearance';
import { useAuthStore } from './auth'; import { useAuthStore } from './auth';
import { useAvatarStore } from './avatar'; import { useAvatarStore } from './avatar';
@@ -424,7 +426,7 @@ export const useUserStore = defineStore('User', () => {
} else { } else {
ref.$travelingToLocation = presence.travelingToWorld; ref.$travelingToLocation = presence.travelingToWorld;
} }
locationStore.updateCurrentUserLocation(); runUpdateCurrentUserLocationFlow();
} }
const robotUrl = `${AppDebug.endpointDomain}/file/file_0e8c4e32-7444-44ea-ade4-313c010d4bae/1/file`; const robotUrl = `${AppDebug.endpointDomain}/file/file_0e8c4e32-7444-44ea-ade4-313c010d4bae/1/file`;
@@ -546,7 +548,7 @@ export const useUserStore = defineStore('User', () => {
if (ref.status) { if (ref.status) {
currentUser.value.status = ref.status; currentUser.value.status = ref.status;
} }
locationStore.updateCurrentUserLocation(); runUpdateCurrentUserLocationFlow();
} }
// add user ref to playerList, friendList, photonLobby, photonLobbyCurrent // add user ref to playerList, friendList, photonLobby, photonLobbyCurrent
const playerListRef = locationStore.lastLocation.playerList.get(ref.id); const playerListRef = locationStore.lastLocation.playerList.get(ref.id);
@@ -586,7 +588,7 @@ export const useUserStore = defineStore('User', () => {
if (ref.state === 'online') { if (ref.state === 'online') {
runUpdateFriendFlow(ref.id, ref.state); // online/offline runUpdateFriendFlow(ref.id, ref.state); // online/offline
} }
favoriteStore.applyFavorite('friend', ref.id); applyFavorite('friend', ref.id);
friendStore.userOnFriend(ref); friendStore.userOnFriend(ref);
const D = userDialog.value; const D = userDialog.value;
if (D.visible && D.id === ref.id) { if (D.visible && D.id === ref.id) {
+1 -1
View File
@@ -181,7 +181,7 @@ export const useVrStore = defineStore('Vr', () => {
newState.overlayHand newState.overlayHand
); );
if (!newState.active) { if (!newState.active) {
gameStore.updateIsHmdAfk(false); gameStore.setIsHmdAfk(false);
} }
if (LINUX) { if (LINUX) {
+6 -2
View File
@@ -22,6 +22,10 @@ import { refreshCustomScript } from '../shared/utils/base/ui';
import { useAdvancedSettingsStore } from './settings/advanced'; import { useAdvancedSettingsStore } from './settings/advanced';
import { useAvatarProviderStore } from './avatarProvider'; import { useAvatarProviderStore } from './avatarProvider';
import { useAvatarStore } from './avatar'; import { useAvatarStore } from './avatar';
import {
addLocalWorldFavorite,
addLocalAvatarFavorite
} from '../coordinators/favoriteCoordinator';
import { useFavoriteStore } from './favorite'; import { useFavoriteStore } from './favorite';
import { useFriendStore } from './friend'; import { useFriendStore } from './friend';
import { useGalleryStore } from './gallery'; import { useGalleryStore } from './gallery';
@@ -686,7 +690,7 @@ export const useVrcxStore = defineStore('Vrcx', () => {
} }
queryRequest.fetch('world', { worldId: id }).then(() => { queryRequest.fetch('world', { worldId: id }).then(() => {
searchStore.directAccessWorld(id); searchStore.directAccessWorld(id);
favoriteStore.addLocalWorldFavorite(id, group); addLocalWorldFavorite(id, group);
}); });
break; break;
case 'local-favorite-avatar': case 'local-favorite-avatar':
@@ -698,7 +702,7 @@ export const useVrcxStore = defineStore('Vrcx', () => {
} }
avatarRequest.getAvatar({ avatarId: avatarIdFav }).then(() => { avatarRequest.getAvatar({ avatarId: avatarIdFav }).then(() => {
avatarStore.showAvatarDialog(avatarIdFav); avatarStore.showAvatarDialog(avatarIdFav);
favoriteStore.addLocalAvatarFavorite( addLocalAvatarFavorite(
avatarIdFav, avatarIdFav,
avatarGroup avatarGroup
); );
+2 -1
View File
@@ -18,6 +18,7 @@ import { instanceRequest, queryRequest, worldRequest } from '../api';
import { database } from '../service/database'; import { database } from '../service/database';
import { patchWorldFromEvent } from '../queries'; import { patchWorldFromEvent } from '../queries';
import { processBulk } from '../service/request'; import { processBulk } from '../service/request';
import { applyFavorite } from '../coordinators/favoriteCoordinator';
import { useFavoriteStore } from './favorite'; import { useFavoriteStore } from './favorite';
import { useInstanceStore } from './instance'; import { useInstanceStore } from './instance';
import { useLocationStore } from './location'; import { useLocationStore } from './location';
@@ -275,7 +276,7 @@ export const useWorldStore = defineStore('World', () => {
Object.assign(ref, json); Object.assign(ref, json);
} }
ref.$isLabs = ref.tags.includes('system_labs'); ref.$isLabs = ref.tags.includes('system_labs');
favoriteStore.applyFavorite('world', ref.id); applyFavorite('world', ref.id);
const userDialog = userStore.userDialog; const userDialog = userStore.userDialog;
if (userDialog.visible && userDialog.$location.worldId === ref.id) { if (userDialog.visible && userDialog.$location.worldId === ref.id) {
userStore.applyUserDialogLocation(); userStore.applyUserDialogLocation();
+10 -8
View File
@@ -463,6 +463,15 @@
import { useFavoritesGroupPanel } from './composables/useFavoritesGroupPanel.js'; import { useFavoritesGroupPanel } from './composables/useFavoritesGroupPanel.js';
import { useFavoritesLocalGroups } from './composables/useFavoritesLocalGroups.js'; import { useFavoritesLocalGroups } from './composables/useFavoritesLocalGroups.js';
import { useFavoritesSplitter } from './composables/useFavoritesSplitter.js'; import { useFavoritesSplitter } from './composables/useFavoritesSplitter.js';
import {
deleteLocalAvatarFavoriteGroup,
renameLocalAvatarFavoriteGroup,
newLocalAvatarFavoriteGroup,
refreshFavorites,
getLocalAvatarFavorites,
checkInvalidLocalAvatars,
removeInvalidLocalAvatars
} from '../../coordinators/favoriteCoordinator';
import AvatarExportDialog from './dialogs/AvatarExportDialog.vue'; import AvatarExportDialog from './dialogs/AvatarExportDialog.vue';
import FavoritesAvatarItem from './components/FavoritesAvatarItem.vue'; import FavoritesAvatarItem from './components/FavoritesAvatarItem.vue';
@@ -506,15 +515,8 @@
const { const {
showAvatarImportDialog, showAvatarImportDialog,
localAvatarFavGroupLength, localAvatarFavGroupLength,
deleteLocalAvatarFavoriteGroup,
renameLocalAvatarFavoriteGroup,
newLocalAvatarFavoriteGroup,
localAvatarFavoritesList, localAvatarFavoritesList,
refreshFavorites, handleFavoriteGroup
getLocalAvatarFavorites,
handleFavoriteGroup,
checkInvalidLocalAvatars,
removeInvalidLocalAvatars
} = favoriteStore; } = favoriteStore;
const { avatarHistory } = storeToRefs(useAvatarStore()); const { avatarHistory } = storeToRefs(useAvatarStore());
const { promptClearAvatarHistory, showAvatarDialog, applyAvatar } = useAvatarStore(); const { promptClearAvatarHistory, showAvatarDialog, applyAvatar } = useAvatarStore();
+9 -7
View File
@@ -356,6 +356,14 @@
import { useFavoritesGroupPanel } from './composables/useFavoritesGroupPanel.js'; import { useFavoritesGroupPanel } from './composables/useFavoritesGroupPanel.js';
import { useFavoritesLocalGroups } from './composables/useFavoritesLocalGroups.js'; import { useFavoritesLocalGroups } from './composables/useFavoritesLocalGroups.js';
import { useFavoritesSplitter } from './composables/useFavoritesSplitter.js'; import { useFavoritesSplitter } from './composables/useFavoritesSplitter.js';
import {
refreshFavorites,
getLocalWorldFavorites,
getLocalFriendFavorites,
deleteLocalFriendFavoriteGroup,
renameLocalFriendFavoriteGroup,
removeLocalFriendFavorite
} from '../../coordinators/favoriteCoordinator';
import FavoritesContentHeader from './components/FavoritesContentHeader.vue'; import FavoritesContentHeader from './components/FavoritesContentHeader.vue';
import FavoritesFriendItem from './components/FavoritesFriendItem.vue'; import FavoritesFriendItem from './components/FavoritesFriendItem.vue';
@@ -390,15 +398,9 @@
} = storeToRefs(favoriteStore); } = storeToRefs(favoriteStore);
const { const {
showFriendImportDialog, showFriendImportDialog,
refreshFavorites,
getLocalWorldFavorites,
getLocalFriendFavorites,
handleFavoriteGroup, handleFavoriteGroup,
localFriendFavGroupLength, localFriendFavGroupLength,
deleteLocalFriendFavoriteGroup, newLocalFriendFavoriteGroup
renameLocalFriendFavoriteGroup,
newLocalFriendFavoriteGroup,
removeLocalFriendFavorite
} = favoriteStore; } = favoriteStore;
const userStore = useUserStore(); const userStore = useUserStore();
const { showUserDialog } = userStore; const { showUserDialog } = userStore;
+8 -6
View File
@@ -395,6 +395,13 @@
import { useFavoritesGroupPanel } from './composables/useFavoritesGroupPanel.js'; import { useFavoritesGroupPanel } from './composables/useFavoritesGroupPanel.js';
import { useFavoritesLocalGroups } from './composables/useFavoritesLocalGroups.js'; import { useFavoritesLocalGroups } from './composables/useFavoritesLocalGroups.js';
import { useFavoritesSplitter } from './composables/useFavoritesSplitter.js'; import { useFavoritesSplitter } from './composables/useFavoritesSplitter.js';
import {
renameLocalWorldFavoriteGroup,
removeLocalWorldFavorite,
newLocalWorldFavoriteGroup,
refreshFavorites,
getLocalWorldFavorites
} from '../../coordinators/favoriteCoordinator';
import FavoritesContentHeader from './components/FavoritesContentHeader.vue'; import FavoritesContentHeader from './components/FavoritesContentHeader.vue';
import FavoritesToolbar from './components/FavoritesToolbar.vue'; import FavoritesToolbar from './components/FavoritesToolbar.vue';
@@ -426,13 +433,8 @@
showWorldImportDialog, showWorldImportDialog,
localWorldFavGroupLength, localWorldFavGroupLength,
deleteLocalWorldFavoriteGroup, deleteLocalWorldFavoriteGroup,
renameLocalWorldFavoriteGroup,
removeLocalWorldFavorite,
newLocalWorldFavoriteGroup,
handleFavoriteGroup, handleFavoriteGroup,
localWorldFavoritesList, localWorldFavoritesList
refreshFavorites,
getLocalWorldFavorites
} = favoriteStore; } = favoriteStore;
const { showWorldDialog } = useWorldStore(); const { showWorldDialog } = useWorldStore();
@@ -152,6 +152,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useAvatarStore, useFavoriteStore, useUiStore, useUserStore } from '../../../stores'; import { useAvatarStore, useFavoriteStore, useUiStore, useUserStore } from '../../../stores';
import { removeLocalAvatarFavorite } from '../../../coordinators/favoriteCoordinator';
import { favoriteRequest } from '../../../api'; import { favoriteRequest } from '../../../api';
import FavoritesMoveDropdown from './FavoritesMoveDropdown.vue'; import FavoritesMoveDropdown from './FavoritesMoveDropdown.vue';
@@ -168,7 +169,7 @@
const { t } = useI18n(); const { t } = useI18n();
const { favoriteAvatarGroups } = storeToRefs(useFavoriteStore()); const { favoriteAvatarGroups } = storeToRefs(useFavoriteStore());
const { removeLocalAvatarFavorite, showFavoriteDialog } = useFavoriteStore(); const { showFavoriteDialog } = useFavoriteStore();
const { selectAvatarWithConfirmation } = useAvatarStore(); const { selectAvatarWithConfirmation } = useAvatarStore();
const { shiftHeld } = storeToRefs(useUiStore()); const { shiftHeld } = storeToRefs(useUiStore());
const { currentUser } = storeToRefs(useUserStore()); const { currentUser } = storeToRefs(useUserStore());
@@ -91,6 +91,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { favoriteRequest } from '../../../api'; import { favoriteRequest } from '../../../api';
import { removeLocalFriendFavorite } from '../../../coordinators/favoriteCoordinator';
import { useFavoriteStore } from '../../../stores'; import { useFavoriteStore } from '../../../stores';
import { userImage } from '../../../shared/utils'; import { userImage } from '../../../shared/utils';
@@ -106,7 +107,7 @@
const emit = defineEmits(['click', 'toggle-select']); const emit = defineEmits(['click', 'toggle-select']);
const { favoriteFriendGroups } = storeToRefs(useFavoriteStore()); const { favoriteFriendGroups } = storeToRefs(useFavoriteStore());
const { showFavoriteDialog, removeLocalFriendFavorite } = useFavoriteStore(); const { showFavoriteDialog } = useFavoriteStore();
const { t } = useI18n(); const { t } = useI18n();
const isSelected = computed({ const isSelected = computed({
@@ -166,6 +166,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useFavoriteStore, useInstanceStore, useInviteStore, useUiStore } from '../../../stores'; import { useFavoriteStore, useInstanceStore, useInviteStore, useUiStore } from '../../../stores';
import { runNewInstanceSelfInviteFlow as newInstanceSelfInvite } from '../../../coordinators/inviteCoordinator';
import { favoriteRequest } from '../../../api'; import { favoriteRequest } from '../../../api';
import FavoritesMoveDropdown from './FavoritesMoveDropdown.vue'; import FavoritesMoveDropdown from './FavoritesMoveDropdown.vue';
@@ -181,7 +182,7 @@
const emit = defineEmits(['toggle-select', 'remove-local-world-favorite', 'click']); const emit = defineEmits(['toggle-select', 'remove-local-world-favorite', 'click']);
const { favoriteWorldGroups } = storeToRefs(useFavoriteStore()); const { favoriteWorldGroups } = storeToRefs(useFavoriteStore());
const { showFavoriteDialog } = useFavoriteStore(); const { showFavoriteDialog } = useFavoriteStore();
const { newInstanceSelfInvite } = useInviteStore();
const { t } = useI18n(); const { t } = useI18n();
const { canOpenInstanceInGame } = useInviteStore(); const { canOpenInstanceInGame } = useInviteStore();
const { shiftHeld } = storeToRefs(useUiStore()); const { shiftHeld } = storeToRefs(useUiStore());
@@ -130,6 +130,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useFavoriteStore, useInstanceStore, useInviteStore, useUiStore } from '../../../stores'; import { useFavoriteStore, useInstanceStore, useInviteStore, useUiStore } from '../../../stores';
import { runNewInstanceSelfInviteFlow as newInstanceSelfInvite } from '../../../coordinators/inviteCoordinator';
import FavoritesMoveDropdown from './FavoritesMoveDropdown.vue'; import FavoritesMoveDropdown from './FavoritesMoveDropdown.vue';
@@ -142,7 +143,7 @@
const emit = defineEmits(['remove-local-world-favorite', 'click']); const emit = defineEmits(['remove-local-world-favorite', 'click']);
const { favoriteWorldGroups } = storeToRefs(useFavoriteStore()); const { favoriteWorldGroups } = storeToRefs(useFavoriteStore());
const { showFavoriteDialog } = useFavoriteStore(); const { showFavoriteDialog } = useFavoriteStore();
const { newInstanceSelfInvite } = useInviteStore();
const { shiftHeld } = storeToRefs(useUiStore()); const { shiftHeld } = storeToRefs(useUiStore());
const { t } = useI18n(); const { t } = useI18n();
const { canOpenInstanceInGame } = useInviteStore(); const { canOpenInstanceInGame } = useInviteStore();
@@ -11,9 +11,13 @@ const mocks = vi.hoisted(() => ({
createNewInstance: vi.fn() createNewInstance: vi.fn()
})); }));
vi.mock('pinia', () => ({ vi.mock('pinia', async (importOriginal) => {
const actual = await importOriginal();
return {
...actual,
storeToRefs: (store) => store storeToRefs: (store) => store
})); };
});
vi.mock('vue-i18n', () => ({ vi.mock('vue-i18n', () => ({
useI18n: () => ({ useI18n: () => ({
@@ -123,6 +123,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useAvatarStore, useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores'; import { useAvatarStore, useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores';
import { addLocalAvatarFavorite } from '../../../coordinators/favoriteCoordinator';
import { avatarRequest, favoriteRequest } from '../../../api'; import { avatarRequest, favoriteRequest } from '../../../api';
import { createColumns } from './avatarImportColumns.jsx'; import { createColumns } from './avatarImportColumns.jsx';
import { removeFromArray } from '../../../shared/utils'; import { removeFromArray } from '../../../shared/utils';
@@ -133,7 +134,7 @@
const { showUserDialog } = useUserStore(); const { showUserDialog } = useUserStore();
const { favoriteAvatarGroups, avatarImportDialogInput, avatarImportDialogVisible, localAvatarFavoriteGroups } = const { favoriteAvatarGroups, avatarImportDialogInput, avatarImportDialogVisible, localAvatarFavoriteGroups } =
storeToRefs(useFavoriteStore()); storeToRefs(useFavoriteStore());
const { addLocalAvatarFavorite, localAvatarFavGroupLength, getCachedFavoritesByObjectId } = useFavoriteStore(); const { localAvatarFavGroupLength, getCachedFavoritesByObjectId } = useFavoriteStore();
const { showAvatarDialog, applyAvatar } = useAvatarStore(); const { showAvatarDialog, applyAvatar } = useAvatarStore();
const { showFullscreenImageDialog } = useGalleryStore(); const { showFullscreenImageDialog } = useGalleryStore();
@@ -127,6 +127,7 @@
import { removeFromArray, userImage, userImageFull } from '../../../shared/utils'; import { removeFromArray, userImage, userImageFull } from '../../../shared/utils';
import { useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores'; import { useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores';
import { addLocalFriendFavorite } from '../../../coordinators/favoriteCoordinator';
import { favoriteRequest, userRequest } from '../../../api'; import { favoriteRequest, userRequest } from '../../../api';
import { createColumns } from './friendImportColumns.jsx'; import { createColumns } from './friendImportColumns.jsx';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable'; import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
@@ -139,7 +140,7 @@
const { favoriteFriendGroups, friendImportDialogInput, friendImportDialogVisible, localFriendFavoriteGroups } = const { favoriteFriendGroups, friendImportDialogInput, friendImportDialogVisible, localFriendFavoriteGroups } =
storeToRefs(useFavoriteStore()); storeToRefs(useFavoriteStore());
const { showFullscreenImageDialog } = useGalleryStore(); const { showFullscreenImageDialog } = useGalleryStore();
const { getCachedFavoritesByObjectId, localFriendFavGroupLength, addLocalFriendFavorite } = useFavoriteStore(); const { getCachedFavoritesByObjectId, localFriendFavGroupLength } = useFavoriteStore();
const friendImportDialog = ref({ const friendImportDialog = ref({
loading: false, loading: false,
@@ -127,6 +127,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useFavoriteStore, useGalleryStore, useUserStore, useWorldStore } from '../../../stores'; import { useFavoriteStore, useGalleryStore, useUserStore, useWorldStore } from '../../../stores';
import { addLocalWorldFavorite } from '../../../coordinators/favoriteCoordinator';
import { favoriteRequest, worldRequest } from '../../../api'; import { favoriteRequest, worldRequest } from '../../../api';
import { createColumns } from './worldImportColumns.jsx'; import { createColumns } from './worldImportColumns.jsx';
import { removeFromArray } from '../../../shared/utils'; import { removeFromArray } from '../../../shared/utils';
@@ -135,7 +136,7 @@
const { showUserDialog } = useUserStore(); const { showUserDialog } = useUserStore();
const { favoriteWorldGroups, worldImportDialogInput, worldImportDialogVisible, localWorldFavoriteGroups } = const { favoriteWorldGroups, worldImportDialogInput, worldImportDialogVisible, localWorldFavoriteGroups } =
storeToRefs(useFavoriteStore()); storeToRefs(useFavoriteStore());
const { localWorldFavGroupLength, addLocalWorldFavorite, getCachedFavoritesByObjectId } = useFavoriteStore(); const { localWorldFavGroupLength, getCachedFavoritesByObjectId } = useFavoriteStore();
const { showWorldDialog } = useWorldStore(); const { showWorldDialog } = useWorldStore();
const { showFullscreenImageDialog } = useGalleryStore(); const { showFullscreenImageDialog } = useGalleryStore();
+2 -1
View File
@@ -58,6 +58,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useAppearanceSettingsStore, useModalStore, useModerationStore, useVrcxStore } from '../../stores'; import { useAppearanceSettingsStore, useModalStore, useModerationStore, useVrcxStore } from '../../stores';
import { runRefreshPlayerModerationsFlow as refreshPlayerModerations } from '../../coordinators/moderationCoordinator';
import { DataTableLayout } from '../../components/ui/data-table'; import { DataTableLayout } from '../../components/ui/data-table';
import { createColumns } from './columns.jsx'; import { createColumns } from './columns.jsx';
import { moderationTypes } from '../../shared/constants'; import { moderationTypes } from '../../shared/constants';
@@ -69,7 +70,7 @@
const { t } = useI18n(); const { t } = useI18n();
const { playerModerationTable } = storeToRefs(useModerationStore()); const { playerModerationTable } = storeToRefs(useModerationStore());
const { refreshPlayerModerations, handlePlayerModerationDelete } = useModerationStore(); const { handlePlayerModerationDelete } = useModerationStore();
const appearanceSettingsStore = useAppearanceSettingsStore(); const appearanceSettingsStore = useAppearanceSettingsStore();
const vrcxStore = useVrcxStore(); const vrcxStore = useVrcxStore();
const modalStore = useModalStore(); const modalStore = useModalStore();
@@ -25,9 +25,13 @@ mocks.pagination = mocks.makeRef({
pageSize: 10 pageSize: 10
}); });
vi.mock('pinia', () => ({ vi.mock('pinia', async (importOriginal) => {
const actual = await importOriginal();
return {
...actual,
storeToRefs: (store) => store storeToRefs: (store) => store
})); };
});
vi.mock('vue-i18n', () => ({ vi.mock('vue-i18n', () => ({
useI18n: () => ({ useI18n: () => ({
@@ -68,10 +72,18 @@ vi.mock('../../../api', () => ({
} }
})); }));
vi.mock('../../../shared/constants', () => ({ vi.mock('../../../coordinators/moderationCoordinator', () => ({
moderationTypes: ['block', 'mute', 'unmute'] runRefreshPlayerModerationsFlow: (...args) => mocks.refreshPlayerModerations(...args)
})); }));
vi.mock('../../../shared/constants', async (importOriginal) => {
const actual = await importOriginal();
return {
...actual,
moderationTypes: ['block', 'mute', 'unmute']
};
});
vi.mock('../columns.jsx', () => ({ vi.mock('../columns.jsx', () => ({
createColumns: (handlers) => { createColumns: (handlers) => {
mocks.columnHandlers = handlers; mocks.columnHandlers = handlers;
@@ -365,6 +365,7 @@
import PresetColorPicker from '@/components/PresetColorPicker.vue'; import PresetColorPicker from '@/components/PresetColorPicker.vue';
import TableLimitsDialog from '@/components/dialogs/TableLimitsDialog.vue'; import TableLimitsDialog from '@/components/dialogs/TableLimitsDialog.vue';
import { saveSortFavoritesOption } from '@/coordinators/favoriteCoordinator';
import SimpleSwitch from '../SimpleSwitch.vue'; import SimpleSwitch from '../SimpleSwitch.vue';
@@ -398,7 +399,6 @@
const appLanguageDisplayName = computed(() => getLanguageName(String(appLanguage.value))); const appLanguageDisplayName = computed(() => getLanguageName(String(appLanguage.value)));
const { saveSortFavoritesOption } = useFavoriteStore();
const { const {
setDisplayVRCPlusIconsAsAvatar, setDisplayVRCPlusIconsAsAvatar,
@@ -184,11 +184,12 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useAdvancedSettingsStore, useGameStore, useModalStore } from '../../../stores'; import { useAdvancedSettingsStore, useGameStore, useModalStore } from '../../../stores';
import { runSweepVRChatCacheFlow as sweepVRChatCache } from '../../../coordinators/gameCoordinator';
import { VRChatCameraResolutions, VRChatScreenshotResolutions } from '../../../shared/constants'; import { VRChatCameraResolutions, VRChatScreenshotResolutions } from '../../../shared/constants';
import { getVRChatResolution, openExternalLink } from '../../../shared/utils'; import { getVRChatResolution, openExternalLink } from '../../../shared/utils';
const { VRChatUsedCacheSize, VRChatTotalCacheSize, VRChatCacheSizeLoading } = storeToRefs(useGameStore()); const { VRChatUsedCacheSize, VRChatTotalCacheSize, VRChatCacheSizeLoading } = storeToRefs(useGameStore());
const { sweepVRChatCache, getVRChatCacheSize } = useGameStore(); const { getVRChatCacheSize } = useGameStore();
const { folderSelectorDialog } = useAdvancedSettingsStore(); const { folderSelectorDialog } = useAdvancedSettingsStore();
const { isVRChatConfigDialogVisible } = storeToRefs(useAdvancedSettingsStore()); const { isVRChatConfigDialogVisible } = storeToRefs(useAdvancedSettingsStore());
const modalStore = useModalStore(); const modalStore = useModalStore();
@@ -59,7 +59,6 @@ vi.mock('../../../../stores', () => ({
VRChatUsedCacheSize, VRChatUsedCacheSize,
VRChatTotalCacheSize, VRChatTotalCacheSize,
VRChatCacheSizeLoading, VRChatCacheSizeLoading,
sweepVRChatCache: mocks.sweepVRChatCache,
getVRChatCacheSize: mocks.getVRChatCacheSize getVRChatCacheSize: mocks.getVRChatCacheSize
}), }),
useAdvancedSettingsStore: () => ({ useAdvancedSettingsStore: () => ({
@@ -97,6 +96,10 @@ vi.mock('vue-sonner', () => ({
toast: mocks.toast toast: mocks.toast
})); }));
vi.mock('../../../../coordinators/gameCoordinator', () => ({
runSweepVRChatCacheFlow: (...args) => mocks.sweepVRChatCache(...args)
}));
// Set global mocks for CefSharp-injected APIs // Set global mocks for CefSharp-injected APIs
globalThis.AppApi = mocks.appApi; globalThis.AppApi = mocks.appApi;
globalThis.AssetBundleManager = mocks.assetBundleManager; globalThis.AssetBundleManager = mocks.assetBundleManager;