mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-19 06:43:51 +02:00
refactor utils
This commit is contained in:
@@ -6,10 +6,11 @@
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useGlobalSearchStore } from '../stores/globalSearch';
|
import { useGlobalSearchStore } from '../stores/globalSearch';
|
||||||
import { userImage } from '../shared/utils';
|
import { useUserDisplay } from '../composables/useUserDisplay';
|
||||||
|
|
||||||
import GlobalSearchSync from './GlobalSearchSync.vue';
|
import GlobalSearchSync from './GlobalSearchSync.vue';
|
||||||
|
|
||||||
|
const { userImage } = useUserDisplay();
|
||||||
const globalSearchStore = useGlobalSearchStore();
|
const globalSearchStore = useGlobalSearchStore();
|
||||||
const {
|
const {
|
||||||
isOpen,
|
isOpen,
|
||||||
|
|||||||
@@ -159,7 +159,8 @@
|
|||||||
useModalStore,
|
useModalStore,
|
||||||
useUserStore
|
useUserStore
|
||||||
} from '../stores';
|
} from '../stores';
|
||||||
import { checkCanInviteSelf, formatDateFilter, hasGroupPermission, parseLocation } from '../shared/utils';
|
import { formatDateFilter, hasGroupPermission, parseLocation } from '../shared/utils';
|
||||||
|
import { useInviteChecks } from '../composables/useInviteChecks';
|
||||||
import { instanceRequest, miscRequest } from '../api';
|
import { instanceRequest, miscRequest } from '../api';
|
||||||
import { showUserDialog } from '../coordinators/userCoordinator';
|
import { showUserDialog } from '../coordinators/userCoordinator';
|
||||||
|
|
||||||
@@ -180,6 +181,7 @@
|
|||||||
const { instanceJoinHistory } = storeToRefs(instanceStore);
|
const { instanceJoinHistory } = storeToRefs(instanceStore);
|
||||||
const { canOpenInstanceInGame } = storeToRefs(inviteStore);
|
const { canOpenInstanceInGame } = storeToRefs(inviteStore);
|
||||||
const { isOpeningInstance } = storeToRefs(launchStore);
|
const { isOpeningInstance } = storeToRefs(launchStore);
|
||||||
|
const { checkCanInviteSelf } = useInviteChecks();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
location: {
|
location: {
|
||||||
|
|||||||
@@ -571,6 +571,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
useAppearanceSettingsStore,
|
useAppearanceSettingsStore,
|
||||||
|
useAuthStore,
|
||||||
useAvatarStore,
|
useAvatarStore,
|
||||||
useFavoriteStore,
|
useFavoriteStore,
|
||||||
useGalleryStore,
|
useGalleryStore,
|
||||||
@@ -622,6 +623,7 @@ import { showUserDialog } from '../../../coordinators/userCoordinator';
|
|||||||
const { isGameRunning } = storeToRefs(useGameStore());
|
const { isGameRunning } = storeToRefs(useGameStore());
|
||||||
const { showFullscreenImageDialog } = useGalleryStore();
|
const { showFullscreenImageDialog } = useGalleryStore();
|
||||||
const { isDarkMode } = storeToRefs(useAppearanceSettingsStore());
|
const { isDarkMode } = storeToRefs(useAppearanceSettingsStore());
|
||||||
|
const authStore = useAuthStore();
|
||||||
const modalStore = useModalStore();
|
const modalStore = useModalStore();
|
||||||
const uiStore = useUiStore();
|
const uiStore = useUiStore();
|
||||||
|
|
||||||
@@ -698,7 +700,7 @@ import { showUserDialog } from '../../../coordinators/userCoordinator';
|
|||||||
// skip imposters
|
// skip imposters
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!compareUnityVersion(unityPackage.unitySortNumber)) {
|
if (!compareUnityVersion(unityPackage.unitySortNumber, authStore.cachedConfig.sdkUnityVersion)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let platform = 'PC';
|
let platform = 'PC';
|
||||||
|
|||||||
@@ -210,13 +210,15 @@
|
|||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { downloadAndSaveJson, hasGroupPermission, userImage } from '../../../shared/utils';
|
import { downloadAndSaveJson, hasGroupPermission } from '../../../shared/utils';
|
||||||
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
import { useGroupStore, useUserStore } from '../../../stores';
|
import { useGroupStore, useUserStore } from '../../../stores';
|
||||||
import { applyGroupMember, handleGroupMember } from '../../../coordinators/groupCoordinator';
|
import { applyGroupMember, handleGroupMember } from '../../../coordinators/groupCoordinator';
|
||||||
import { groupDialogSortingOptions } from '../../../shared/constants';
|
import { groupDialogSortingOptions } from '../../../shared/constants';
|
||||||
import { useGroupMembers } from './useGroupMembers';
|
import { useGroupMembers } from './useGroupMembers';
|
||||||
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
||||||
|
|
||||||
|
const { userImage } = useUserDisplay();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,8 @@
|
|||||||
|
|
||||||
import { useAppearanceSettingsStore, useGalleryStore, useGroupStore, useUserStore } from '../../../stores';
|
import { useAppearanceSettingsStore, useGalleryStore, useGroupStore, useUserStore } from '../../../stores';
|
||||||
import { applyGroupMember, handleGroupMember, handleGroupMemberProps } from '../../../coordinators/groupCoordinator';
|
import { applyGroupMember, handleGroupMember, handleGroupMemberProps } from '../../../coordinators/groupCoordinator';
|
||||||
import { hasGroupPermission, userImage, userImageFull } from '../../../shared/utils';
|
import { hasGroupPermission } from '../../../shared/utils';
|
||||||
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
import { groupDialogFilterOptions, groupDialogSortingOptions } from '../../../shared/constants';
|
import { groupDialogFilterOptions, groupDialogSortingOptions } from '../../../shared/constants';
|
||||||
import { groupRequest, userRequest } from '../../../api';
|
import { groupRequest, userRequest } from '../../../api';
|
||||||
import { resolveRoleNames } from './groupModerationUtils';
|
import { resolveRoleNames } from './groupModerationUtils';
|
||||||
@@ -142,6 +143,7 @@
|
|||||||
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
||||||
|
|
||||||
// ── Stores ───────────────────────────────────────────────────
|
// ── Stores ───────────────────────────────────────────────────
|
||||||
|
const { userImage, userImageFull } = useUserDisplay();
|
||||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||||
const { randomUserColours } = storeToRefs(appearanceSettingsStore);
|
const { randomUserColours } = storeToRefs(appearanceSettingsStore);
|
||||||
|
|
||||||
|
|||||||
@@ -106,12 +106,14 @@
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useFriendStore, useGalleryStore, useInviteStore, useModalStore, useUserStore } from '../../../stores';
|
import { useFriendStore, useGalleryStore, useInviteStore, useModalStore, useUserStore } from '../../../stores';
|
||||||
import { parseLocation, userImage, userStatusClass } from '../../../shared/utils';
|
import { parseLocation } from '../../../shared/utils';
|
||||||
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
import { instanceRequest, notificationRequest } from '../../../api';
|
import { instanceRequest, notificationRequest } from '../../../api';
|
||||||
import { VirtualCombobox } from '../../ui/virtual-combobox';
|
import { VirtualCombobox } from '../../ui/virtual-combobox';
|
||||||
|
|
||||||
import SendInviteDialog from './SendInviteDialog.vue';
|
import SendInviteDialog from './SendInviteDialog.vue';
|
||||||
|
|
||||||
|
const { userImage, userStatusClass } = useUserDisplay();
|
||||||
const { vipFriends, onlineFriends, activeFriends } = storeToRefs(useFriendStore());
|
const { vipFriends, onlineFriends, activeFriends } = storeToRefs(useFriendStore());
|
||||||
const { refreshInviteMessageTableData } = useInviteStore();
|
const { refreshInviteMessageTableData } = useInviteStore();
|
||||||
const { currentUser } = storeToRefs(useUserStore());
|
const { currentUser } = storeToRefs(useUserStore());
|
||||||
|
|||||||
@@ -96,13 +96,15 @@
|
|||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { hasGroupPermission, userImage, userStatusClass } from '../../shared/utils';
|
import { hasGroupPermission } from '../../shared/utils';
|
||||||
|
import { useUserDisplay } from '../../composables/useUserDisplay';
|
||||||
import { useFriendStore, useGroupStore, useModalStore } from '../../stores';
|
import { useFriendStore, useGroupStore, useModalStore } from '../../stores';
|
||||||
import { groupRequest, queryRequest } from '../../api';
|
import { groupRequest, queryRequest } from '../../api';
|
||||||
import { VirtualCombobox } from '../ui/virtual-combobox';
|
import { VirtualCombobox } from '../ui/virtual-combobox';
|
||||||
|
|
||||||
import configRepository from '../../services/config';
|
import configRepository from '../../services/config';
|
||||||
|
|
||||||
|
const { userImage, userStatusClass } = useUserDisplay();
|
||||||
const { vipFriends, onlineFriends, activeFriends, offlineFriends } = storeToRefs(useFriendStore());
|
const { vipFriends, onlineFriends, activeFriends, offlineFriends } = storeToRefs(useFriendStore());
|
||||||
const { currentUserGroups, inviteGroupDialog } = storeToRefs(useGroupStore());
|
const { currentUserGroups, inviteGroupDialog } = storeToRefs(useGroupStore());
|
||||||
const { applyGroup } = useGroupStore();
|
const { applyGroup } = useGroupStore();
|
||||||
|
|||||||
@@ -161,7 +161,8 @@
|
|||||||
useLocationStore,
|
useLocationStore,
|
||||||
useModalStore
|
useModalStore
|
||||||
} from '../../stores';
|
} from '../../stores';
|
||||||
import { checkCanInvite, getLaunchURL, isRealInstance, parseLocation } from '../../shared/utils';
|
import { getLaunchURL, isRealInstance, parseLocation } from '../../shared/utils';
|
||||||
|
import { useInviteChecks } from '../../composables/useInviteChecks';
|
||||||
import { instanceRequest, queryRequest } from '../../api';
|
import { instanceRequest, queryRequest } from '../../api';
|
||||||
|
|
||||||
import InviteDialog from './InviteDialog/InviteDialog.vue';
|
import InviteDialog from './InviteDialog/InviteDialog.vue';
|
||||||
@@ -178,6 +179,7 @@
|
|||||||
|
|
||||||
const { canOpenInstanceInGame } = storeToRefs(useInviteStore());
|
const { canOpenInstanceInGame } = storeToRefs(useInviteStore());
|
||||||
const { isGameRunning } = storeToRefs(useGameStore());
|
const { isGameRunning } = storeToRefs(useGameStore());
|
||||||
|
const { checkCanInvite } = useInviteChecks();
|
||||||
|
|
||||||
const launchModeLabel = computed(() =>
|
const launchModeLabel = computed(() =>
|
||||||
launchDialog.value.desktop ? t('dialog.launch.start_as_desktop') : t('dialog.launch.launch')
|
launchDialog.value.desktop ? t('dialog.launch.start_as_desktop') : t('dialog.launch.launch')
|
||||||
|
|||||||
@@ -63,11 +63,13 @@
|
|||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { hasGroupModerationPermission, userImage } from '../../shared/utils';
|
import { hasGroupModerationPermission } from '../../shared/utils';
|
||||||
|
import { useUserDisplay } from '../../composables/useUserDisplay';
|
||||||
import { VirtualCombobox } from '../ui/virtual-combobox';
|
import { VirtualCombobox } from '../ui/virtual-combobox';
|
||||||
import { queryRequest } from '../../api';
|
import { queryRequest } from '../../api';
|
||||||
import { useGroupStore } from '../../stores';
|
import { useGroupStore } from '../../stores';
|
||||||
|
|
||||||
|
const { userImage } = useUserDisplay();
|
||||||
const { currentUserGroups, moderateGroupDialog } = storeToRefs(useGroupStore());
|
const { currentUserGroups, moderateGroupDialog } = storeToRefs(useGroupStore());
|
||||||
const { showGroupMemberModerationDialog } = useGroupStore();
|
const { showGroupMemberModerationDialog } = useGroupStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|||||||
@@ -251,7 +251,7 @@
|
|||||||
DropdownMenuTrigger
|
DropdownMenuTrigger
|
||||||
} from '../../ui/dropdown-menu';
|
} from '../../ui/dropdown-menu';
|
||||||
import { useGameStore, useLocationStore, useUserStore } from '../../../stores';
|
import { useGameStore, useLocationStore, useUserStore } from '../../../stores';
|
||||||
import { checkCanInvite } from '../../../shared/utils';
|
import { useInviteChecks } from '../../../composables/useInviteChecks';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
userDialogCommand: {
|
userDialogCommand: {
|
||||||
@@ -265,6 +265,7 @@
|
|||||||
const { userDialog, currentUser } = storeToRefs(useUserStore());
|
const { userDialog, currentUser } = storeToRefs(useUserStore());
|
||||||
const { isGameRunning } = storeToRefs(useGameStore());
|
const { isGameRunning } = storeToRefs(useGameStore());
|
||||||
const { lastLocation } = storeToRefs(useLocationStore());
|
const { lastLocation } = storeToRefs(useLocationStore());
|
||||||
|
const { checkCanInvite } = useInviteChecks();
|
||||||
|
|
||||||
const hasRequest = computed(() => userDialog.value.incomingRequest || userDialog.value.outgoingRequest);
|
const hasRequest = computed(() => userDialog.value.incomingRequest || userDialog.value.outgoingRequest);
|
||||||
const hasRisk = computed(
|
const hasRisk = computed(
|
||||||
|
|||||||
@@ -269,13 +269,14 @@
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '../../ui/dropdown-menu';
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '../../ui/dropdown-menu';
|
||||||
import { useInstanceStore, useWorldStore } from '../../../stores';
|
import { useAuthStore, useInstanceStore, useWorldStore } from '../../../stores';
|
||||||
import { openExternalLink } from '../../../shared/utils';
|
import { openExternalLink } from '../../../shared/utils';
|
||||||
import { useWorldDialogInfo } from './useWorldDialogInfo';
|
import { useWorldDialogInfo } from './useWorldDialogInfo';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const { worldDialog } = storeToRefs(useWorldStore());
|
const { worldDialog } = storeToRefs(useWorldStore());
|
||||||
|
const authStore = useAuthStore();
|
||||||
const { showPreviousInstancesListDialog: openPreviousInstancesListDialog } = useInstanceStore();
|
const { showPreviousInstancesListDialog: openPreviousInstancesListDialog } = useInstanceStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -293,7 +294,7 @@
|
|||||||
copyWorldName,
|
copyWorldName,
|
||||||
commaNumber,
|
commaNumber,
|
||||||
formatDateFilter
|
formatDateFilter
|
||||||
} = useWorldDialogInfo(worldDialog, { t, toast });
|
} = useWorldDialogInfo(worldDialog, { t, toast, sdkUnityVersion: authStore.cachedConfig.sdkUnityVersion });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -108,7 +108,8 @@
|
|||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { refreshInstancePlayerCount, userImage, userStatusClass } from '../../../shared/utils';
|
import { refreshInstancePlayerCount } from '../../../shared/utils';
|
||||||
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
import {
|
import {
|
||||||
useAppearanceSettingsStore,
|
useAppearanceSettingsStore,
|
||||||
useInstanceStore,
|
useInstanceStore,
|
||||||
@@ -118,9 +119,10 @@
|
|||||||
} from '../../../stores';
|
} from '../../../stores';
|
||||||
|
|
||||||
import InstanceActionBar from '../../InstanceActionBar.vue';
|
import InstanceActionBar from '../../InstanceActionBar.vue';
|
||||||
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const { userImage, userStatusClass } = useUserDisplay();
|
||||||
|
|
||||||
const { isAgeGatedInstancesVisible } = storeToRefs(useAppearanceSettingsStore());
|
const { isAgeGatedInstancesVisible } = storeToRefs(useAppearanceSettingsStore());
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { database } from '../../../services/database';
|
|||||||
* @param {Function} deps.toast - toast notification function
|
* @param {Function} deps.toast - toast notification function
|
||||||
* @returns {Object} info composable API
|
* @returns {Object} info composable API
|
||||||
*/
|
*/
|
||||||
export function useWorldDialogInfo(worldDialog, { t, toast }) {
|
export function useWorldDialogInfo(worldDialog, { t, toast, sdkUnityVersion }) {
|
||||||
const memo = computed({
|
const memo = computed({
|
||||||
get() {
|
get() {
|
||||||
return worldDialog.value.memo;
|
return worldDialog.value.memo;
|
||||||
@@ -71,7 +71,7 @@ export function useWorldDialogInfo(worldDialog, { t, toast }) {
|
|||||||
const platforms = [];
|
const platforms = [];
|
||||||
if (ref.unityPackages) {
|
if (ref.unityPackages) {
|
||||||
for (const unityPackage of ref.unityPackages) {
|
for (const unityPackage of ref.unityPackages) {
|
||||||
if (!compareUnityVersion(unityPackage.unitySortNumber)) {
|
if (!compareUnityVersion(unityPackage.unitySortNumber, sdkUnityVersion)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let platform = 'PC';
|
let platform = 'PC';
|
||||||
|
|||||||
39
src/composables/useInviteChecks.js
Normal file
39
src/composables/useInviteChecks.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import {
|
||||||
|
useFriendStore,
|
||||||
|
useInstanceStore,
|
||||||
|
useLocationStore,
|
||||||
|
useUserStore
|
||||||
|
} from '../stores';
|
||||||
|
import {
|
||||||
|
checkCanInvite as checkCanInvitePure,
|
||||||
|
checkCanInviteSelf as checkCanInviteSelfPure
|
||||||
|
} from '../shared/utils/invite';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable that provides store-aware invite check functions.
|
||||||
|
* Delegates to the pure utility functions after resolving store data.
|
||||||
|
*/
|
||||||
|
export function useInviteChecks() {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const locationStore = useLocationStore();
|
||||||
|
const instanceStore = useInstanceStore();
|
||||||
|
const friendStore = useFriendStore();
|
||||||
|
|
||||||
|
function checkCanInvite(location) {
|
||||||
|
return checkCanInvitePure(location, {
|
||||||
|
currentUserId: userStore.currentUser.id,
|
||||||
|
lastLocationStr: locationStore.lastLocation.location,
|
||||||
|
cachedInstances: instanceStore.cachedInstances
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkCanInviteSelf(location) {
|
||||||
|
return checkCanInviteSelfPure(location, {
|
||||||
|
currentUserId: userStore.currentUser.id,
|
||||||
|
cachedInstances: instanceStore.cachedInstances,
|
||||||
|
friends: friendStore.friends
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { checkCanInvite, checkCanInviteSelf };
|
||||||
|
}
|
||||||
43
src/composables/useUserDisplay.js
Normal file
43
src/composables/useUserDisplay.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { useAppearanceSettingsStore, useUserStore } from '../stores';
|
||||||
|
import {
|
||||||
|
userImage as userImagePure,
|
||||||
|
userImageFull as userImageFullPure,
|
||||||
|
userStatusClass as userStatusClassPure
|
||||||
|
} from '../shared/utils/user';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable that provides store-aware user display functions.
|
||||||
|
* Delegates to the pure utility functions after resolving store data.
|
||||||
|
*/
|
||||||
|
export function useUserDisplay() {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const appearanceStore = useAppearanceSettingsStore();
|
||||||
|
|
||||||
|
function userStatusClass(user, pendingOffline = false) {
|
||||||
|
return userStatusClassPure(user, pendingOffline, userStore.currentUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
function userImage(
|
||||||
|
user,
|
||||||
|
isIcon = false,
|
||||||
|
resolution = '128',
|
||||||
|
isUserDialogIcon = false
|
||||||
|
) {
|
||||||
|
return userImagePure(
|
||||||
|
user,
|
||||||
|
isIcon,
|
||||||
|
resolution,
|
||||||
|
isUserDialogIcon,
|
||||||
|
appearanceStore.displayVRCPlusIconsAsAvatar
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function userImageFull(user) {
|
||||||
|
return userImageFullPure(
|
||||||
|
user,
|
||||||
|
appearanceStore.displayVRCPlusIconsAsAvatar
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { userStatusClass, userImage, userImageFull };
|
||||||
|
}
|
||||||
@@ -321,7 +321,7 @@ export function updateUserCurrentStatus(ref) {
|
|||||||
friendStore.updateOnlineFriendCounter();
|
friendStore.updateOnlineFriendCounter();
|
||||||
|
|
||||||
if (appearanceSettingsStore.randomUserColours) {
|
if (appearanceSettingsStore.randomUserColours) {
|
||||||
getNameColour(userStore.currentUser.id).then((colour) => {
|
getNameColour(userStore.currentUser.id, appearanceSettingsStore.isDarkMode).then((colour) => {
|
||||||
userStore.setCurrentUserColour(colour);
|
userStore.setCurrentUserColour(colour);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,151 +1,154 @@
|
|||||||
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
||||||
|
|
||||||
// Mock stores
|
|
||||||
vi.mock('../../../stores', () => ({
|
|
||||||
useFriendStore: vi.fn(),
|
|
||||||
useInstanceStore: vi.fn(),
|
|
||||||
useLocationStore: vi.fn(),
|
|
||||||
useUserStore: vi.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Mock transitive deps
|
|
||||||
vi.mock('../../../views/Feed/Feed.vue', () => ({
|
|
||||||
default: { template: '<div />' }
|
|
||||||
}));
|
|
||||||
vi.mock('../../../views/Feed/columns.jsx', () => ({ columns: [] }));
|
|
||||||
vi.mock('../../../plugins/router', () => ({
|
|
||||||
default: { push: vi.fn(), currentRoute: { value: {} } }
|
|
||||||
}));
|
|
||||||
|
|
||||||
import {
|
|
||||||
useFriendStore,
|
|
||||||
useInstanceStore,
|
|
||||||
useLocationStore,
|
|
||||||
useUserStore
|
|
||||||
} from '../../../stores';
|
|
||||||
import { checkCanInvite, checkCanInviteSelf } from '../invite';
|
import { checkCanInvite, checkCanInviteSelf } from '../invite';
|
||||||
|
|
||||||
|
const storeMocks = vi.hoisted(() => ({
|
||||||
|
useUserStore: vi.fn(() => ({ currentUser: { id: 'usr_me' } })),
|
||||||
|
useLocationStore: vi.fn(() => ({
|
||||||
|
lastLocation: { location: '', friendList: new Set() }
|
||||||
|
})),
|
||||||
|
useInstanceStore: vi.fn(() => ({ cachedInstances: new Map() })),
|
||||||
|
useFriendStore: vi.fn(() => ({ friends: new Map() }))
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('../../../stores', () => storeMocks);
|
||||||
|
|
||||||
describe('Invite Utils', () => {
|
describe('Invite Utils', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
useUserStore.mockReturnValue({
|
vi.clearAllMocks();
|
||||||
currentUser: { id: 'usr_me' }
|
|
||||||
});
|
|
||||||
useLocationStore.mockReturnValue({
|
|
||||||
lastLocation: { location: 'wrld_last:12345' }
|
|
||||||
});
|
|
||||||
useInstanceStore.mockReturnValue({
|
|
||||||
cachedInstances: new Map()
|
|
||||||
});
|
|
||||||
useFriendStore.mockReturnValue({
|
|
||||||
friends: new Map()
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const defaultInviteDeps = {
|
||||||
|
currentUserId: 'usr_me',
|
||||||
|
lastLocationStr: 'wrld_last:12345',
|
||||||
|
cachedInstances: new Map()
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultSelfDeps = {
|
||||||
|
currentUserId: 'usr_me',
|
||||||
|
cachedInstances: new Map(),
|
||||||
|
friends: new Map()
|
||||||
|
};
|
||||||
|
|
||||||
describe('checkCanInvite', () => {
|
describe('checkCanInvite', () => {
|
||||||
|
test('does not access stores when deps are provided (pure path)', () => {
|
||||||
|
checkCanInvite('wrld_123:instance', defaultInviteDeps);
|
||||||
|
expect(storeMocks.useUserStore).not.toHaveBeenCalled();
|
||||||
|
expect(storeMocks.useLocationStore).not.toHaveBeenCalled();
|
||||||
|
expect(storeMocks.useInstanceStore).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
test('returns false for empty location', () => {
|
test('returns false for empty location', () => {
|
||||||
expect(checkCanInvite('')).toBe(false);
|
expect(checkCanInvite('', defaultInviteDeps)).toBe(false);
|
||||||
expect(checkCanInvite(null)).toBe(false);
|
expect(checkCanInvite(null, defaultInviteDeps)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns true for public instance', () => {
|
test('returns true for public instance', () => {
|
||||||
expect(checkCanInvite('wrld_123:instance')).toBe(true);
|
expect(checkCanInvite('wrld_123:instance', defaultInviteDeps)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns true for group instance', () => {
|
test('returns true for group instance', () => {
|
||||||
expect(
|
expect(
|
||||||
checkCanInvite(
|
checkCanInvite(
|
||||||
'wrld_123:instance~group(grp_123)~groupAccessType(public)'
|
'wrld_123:instance~group(grp_123)~groupAccessType(public)',
|
||||||
|
defaultInviteDeps
|
||||||
)
|
)
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns true for own instance', () => {
|
test('returns true for own instance', () => {
|
||||||
expect(checkCanInvite('wrld_123:instance~private(usr_me)')).toBe(
|
expect(checkCanInvite('wrld_123:instance~private(usr_me)', defaultInviteDeps)).toBe(
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns false for invite-only instance owned by another', () => {
|
test('returns false for invite-only instance owned by another', () => {
|
||||||
expect(checkCanInvite('wrld_123:instance~private(usr_other)')).toBe(
|
expect(checkCanInvite('wrld_123:instance~private(usr_other)', defaultInviteDeps)).toBe(
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns false for friends-only instance', () => {
|
test('returns false for friends-only instance', () => {
|
||||||
expect(checkCanInvite('wrld_123:instance~friends(usr_other)')).toBe(
|
expect(checkCanInvite('wrld_123:instance~friends(usr_other)', defaultInviteDeps)).toBe(
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns true for friends+ instance if current location matches', () => {
|
test('returns true for friends+ instance if current location matches', () => {
|
||||||
const location = 'wrld_123:instance~hidden(usr_other)';
|
const location = 'wrld_123:instance~hidden(usr_other)';
|
||||||
useLocationStore.mockReturnValue({
|
expect(checkCanInvite(location, {
|
||||||
lastLocation: { location }
|
...defaultInviteDeps,
|
||||||
});
|
lastLocationStr: location
|
||||||
expect(checkCanInvite(location)).toBe(true);
|
})).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns false for friends+ instance if not in that location', () => {
|
test('returns false for friends+ instance if not in that location', () => {
|
||||||
expect(checkCanInvite('wrld_123:instance~hidden(usr_other)')).toBe(
|
expect(checkCanInvite('wrld_123:instance~hidden(usr_other)', defaultInviteDeps)).toBe(
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns false for closed instance', () => {
|
test('returns false for closed instance', () => {
|
||||||
const location = 'wrld_123:instance';
|
const location = 'wrld_123:instance';
|
||||||
useInstanceStore.mockReturnValue({
|
expect(checkCanInvite(location, {
|
||||||
|
...defaultInviteDeps,
|
||||||
cachedInstances: new Map([
|
cachedInstances: new Map([
|
||||||
[location, { closedAt: '2024-01-01' }]
|
[location, { closedAt: '2024-01-01' }]
|
||||||
])
|
])
|
||||||
});
|
})).toBe(false);
|
||||||
expect(checkCanInvite(location)).toBe(false);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('checkCanInviteSelf', () => {
|
describe('checkCanInviteSelf', () => {
|
||||||
|
test('does not access stores when deps are provided (pure path)', () => {
|
||||||
|
checkCanInviteSelf('wrld_123:instance', defaultSelfDeps);
|
||||||
|
expect(storeMocks.useUserStore).not.toHaveBeenCalled();
|
||||||
|
expect(storeMocks.useInstanceStore).not.toHaveBeenCalled();
|
||||||
|
expect(storeMocks.useFriendStore).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
test('returns false for empty location', () => {
|
test('returns false for empty location', () => {
|
||||||
expect(checkCanInviteSelf('')).toBe(false);
|
expect(checkCanInviteSelf('', defaultSelfDeps)).toBe(false);
|
||||||
expect(checkCanInviteSelf(null)).toBe(false);
|
expect(checkCanInviteSelf(null, defaultSelfDeps)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns true for own instance', () => {
|
test('returns true for own instance', () => {
|
||||||
expect(
|
expect(
|
||||||
checkCanInviteSelf('wrld_123:instance~private(usr_me)')
|
checkCanInviteSelf('wrld_123:instance~private(usr_me)', defaultSelfDeps)
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns true for public instance', () => {
|
test('returns true for public instance', () => {
|
||||||
expect(checkCanInviteSelf('wrld_123:instance')).toBe(true);
|
expect(checkCanInviteSelf('wrld_123:instance', defaultSelfDeps)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns true for friends-only instance if user is a friend', () => {
|
test('returns true for friends-only instance if user is a friend', () => {
|
||||||
useFriendStore.mockReturnValue({
|
|
||||||
friends: new Map([['usr_owner', {}]])
|
|
||||||
});
|
|
||||||
expect(
|
expect(
|
||||||
checkCanInviteSelf('wrld_123:instance~friends(usr_owner)')
|
checkCanInviteSelf('wrld_123:instance~friends(usr_owner)', {
|
||||||
|
...defaultSelfDeps,
|
||||||
|
friends: new Map([['usr_owner', {}]])
|
||||||
|
})
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns false for friends-only instance if user is not a friend', () => {
|
test('returns false for friends-only instance if user is not a friend', () => {
|
||||||
expect(
|
expect(
|
||||||
checkCanInviteSelf('wrld_123:instance~friends(usr_other)')
|
checkCanInviteSelf('wrld_123:instance~friends(usr_other)', defaultSelfDeps)
|
||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns false for closed instance', () => {
|
test('returns false for closed instance', () => {
|
||||||
const location = 'wrld_123:instance';
|
const location = 'wrld_123:instance';
|
||||||
useInstanceStore.mockReturnValue({
|
expect(checkCanInviteSelf(location, {
|
||||||
|
...defaultSelfDeps,
|
||||||
cachedInstances: new Map([
|
cachedInstances: new Map([
|
||||||
[location, { closedAt: '2024-01-01' }]
|
[location, { closedAt: '2024-01-01' }]
|
||||||
])
|
])
|
||||||
});
|
})).toBe(false);
|
||||||
expect(checkCanInviteSelf(location)).toBe(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns true for invite instance (not owned, not closed)', () => {
|
test('returns true for invite instance (not owned, not closed)', () => {
|
||||||
expect(
|
expect(
|
||||||
checkCanInviteSelf('wrld_123:instance~private(usr_other)')
|
checkCanInviteSelf('wrld_123:instance~private(usr_other)', defaultSelfDeps)
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
||||||
|
|
||||||
// Mock stores
|
|
||||||
vi.mock('../../../stores', () => ({
|
|
||||||
useUserStore: vi.fn(),
|
|
||||||
useAppearanceSettingsStore: vi.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Mock common.js
|
// Mock common.js
|
||||||
vi.mock('../common', () => ({
|
vi.mock('../common', () => ({
|
||||||
convertFileUrlToImageUrl: vi.fn((url) => `converted:${url}`)
|
convertFileUrlToImageUrl: vi.fn((url) => `converted:${url}`)
|
||||||
@@ -21,16 +15,22 @@ vi.mock('../base/ui', () => ({
|
|||||||
HueToHex: vi.fn((h) => `#hue${h}`)
|
HueToHex: vi.fn((h) => `#hue${h}`)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Mock transitive deps that get pulled in via stores
|
const storeMocks = vi.hoisted(() => ({
|
||||||
vi.mock('../../../views/Feed/Feed.vue', () => ({
|
useUserStore: vi.fn(() => ({
|
||||||
default: { template: '<div />' }
|
currentUser: {
|
||||||
}));
|
id: 'usr_store',
|
||||||
vi.mock('../../../views/Feed/columns.jsx', () => ({ columns: [] }));
|
presence: { platform: 'standalonewindows' },
|
||||||
vi.mock('../../../plugins/router', () => ({
|
onlineFriends: [],
|
||||||
default: { push: vi.fn(), currentRoute: { value: {} } }
|
activeFriends: []
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
useAppearanceSettingsStore: vi.fn(() => ({
|
||||||
|
displayVRCPlusIconsAsAvatar: false
|
||||||
|
}))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
import { useAppearanceSettingsStore, useUserStore } from '../../../stores';
|
vi.mock('../../../stores', () => storeMocks);
|
||||||
|
|
||||||
import {
|
import {
|
||||||
languageClass,
|
languageClass,
|
||||||
parseUserUrl,
|
parseUserUrl,
|
||||||
@@ -209,28 +209,42 @@ describe('User Utils', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('userStatusClass (with store mock)', () => {
|
describe('userStatusClass (explicit currentUser)', () => {
|
||||||
|
let currentUser;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
useUserStore.mockReturnValue({
|
vi.clearAllMocks();
|
||||||
currentUser: {
|
currentUser = {
|
||||||
id: 'usr_me',
|
id: 'usr_me',
|
||||||
presence: { platform: 'standalonewindows' },
|
presence: { platform: 'standalonewindows' },
|
||||||
onlineFriends: [],
|
onlineFriends: [],
|
||||||
activeFriends: []
|
activeFriends: []
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('does not access stores when currentUser is passed (pure path)', () => {
|
||||||
|
userStatusClass(
|
||||||
|
{ id: 'usr_me', status: 'active', isFriend: true },
|
||||||
|
false,
|
||||||
|
currentUser
|
||||||
|
);
|
||||||
|
expect(storeMocks.useUserStore).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns null for undefined user', () => {
|
test('returns null for undefined user', () => {
|
||||||
expect(userStatusClass(undefined)).toBeNull();
|
expect(userStatusClass(undefined, false, currentUser)).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns current user style with status', () => {
|
test('returns current user style with status', () => {
|
||||||
const result = userStatusClass({
|
const result = userStatusClass(
|
||||||
id: 'usr_me',
|
{
|
||||||
status: 'active',
|
id: 'usr_me',
|
||||||
isFriend: true
|
status: 'active',
|
||||||
});
|
isFriend: true
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
currentUser
|
||||||
|
);
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
'status-icon': true,
|
'status-icon': true,
|
||||||
online: true,
|
online: true,
|
||||||
@@ -239,35 +253,37 @@ describe('User Utils', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('returns mobile true for non-PC platform on current user', () => {
|
test('returns mobile true for non-PC platform on current user', () => {
|
||||||
useUserStore.mockReturnValue({
|
currentUser.presence = { platform: 'android' };
|
||||||
currentUser: {
|
const result = userStatusClass(
|
||||||
|
{
|
||||||
id: 'usr_me',
|
id: 'usr_me',
|
||||||
presence: { platform: 'android' },
|
status: 'active'
|
||||||
onlineFriends: [],
|
},
|
||||||
activeFriends: []
|
false,
|
||||||
}
|
currentUser
|
||||||
});
|
);
|
||||||
const result = userStatusClass({
|
|
||||||
id: 'usr_me',
|
|
||||||
status: 'active'
|
|
||||||
});
|
|
||||||
expect(result.mobile).toBe(true);
|
expect(result.mobile).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns null for non-friend users', () => {
|
test('returns null for non-friend users', () => {
|
||||||
expect(
|
expect(
|
||||||
userStatusClass({
|
userStatusClass(
|
||||||
id: 'usr_other',
|
{
|
||||||
status: 'active',
|
id: 'usr_other',
|
||||||
isFriend: false
|
status: 'active',
|
||||||
})
|
isFriend: false
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
currentUser
|
||||||
|
)
|
||||||
).toBeNull();
|
).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns offline style for pending offline friend', () => {
|
test('returns offline style for pending offline friend', () => {
|
||||||
const result = userStatusClass(
|
const result = userStatusClass(
|
||||||
{ id: 'usr_other', isFriend: true, status: 'active' },
|
{ id: 'usr_other', isFriend: true, status: 'active' },
|
||||||
true
|
true,
|
||||||
|
currentUser
|
||||||
);
|
);
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
'status-icon': true,
|
'status-icon': true,
|
||||||
@@ -309,7 +325,7 @@ describe('User Utils', () => {
|
|||||||
status,
|
status,
|
||||||
location,
|
location,
|
||||||
state
|
state
|
||||||
});
|
}, false, currentUser);
|
||||||
expect(result[expected]).toBe(true);
|
expect(result[expected]).toBe(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -321,7 +337,7 @@ describe('User Utils', () => {
|
|||||||
status: 'active',
|
status: 'active',
|
||||||
location: 'offline',
|
location: 'offline',
|
||||||
state: ''
|
state: ''
|
||||||
});
|
}, false, currentUser);
|
||||||
expect(result.offline).toBe(true);
|
expect(result.offline).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -332,7 +348,7 @@ describe('User Utils', () => {
|
|||||||
status: 'busy',
|
status: 'busy',
|
||||||
location: 'private',
|
location: 'private',
|
||||||
state: 'active'
|
state: 'active'
|
||||||
});
|
}, false, currentUser);
|
||||||
expect(result.active).toBe(true);
|
expect(result.active).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -344,7 +360,7 @@ describe('User Utils', () => {
|
|||||||
location: 'wrld_1',
|
location: 'wrld_1',
|
||||||
state: 'online',
|
state: 'online',
|
||||||
$platform: 'android'
|
$platform: 'android'
|
||||||
});
|
}, false, currentUser);
|
||||||
expect(result.mobile).toBe(true);
|
expect(result.mobile).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -356,7 +372,7 @@ describe('User Utils', () => {
|
|||||||
location: 'wrld_1',
|
location: 'wrld_1',
|
||||||
state: 'online',
|
state: 'online',
|
||||||
$platform: 'standalonewindows'
|
$platform: 'standalonewindows'
|
||||||
});
|
}, false, currentUser);
|
||||||
expect(result.mobile).toBeUndefined();
|
expect(result.mobile).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -364,7 +380,7 @@ describe('User Utils', () => {
|
|||||||
const result = userStatusClass({
|
const result = userStatusClass({
|
||||||
userId: 'usr_me',
|
userId: 'usr_me',
|
||||||
status: 'busy'
|
status: 'busy'
|
||||||
});
|
}, false, currentUser);
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
'status-icon': true,
|
'status-icon': true,
|
||||||
busy: true,
|
busy: true,
|
||||||
@@ -373,79 +389,78 @@ describe('User Utils', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('handles private location with empty state (temp fix branch)', () => {
|
test('handles private location with empty state (temp fix branch)', () => {
|
||||||
useUserStore.mockReturnValue({
|
currentUser.activeFriends = ['usr_f'];
|
||||||
currentUser: {
|
|
||||||
id: 'usr_me',
|
|
||||||
onlineFriends: [],
|
|
||||||
activeFriends: ['usr_f']
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const result = userStatusClass({
|
const result = userStatusClass({
|
||||||
id: 'usr_f',
|
id: 'usr_f',
|
||||||
isFriend: true,
|
isFriend: true,
|
||||||
status: 'busy',
|
status: 'busy',
|
||||||
location: 'private',
|
location: 'private',
|
||||||
state: ''
|
state: ''
|
||||||
});
|
}, false, currentUser);
|
||||||
// activeFriends includes usr_f → active
|
// activeFriends includes usr_f → active
|
||||||
expect(result.active).toBe(true);
|
expect(result.active).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('handles private location temp fix → offline branch', () => {
|
test('handles private location temp fix → offline branch', () => {
|
||||||
useUserStore.mockReturnValue({
|
currentUser.activeFriends = [];
|
||||||
currentUser: {
|
|
||||||
id: 'usr_me',
|
|
||||||
onlineFriends: [],
|
|
||||||
activeFriends: []
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const result = userStatusClass({
|
const result = userStatusClass({
|
||||||
id: 'usr_f',
|
id: 'usr_f',
|
||||||
isFriend: true,
|
isFriend: true,
|
||||||
status: 'busy',
|
status: 'busy',
|
||||||
location: 'private',
|
location: 'private',
|
||||||
state: ''
|
state: ''
|
||||||
});
|
}, false, currentUser);
|
||||||
expect(result.offline).toBe(true);
|
expect(result.offline).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('userImage (with store mock)', () => {
|
describe('userImage (explicit settings)', () => {
|
||||||
beforeEach(() => {
|
test('does not access appearance store when setting is passed (pure path)', () => {
|
||||||
useAppearanceSettingsStore.mockReturnValue({
|
userImage(
|
||||||
displayVRCPlusIconsAsAvatar: false
|
{ thumbnailUrl: 'https://img.com/thumb' },
|
||||||
});
|
false,
|
||||||
|
'128',
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
expect(storeMocks.useAppearanceSettingsStore).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns empty string for falsy user', () => {
|
test('returns empty string for falsy user', () => {
|
||||||
expect(userImage(null)).toBe('');
|
expect(userImage(null, false, '128', false, false)).toBe('');
|
||||||
expect(userImage(undefined)).toBe('');
|
expect(userImage(undefined, false, '128', false, false)).toBe('');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns profilePicOverrideThumbnail when available', () => {
|
test('returns profilePicOverrideThumbnail when available', () => {
|
||||||
const user = {
|
const user = {
|
||||||
profilePicOverrideThumbnail: 'https://img.com/pic/256/thumb'
|
profilePicOverrideThumbnail: 'https://img.com/pic/256/thumb'
|
||||||
};
|
};
|
||||||
expect(userImage(user)).toBe('https://img.com/pic/256/thumb');
|
expect(userImage(user, false, '128', false, false)).toBe(
|
||||||
|
'https://img.com/pic/256/thumb'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('replaces resolution for icon mode with profilePicOverrideThumbnail', () => {
|
test('replaces resolution for icon mode with profilePicOverrideThumbnail', () => {
|
||||||
const user = {
|
const user = {
|
||||||
profilePicOverrideThumbnail: 'https://img.com/pic/256/thumb'
|
profilePicOverrideThumbnail: 'https://img.com/pic/256/thumb'
|
||||||
};
|
};
|
||||||
expect(userImage(user, true, '64')).toBe(
|
expect(userImage(user, true, '64', false, false)).toBe(
|
||||||
'https://img.com/pic/64/thumb'
|
'https://img.com/pic/64/thumb'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns profilePicOverride when no thumbnail', () => {
|
test('returns profilePicOverride when no thumbnail', () => {
|
||||||
const user = { profilePicOverride: 'https://img.com/full' };
|
const user = { profilePicOverride: 'https://img.com/full' };
|
||||||
expect(userImage(user)).toBe('https://img.com/full');
|
expect(userImage(user, false, '128', false, false)).toBe(
|
||||||
|
'https://img.com/full'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns thumbnailUrl as fallback', () => {
|
test('returns thumbnailUrl as fallback', () => {
|
||||||
const user = { thumbnailUrl: 'https://img.com/thumb' };
|
const user = { thumbnailUrl: 'https://img.com/thumb' };
|
||||||
expect(userImage(user)).toBe('https://img.com/thumb');
|
expect(userImage(user, false, '128', false, false)).toBe(
|
||||||
|
'https://img.com/thumb'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns currentAvatarThumbnailImageUrl as fallback', () => {
|
test('returns currentAvatarThumbnailImageUrl as fallback', () => {
|
||||||
@@ -453,7 +468,9 @@ describe('User Utils', () => {
|
|||||||
currentAvatarThumbnailImageUrl:
|
currentAvatarThumbnailImageUrl:
|
||||||
'https://img.com/avatar/256/thumb'
|
'https://img.com/avatar/256/thumb'
|
||||||
};
|
};
|
||||||
expect(userImage(user)).toBe('https://img.com/avatar/256/thumb');
|
expect(userImage(user, false, '128', false, false)).toBe(
|
||||||
|
'https://img.com/avatar/256/thumb'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('replaces resolution for icon mode with currentAvatarThumbnailImageUrl', () => {
|
test('replaces resolution for icon mode with currentAvatarThumbnailImageUrl', () => {
|
||||||
@@ -461,7 +478,7 @@ describe('User Utils', () => {
|
|||||||
currentAvatarThumbnailImageUrl:
|
currentAvatarThumbnailImageUrl:
|
||||||
'https://img.com/avatar/256/thumb'
|
'https://img.com/avatar/256/thumb'
|
||||||
};
|
};
|
||||||
expect(userImage(user, true, '64')).toBe(
|
expect(userImage(user, true, '64', false, false)).toBe(
|
||||||
'https://img.com/avatar/64/thumb'
|
'https://img.com/avatar/64/thumb'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -470,39 +487,37 @@ describe('User Utils', () => {
|
|||||||
const user = {
|
const user = {
|
||||||
currentAvatarImageUrl: 'https://img.com/avatar/full'
|
currentAvatarImageUrl: 'https://img.com/avatar/full'
|
||||||
};
|
};
|
||||||
expect(userImage(user)).toBe('https://img.com/avatar/full');
|
expect(userImage(user, false, '128', false, false)).toBe(
|
||||||
|
'https://img.com/avatar/full'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('converts currentAvatarImageUrl for icon mode', () => {
|
test('converts currentAvatarImageUrl for icon mode', () => {
|
||||||
const user = {
|
const user = {
|
||||||
currentAvatarImageUrl: 'https://img.com/avatar/full'
|
currentAvatarImageUrl: 'https://img.com/avatar/full'
|
||||||
};
|
};
|
||||||
expect(userImage(user, true)).toBe(
|
expect(userImage(user, true, '128', false, false)).toBe(
|
||||||
'converted:https://img.com/avatar/full'
|
'converted:https://img.com/avatar/full'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns empty string when user has no image fields', () => {
|
test('returns empty string when user has no image fields', () => {
|
||||||
expect(userImage({})).toBe('');
|
expect(userImage({}, false, '128', false, false)).toBe('');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns userIcon when displayVRCPlusIconsAsAvatar is true', () => {
|
test('returns userIcon when displayVRCPlusIconsAsAvatar is true', () => {
|
||||||
useAppearanceSettingsStore.mockReturnValue({
|
|
||||||
displayVRCPlusIconsAsAvatar: true
|
|
||||||
});
|
|
||||||
const user = {
|
const user = {
|
||||||
userIcon: 'https://img.com/icon',
|
userIcon: 'https://img.com/icon',
|
||||||
thumbnailUrl: 'https://img.com/thumb'
|
thumbnailUrl: 'https://img.com/thumb'
|
||||||
};
|
};
|
||||||
expect(userImage(user)).toBe('https://img.com/icon');
|
expect(userImage(user, false, '128', false, true)).toBe(
|
||||||
|
'https://img.com/icon'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('converts userIcon for icon mode when VRCPlus setting enabled', () => {
|
test('converts userIcon for icon mode when VRCPlus setting enabled', () => {
|
||||||
useAppearanceSettingsStore.mockReturnValue({
|
|
||||||
displayVRCPlusIconsAsAvatar: true
|
|
||||||
});
|
|
||||||
const user = { userIcon: 'https://img.com/icon' };
|
const user = { userIcon: 'https://img.com/icon' };
|
||||||
expect(userImage(user, true)).toBe(
|
expect(userImage(user, true, '128', false, true)).toBe(
|
||||||
'converted:https://img.com/icon'
|
'converted:https://img.com/icon'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -512,21 +527,23 @@ describe('User Utils', () => {
|
|||||||
userIcon: 'https://img.com/icon',
|
userIcon: 'https://img.com/icon',
|
||||||
thumbnailUrl: 'https://img.com/thumb'
|
thumbnailUrl: 'https://img.com/thumb'
|
||||||
};
|
};
|
||||||
expect(userImage(user, false, '128', true)).toBe(
|
expect(userImage(user, false, '128', true, false)).toBe(
|
||||||
'https://img.com/icon'
|
'https://img.com/icon'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('userImageFull (with store mock)', () => {
|
describe('userImageFull (explicit settings)', () => {
|
||||||
beforeEach(() => {
|
test('does not access appearance store when setting is passed (pure path)', () => {
|
||||||
useAppearanceSettingsStore.mockReturnValue({
|
userImageFull(
|
||||||
displayVRCPlusIconsAsAvatar: false
|
{ currentAvatarImageUrl: 'https://img.com/avatar' },
|
||||||
});
|
false
|
||||||
|
);
|
||||||
|
expect(storeMocks.useAppearanceSettingsStore).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns empty string for falsy user', () => {
|
test('returns empty string for falsy user', () => {
|
||||||
expect(userImageFull(null)).toBe('');
|
expect(userImageFull(null, false)).toBe('');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns profilePicOverride when available', () => {
|
test('returns profilePicOverride when available', () => {
|
||||||
@@ -534,25 +551,22 @@ describe('User Utils', () => {
|
|||||||
profilePicOverride: 'https://img.com/full',
|
profilePicOverride: 'https://img.com/full',
|
||||||
currentAvatarImageUrl: 'https://img.com/avatar'
|
currentAvatarImageUrl: 'https://img.com/avatar'
|
||||||
};
|
};
|
||||||
expect(userImageFull(user)).toBe('https://img.com/full');
|
expect(userImageFull(user, false)).toBe('https://img.com/full');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns currentAvatarImageUrl as fallback', () => {
|
test('returns currentAvatarImageUrl as fallback', () => {
|
||||||
const user = {
|
const user = {
|
||||||
currentAvatarImageUrl: 'https://img.com/avatar'
|
currentAvatarImageUrl: 'https://img.com/avatar'
|
||||||
};
|
};
|
||||||
expect(userImageFull(user)).toBe('https://img.com/avatar');
|
expect(userImageFull(user, false)).toBe('https://img.com/avatar');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('returns userIcon when VRCPlus setting enabled', () => {
|
test('returns userIcon when VRCPlus setting enabled', () => {
|
||||||
useAppearanceSettingsStore.mockReturnValue({
|
|
||||||
displayVRCPlusIconsAsAvatar: true
|
|
||||||
});
|
|
||||||
const user = {
|
const user = {
|
||||||
userIcon: 'https://img.com/icon',
|
userIcon: 'https://img.com/icon',
|
||||||
profilePicOverride: 'https://img.com/full'
|
profilePicOverride: 'https://img.com/full'
|
||||||
};
|
};
|
||||||
expect(userImageFull(user)).toBe('https://img.com/icon');
|
expect(userImageFull(user, true)).toBe('https://img.com/icon');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { replaceBioSymbols } from './base/string';
|
import { replaceBioSymbols } from './base/string';
|
||||||
import { useAuthStore } from '../../stores';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -95,10 +94,9 @@ function getPlatformInfo(unityPackages) {
|
|||||||
* @param {string} unitySortNumber
|
* @param {string} unitySortNumber
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function compareUnityVersion(unitySortNumber) {
|
function compareUnityVersion(unitySortNumber, sdkUnityVersion) {
|
||||||
const authStore = useAuthStore();
|
if (!sdkUnityVersion) {
|
||||||
if (!authStore.cachedConfig.sdkUnityVersion) {
|
console.error('No sdkUnityVersion provided');
|
||||||
console.error('No cachedConfig.sdkUnityVersion');
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,9 +104,9 @@ function compareUnityVersion(unitySortNumber) {
|
|||||||
// 2019.4.31f1 2019 04 31 000
|
// 2019.4.31f1 2019 04 31 000
|
||||||
// 5.3.4p1 5 03 04 010
|
// 5.3.4p1 5 03 04 010
|
||||||
// 2019.4.31f1c1 is a thing
|
// 2019.4.31f1c1 is a thing
|
||||||
const array = authStore.cachedConfig.sdkUnityVersion.split('.');
|
const array = sdkUnityVersion.split('.');
|
||||||
if (array.length < 3) {
|
if (array.length < 3) {
|
||||||
console.error('Invalid cachedConfig.sdkUnityVersion');
|
console.error('Invalid sdkUnityVersion');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let currentUnityVersion = array[0];
|
let currentUnityVersion = array[0];
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
extractFileVersion,
|
extractFileVersion,
|
||||||
extractVariantVersion
|
extractVariantVersion
|
||||||
} from '../common';
|
} from '../common';
|
||||||
import { useAvatarStore, useWorldStore } from '../../../stores';
|
import { useAuthStore, useAvatarStore, useWorldStore } from '../../../stores';
|
||||||
import { compareUnityVersion } from '../avatar';
|
import { compareUnityVersion } from '../avatar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -12,6 +12,8 @@ import { compareUnityVersion } from '../avatar';
|
|||||||
* @returns {Promise<string|null>}
|
* @returns {Promise<string|null>}
|
||||||
*/
|
*/
|
||||||
async function getBundleLocation(input) {
|
async function getBundleLocation(input) {
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
const sdkUnityVersion = authStore.cachedConfig.sdkUnityVersion;
|
||||||
const worldStore = useWorldStore();
|
const worldStore = useWorldStore();
|
||||||
const avatarStore = useAvatarStore();
|
const avatarStore = useAvatarStore();
|
||||||
let unityPackage;
|
let unityPackage;
|
||||||
@@ -36,7 +38,7 @@ async function getBundleLocation(input) {
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
unityPackage.platform === 'standalonewindows' &&
|
unityPackage.platform === 'standalonewindows' &&
|
||||||
compareUnityVersion(unityPackage.unitySortNumber)
|
compareUnityVersion(unityPackage.unitySortNumber, sdkUnityVersion)
|
||||||
) {
|
) {
|
||||||
assetUrl = unityPackage.assetUrl;
|
assetUrl = unityPackage.assetUrl;
|
||||||
if (unityPackage.variant !== 'standard') {
|
if (unityPackage.variant !== 'standard') {
|
||||||
@@ -59,7 +61,7 @@ async function getBundleLocation(input) {
|
|||||||
unityPackage = unityPackages[i];
|
unityPackage = unityPackages[i];
|
||||||
if (
|
if (
|
||||||
unityPackage.platform === 'standalonewindows' &&
|
unityPackage.platform === 'standalonewindows' &&
|
||||||
compareUnityVersion(unityPackage.unitySortNumber)
|
compareUnityVersion(unityPackage.unitySortNumber, sdkUnityVersion)
|
||||||
) {
|
) {
|
||||||
assetUrl = unityPackage.assetUrl;
|
assetUrl = unityPackage.assetUrl;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -11,7 +10,6 @@ import {
|
|||||||
import { i18n } from '../../../plugins/i18n';
|
import { i18n } from '../../../plugins/i18n';
|
||||||
import { router } from '../../../plugins/router';
|
import { router } from '../../../plugins/router';
|
||||||
import { textToHex } from './string';
|
import { textToHex } from './string';
|
||||||
import { useAppearanceSettingsStore } from '../../../stores';
|
|
||||||
|
|
||||||
import configRepository from '../../../services/config.js';
|
import configRepository from '../../../services/config.js';
|
||||||
|
|
||||||
@@ -320,11 +318,9 @@ async function refreshCustomScript() {
|
|||||||
* @param {number} hue
|
* @param {number} hue
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function HueToHex(hue) {
|
function HueToHex(hue, isDarkMode) {
|
||||||
const appSettingsStore = useAppearanceSettingsStore();
|
|
||||||
const { isDarkMode } = storeToRefs(appSettingsStore);
|
|
||||||
// this.HSVtoRGB(hue / 65535, .8, .8);
|
// this.HSVtoRGB(hue / 65535, .8, .8);
|
||||||
if (isDarkMode.value) {
|
if (isDarkMode) {
|
||||||
return HSVtoRGB(hue / 65535, 0.6, 1);
|
return HSVtoRGB(hue / 65535, 0.6, 1);
|
||||||
}
|
}
|
||||||
return HSVtoRGB(hue / 65535, 1, 0.7);
|
return HSVtoRGB(hue / 65535, 1, 0.7);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { storeToRefs } from 'pinia';
|
|||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
useAuthStore,
|
||||||
useAvatarStore,
|
useAvatarStore,
|
||||||
useInstanceStore,
|
useInstanceStore,
|
||||||
useModalStore,
|
useModalStore,
|
||||||
@@ -47,6 +48,8 @@ function downloadAndSaveJson(fileName, data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function deleteVRChatCache(ref) {
|
async function deleteVRChatCache(ref) {
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
const sdkUnityVersion = authStore.cachedConfig.sdkUnityVersion;
|
||||||
let assetUrl = '';
|
let assetUrl = '';
|
||||||
let variant = '';
|
let variant = '';
|
||||||
for (let i = ref.unityPackages.length - 1; i > -1; i--) {
|
for (let i = ref.unityPackages.length - 1; i > -1; i--) {
|
||||||
@@ -60,7 +63,7 @@ async function deleteVRChatCache(ref) {
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
unityPackage.platform === 'standalonewindows' &&
|
unityPackage.platform === 'standalonewindows' &&
|
||||||
compareUnityVersion(unityPackage.unitySortNumber)
|
compareUnityVersion(unityPackage.unitySortNumber, sdkUnityVersion)
|
||||||
) {
|
) {
|
||||||
assetUrl = unityPackage.assetUrl;
|
assetUrl = unityPackage.assetUrl;
|
||||||
if (!unityPackage.variant || unityPackage.variant === 'standard') {
|
if (!unityPackage.variant || unityPackage.variant === 'standard') {
|
||||||
@@ -86,6 +89,8 @@ async function checkVRChatCache(ref) {
|
|||||||
if (!ref.unityPackages) {
|
if (!ref.unityPackages) {
|
||||||
return { Item1: -1, Item2: false, Item3: '' };
|
return { Item1: -1, Item2: false, Item3: '' };
|
||||||
}
|
}
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
const sdkUnityVersion = authStore.cachedConfig.sdkUnityVersion;
|
||||||
let assetUrl = '';
|
let assetUrl = '';
|
||||||
let variant = '';
|
let variant = '';
|
||||||
for (let i = ref.unityPackages.length - 1; i > -1; i--) {
|
for (let i = ref.unityPackages.length - 1; i > -1; i--) {
|
||||||
@@ -95,7 +100,7 @@ async function checkVRChatCache(ref) {
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
unityPackage.platform === 'standalonewindows' &&
|
unityPackage.platform === 'standalonewindows' &&
|
||||||
compareUnityVersion(unityPackage.unitySortNumber)
|
compareUnityVersion(unityPackage.unitySortNumber, sdkUnityVersion)
|
||||||
) {
|
) {
|
||||||
assetUrl = unityPackage.assetUrl;
|
assetUrl = unityPackage.assetUrl;
|
||||||
if (!unityPackage.variant || unityPackage.variant === 'standard') {
|
if (!unityPackage.variant || unityPackage.variant === 'standard') {
|
||||||
@@ -153,7 +158,7 @@ function copyToClipboard(text, message = 'Copied successfully!') {
|
|||||||
* @param {number} resolution
|
* @param {number} resolution
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function convertFileUrlToImageUrl(url, resolution = 128) {
|
function convertFileUrlToImageUrl(url, resolution = 128, endpointDomain = AppDebug.endpointDomain) {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -170,7 +175,7 @@ function convertFileUrlToImageUrl(url, resolution = 128) {
|
|||||||
if (match) {
|
if (match) {
|
||||||
const fileId = match[1];
|
const fileId = match[1];
|
||||||
const version = match[2];
|
const version = match[2];
|
||||||
return `${AppDebug.endpointDomain}/image/file_${fileId}/${version}/${resolution}`;
|
return `${endpointDomain}/image/file_${fileId}/${version}/${resolution}`;
|
||||||
}
|
}
|
||||||
// no match return origin url
|
// no match return origin url
|
||||||
return url;
|
return url;
|
||||||
@@ -223,6 +228,8 @@ function openDiscordProfile(discordId) {
|
|||||||
* @returns {Promise<object>}
|
* @returns {Promise<object>}
|
||||||
*/
|
*/
|
||||||
async function getBundleDateSize(ref) {
|
async function getBundleDateSize(ref) {
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
const sdkUnityVersion = authStore.cachedConfig.sdkUnityVersion;
|
||||||
const avatarStore = useAvatarStore();
|
const avatarStore = useAvatarStore();
|
||||||
const { avatarDialog } = storeToRefs(avatarStore);
|
const { avatarDialog } = storeToRefs(avatarStore);
|
||||||
const worldStore = useWorldStore();
|
const worldStore = useWorldStore();
|
||||||
@@ -243,7 +250,7 @@ async function getBundleDateSize(ref) {
|
|||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!compareUnityVersion(unityPackage.unitySortNumber)) {
|
if (!compareUnityVersion(unityPackage.unitySortNumber, sdkUnityVersion)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +1,34 @@
|
|||||||
import {
|
|
||||||
useFriendStore,
|
|
||||||
useInstanceStore,
|
|
||||||
useLocationStore,
|
|
||||||
useUserStore
|
|
||||||
} from '../../stores';
|
|
||||||
import { parseLocation } from './location';
|
import { parseLocation } from './location';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} location
|
* @param {string} location
|
||||||
* @returns
|
* @param {object} deps
|
||||||
|
* @param {string} deps.currentUserId - current user's id
|
||||||
|
* @param {string} deps.lastLocationStr - last location string from location store
|
||||||
|
* @param {Map} deps.cachedInstances - instance cache map
|
||||||
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function checkCanInvite(location) {
|
function checkCanInvite(location, deps) {
|
||||||
if (!location) {
|
if (!location) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const userStore = useUserStore();
|
|
||||||
const locationStore = useLocationStore();
|
|
||||||
const instanceStore = useInstanceStore();
|
|
||||||
const L = parseLocation(location);
|
const L = parseLocation(location);
|
||||||
const instance = instanceStore.cachedInstances.get(location);
|
const instance = deps.cachedInstances?.get(location);
|
||||||
if (instance?.closedAt) {
|
if (instance?.closedAt) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
L.accessType === 'public' ||
|
L.accessType === 'public' ||
|
||||||
L.accessType === 'group' ||
|
L.accessType === 'group' ||
|
||||||
L.userId === userStore.currentUser.id
|
L.userId === deps.currentUserId
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (L.accessType === 'invite' || L.accessType === 'friends') {
|
if (L.accessType === 'invite' || L.accessType === 'friends') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (locationStore.lastLocation.location === location) {
|
if (deps.lastLocationStr === location) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -42,24 +37,25 @@ function checkCanInvite(location) {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} location
|
* @param {string} location
|
||||||
* @returns
|
* @param {object} deps
|
||||||
|
* @param {string} deps.currentUserId - current user's id
|
||||||
|
* @param {Map} deps.cachedInstances - instance cache map
|
||||||
|
* @param {Map} deps.friends - friends map
|
||||||
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function checkCanInviteSelf(location) {
|
function checkCanInviteSelf(location, deps) {
|
||||||
if (!location) {
|
if (!location) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const userStore = useUserStore();
|
|
||||||
const instanceStore = useInstanceStore();
|
|
||||||
const friendStore = useFriendStore();
|
|
||||||
const L = parseLocation(location);
|
const L = parseLocation(location);
|
||||||
const instance = instanceStore.cachedInstances.get(location);
|
const instance = deps.cachedInstances?.get(location);
|
||||||
if (instance?.closedAt) {
|
if (instance?.closedAt) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (L.userId === userStore.currentUser.id) {
|
if (L.userId === deps.currentUserId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (L.accessType === 'friends' && !friendStore.friends.has(L.userId)) {
|
if (L.accessType === 'friends' && !deps.friends?.has(L.userId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { isRealInstance } from './instance.js';
|
import { isRealInstance } from './instance.js';
|
||||||
import { useLocationStore } from '../../stores/location.js';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
parseLocation,
|
parseLocation,
|
||||||
@@ -10,10 +9,12 @@ export {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param friendsArr
|
* @param {Array} friendsArr
|
||||||
|
* @param {object} lastLocation - last location from location store
|
||||||
|
* @param {Set} lastLocation.friendList
|
||||||
|
* @param {string} lastLocation.location
|
||||||
*/
|
*/
|
||||||
function getFriendsLocations(friendsArr) {
|
function getFriendsLocations(friendsArr, lastLocation) {
|
||||||
const locationStore = useLocationStore();
|
|
||||||
// prevent the instance title display as "Traveling".
|
// prevent the instance title display as "Traveling".
|
||||||
if (!friendsArr?.length) {
|
if (!friendsArr?.length) {
|
||||||
return '';
|
return '';
|
||||||
@@ -28,9 +29,11 @@ function getFriendsLocations(friendsArr) {
|
|||||||
return friend.ref.travelingToLocation;
|
return friend.ref.travelingToLocation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const friend of friendsArr) {
|
if (lastLocation) {
|
||||||
if (locationStore.lastLocation.friendList.has(friend.id)) {
|
for (const friend of friendsArr) {
|
||||||
return locationStore.lastLocation.location;
|
if (lastLocation.friendList.has(friend.id)) {
|
||||||
|
return lastLocation.location;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return friendsArr[0].ref?.location;
|
return friendsArr[0].ref?.location;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useAppearanceSettingsStore, useUserStore } from '../../stores';
|
|
||||||
import { HueToHex } from './base/ui';
|
import { HueToHex } from './base/ui';
|
||||||
import { convertFileUrlToImageUrl } from './common';
|
import { convertFileUrlToImageUrl } from './common';
|
||||||
import { languageMappings } from '../constants';
|
import { languageMappings } from '../constants';
|
||||||
@@ -40,21 +39,22 @@ function languageClass(language) {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} userId
|
* @param {string} userId
|
||||||
|
* @param {boolean} isDarkMode
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async function getNameColour(userId) {
|
async function getNameColour(userId, isDarkMode) {
|
||||||
const hue = await AppApi.GetColourFromUserID(userId);
|
const hue = await AppApi.GetColourFromUserID(userId);
|
||||||
return HueToHex(hue);
|
return HueToHex(hue, isDarkMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {object} user
|
* @param {object} user
|
||||||
* @param {boolean} pendingOffline
|
* @param {boolean} pendingOffline
|
||||||
|
* @param {object} currentUser - current user object from useUserStore
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function userStatusClass(user, pendingOffline = false) {
|
function userStatusClass(user, pendingOffline = false, currentUser) {
|
||||||
const userStore = useUserStore();
|
|
||||||
const style = {
|
const style = {
|
||||||
'status-icon': true
|
'status-icon': true
|
||||||
};
|
};
|
||||||
@@ -67,8 +67,8 @@ function userStatusClass(user, pendingOffline = false) {
|
|||||||
} else if (user.userId) {
|
} else if (user.userId) {
|
||||||
id = user.userId;
|
id = user.userId;
|
||||||
}
|
}
|
||||||
if (id === userStore.currentUser.id) {
|
if (id === currentUser?.id) {
|
||||||
const platform = userStore.currentUser.presence?.platform;
|
const platform = currentUser.presence?.platform;
|
||||||
return {
|
return {
|
||||||
...style,
|
...style,
|
||||||
...statusClass(user.status),
|
...statusClass(user.status),
|
||||||
@@ -89,10 +89,10 @@ function userStatusClass(user, pendingOffline = false) {
|
|||||||
user.location === 'private' &&
|
user.location === 'private' &&
|
||||||
user.state === '' &&
|
user.state === '' &&
|
||||||
id &&
|
id &&
|
||||||
!userStore.currentUser.onlineFriends.includes(id)
|
!(currentUser?.onlineFriends || []).includes(id)
|
||||||
) {
|
) {
|
||||||
// temp fix
|
// temp fix
|
||||||
if (userStore.currentUser.activeFriends.includes(id)) {
|
if ((currentUser?.activeFriends || []).includes(id)) {
|
||||||
// Active
|
// Active
|
||||||
style.active = true;
|
style.active = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -166,21 +166,22 @@ function statusClass(status) {
|
|||||||
* @param {boolean} isIcon - is use for icon (about 40x40)
|
* @param {boolean} isIcon - is use for icon (about 40x40)
|
||||||
* @param {string} resolution - requested icon resolution (default 128),
|
* @param {string} resolution - requested icon resolution (default 128),
|
||||||
* @param {boolean} isUserDialogIcon - is use for user dialog icon
|
* @param {boolean} isUserDialogIcon - is use for user dialog icon
|
||||||
|
* @param {boolean} displayVRCPlusIconsAsAvatar - from appearance settings store
|
||||||
* @returns {string} - img url
|
* @returns {string} - img url
|
||||||
*/
|
*/
|
||||||
function userImage(
|
function userImage(
|
||||||
user,
|
user,
|
||||||
isIcon = false,
|
isIcon = false,
|
||||||
resolution = '128',
|
resolution = '128',
|
||||||
isUserDialogIcon = false
|
isUserDialogIcon = false,
|
||||||
|
displayVRCPlusIconsAsAvatar = false
|
||||||
) {
|
) {
|
||||||
const appAppearanceSettingsStore = useAppearanceSettingsStore();
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
(isUserDialogIcon && user.userIcon) ||
|
(isUserDialogIcon && user.userIcon) ||
|
||||||
(appAppearanceSettingsStore.displayVRCPlusIconsAsAvatar &&
|
(displayVRCPlusIconsAsAvatar &&
|
||||||
user.userIcon)
|
user.userIcon)
|
||||||
) {
|
) {
|
||||||
if (isIcon) {
|
if (isIcon) {
|
||||||
@@ -225,15 +226,15 @@ function userImage(
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {object} user
|
* @param {object} user
|
||||||
|
* @param {boolean} displayVRCPlusIconsAsAvatar - from appearance settings store
|
||||||
* @returns {string|*}
|
* @returns {string|*}
|
||||||
*/
|
*/
|
||||||
function userImageFull(user) {
|
function userImageFull(user, displayVRCPlusIconsAsAvatar = false) {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
const appAppearanceSettingsStore = useAppearanceSettingsStore();
|
|
||||||
if (
|
if (
|
||||||
appAppearanceSettingsStore.displayVRCPlusIconsAsAvatar &&
|
displayVRCPlusIconsAsAvatar &&
|
||||||
user.userIcon
|
user.userIcon
|
||||||
) {
|
) {
|
||||||
return user.userIcon;
|
return user.userIcon;
|
||||||
|
|||||||
@@ -347,7 +347,11 @@ export const useNotificationStore = defineStore('Notification', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!checkCanInvite(currentLocation)) {
|
if (!checkCanInvite(currentLocation, {
|
||||||
|
currentUserId: userStore.currentUser.id,
|
||||||
|
lastLocationStr: locationStore.lastLocation.location,
|
||||||
|
cachedInstances: instanceStore.cachedInstances
|
||||||
|
})) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ export const useAppearanceSettingsStore = defineStore(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (randomUserColours.value) {
|
if (randomUserColours.value) {
|
||||||
const colour = await getNameColour(userStore.currentUser.id);
|
const colour = await getNameColour(userStore.currentUser.id, isDarkMode.value);
|
||||||
userStore.setCurrentUserColour(colour);
|
userStore.setCurrentUserColour(colour);
|
||||||
userColourInit();
|
userColourInit();
|
||||||
} else {
|
} else {
|
||||||
@@ -441,7 +441,7 @@ export const useAppearanceSettingsStore = defineStore(
|
|||||||
for (const [userId, hue] of Object.entries(dictObject)) {
|
for (const [userId, hue] of Object.entries(dictObject)) {
|
||||||
const ref = userStore.cachedUsers.get(userId);
|
const ref = userStore.cachedUsers.get(userId);
|
||||||
if (typeof ref !== 'undefined') {
|
if (typeof ref !== 'undefined') {
|
||||||
ref.$userColour = HueToHex(hue);
|
ref.$userColour = HueToHex(hue, isDarkMode.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -460,7 +460,7 @@ export const useAppearanceSettingsStore = defineStore(
|
|||||||
ref.$trustSortNum = trust.trustSortNum;
|
ref.$trustSortNum = trust.trustSortNum;
|
||||||
if (randomUserColours.value && watchState.isFriendsLoaded) {
|
if (randomUserColours.value && watchState.isFriendsLoaded) {
|
||||||
if (!ref.$userColour) {
|
if (!ref.$userColour) {
|
||||||
getNameColour(ref.id).then((colour) => {
|
getNameColour(ref.id, isDarkMode.value).then((colour) => {
|
||||||
ref.$userColour = colour;
|
ref.$userColour = colour;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1042,7 +1042,7 @@ export const useAppearanceSettingsStore = defineStore(
|
|||||||
if (!randomUserColours.value) {
|
if (!randomUserColours.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const colour = await getNameColour(userStore.currentUser.id);
|
const colour = await getNameColour(userStore.currentUser.id, isDarkMode.value);
|
||||||
userStore.setCurrentUserColour(colour);
|
userStore.setCurrentUserColour(colour);
|
||||||
await userColourInit();
|
await userColourInit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,13 +274,14 @@
|
|||||||
useModalStore,
|
useModalStore,
|
||||||
useUserStore
|
useUserStore
|
||||||
} from '../../../stores';
|
} from '../../../stores';
|
||||||
import { userImage, userStatusClass } from '../../../shared/utils';
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
||||||
import { database } from '../../../services/database';
|
import { database } from '../../../services/database';
|
||||||
import { watchState } from '../../../services/watchState';
|
import { watchState } from '../../../services/watchState';
|
||||||
|
|
||||||
import configRepository from '../../../services/config';
|
import configRepository from '../../../services/config';
|
||||||
|
|
||||||
|
const { userImage, userStatusClass } = useUserDisplay();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const friendStore = useFriendStore();
|
const friendStore = useFriendStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|||||||
@@ -350,7 +350,8 @@
|
|||||||
} from '../../components/ui/dropdown-menu';
|
} from '../../components/ui/dropdown-menu';
|
||||||
import { useAppearanceSettingsStore, useFavoriteStore, useModalStore, useUserStore } from '../../stores';
|
import { useAppearanceSettingsStore, useFavoriteStore, useModalStore, useUserStore } from '../../stores';
|
||||||
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../components/ui/resizable';
|
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../components/ui/resizable';
|
||||||
import { debounce, userImage } from '../../shared/utils';
|
import { debounce } from '../../shared/utils';
|
||||||
|
import { useUserDisplay } from '../../composables/useUserDisplay';
|
||||||
import { favoriteRequest } from '../../api';
|
import { favoriteRequest } from '../../api';
|
||||||
import { useFavoritesCardScaling } from './composables/useFavoritesCardScaling.js';
|
import { useFavoritesCardScaling } from './composables/useFavoritesCardScaling.js';
|
||||||
import { useFavoritesGroupPanel } from './composables/useFavoritesGroupPanel.js';
|
import { useFavoritesGroupPanel } from './composables/useFavoritesGroupPanel.js';
|
||||||
@@ -370,6 +371,7 @@
|
|||||||
import FavoritesToolbar from './components/FavoritesToolbar.vue';
|
import FavoritesToolbar from './components/FavoritesToolbar.vue';
|
||||||
import FriendExportDialog from './dialogs/FriendExportDialog.vue';
|
import FriendExportDialog from './dialogs/FriendExportDialog.vue';
|
||||||
|
|
||||||
|
const { userImage } = useUserDisplay();
|
||||||
const friendGroupVisibilityOptions = ref(['public', 'friends', 'private']);
|
const friendGroupVisibilityOptions = ref(['public', 'friends', 'private']);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -93,10 +93,11 @@
|
|||||||
import { favoriteRequest } from '../../../api';
|
import { favoriteRequest } from '../../../api';
|
||||||
import { removeLocalFriendFavorite } from '../../../coordinators/favoriteCoordinator';
|
import { removeLocalFriendFavorite } from '../../../coordinators/favoriteCoordinator';
|
||||||
import { useFavoriteStore } from '../../../stores';
|
import { useFavoriteStore } from '../../../stores';
|
||||||
import { userImage } from '../../../shared/utils';
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
|
|
||||||
import FavoritesMoveDropdown from './FavoritesMoveDropdown.vue';
|
import FavoritesMoveDropdown from './FavoritesMoveDropdown.vue';
|
||||||
|
|
||||||
|
const { userImage } = useUserDisplay();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
favorite: { type: Object, required: true },
|
favorite: { type: Object, required: true },
|
||||||
group: { type: Object, default: null },
|
group: { type: Object, default: null },
|
||||||
|
|||||||
@@ -125,7 +125,8 @@
|
|||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { removeFromArray, userImage, userImageFull } from '../../../shared/utils';
|
import { removeFromArray } from '../../../shared/utils';
|
||||||
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
import { useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores';
|
import { useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores';
|
||||||
import { addLocalFriendFavorite } from '../../../coordinators/favoriteCoordinator';
|
import { addLocalFriendFavorite } from '../../../coordinators/favoriteCoordinator';
|
||||||
import { favoriteRequest, userRequest } from '../../../api';
|
import { favoriteRequest, userRequest } from '../../../api';
|
||||||
@@ -133,6 +134,7 @@
|
|||||||
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
|
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
|
||||||
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
||||||
|
|
||||||
|
const { userImage, userImageFull } = useUserDisplay();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const emit = defineEmits(['update:friendImportDialogInput']);
|
const emit = defineEmits(['update:friendImportDialogInput']);
|
||||||
|
|||||||
@@ -147,7 +147,7 @@
|
|||||||
import { useVirtualizer } from '@tanstack/vue-virtual';
|
import { useVirtualizer } from '@tanstack/vue-virtual';
|
||||||
|
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
|
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
|
||||||
import { useAppearanceSettingsStore, useFavoriteStore, useFriendStore } from '../../stores';
|
import { useAppearanceSettingsStore, useFavoriteStore, useFriendStore, useLocationStore } from '../../stores';
|
||||||
import { Slider } from '../../components/ui/slider';
|
import { Slider } from '../../components/ui/slider';
|
||||||
import { Switch } from '../../components/ui/switch';
|
import { Switch } from '../../components/ui/switch';
|
||||||
import { getFriendsLocations } from '../../shared/utils/location.js';
|
import { getFriendsLocations } from '../../shared/utils/location.js';
|
||||||
@@ -175,6 +175,9 @@
|
|||||||
const favoriteStore = useFavoriteStore();
|
const favoriteStore = useFavoriteStore();
|
||||||
const { favoriteFriendGroups, groupedByGroupKeyFavoriteFriends, localFriendFavorites } = storeToRefs(favoriteStore);
|
const { favoriteFriendGroups, groupedByGroupKeyFavoriteFriends, localFriendFavorites } = storeToRefs(favoriteStore);
|
||||||
|
|
||||||
|
const locationStore = useLocationStore();
|
||||||
|
const { lastLocation } = storeToRefs(locationStore);
|
||||||
|
|
||||||
const collapsedGroups = reactive(new Set());
|
const collapsedGroups = reactive(new Set());
|
||||||
|
|
||||||
const SEGMENTED_BASE_OPTIONS = [
|
const SEGMENTED_BASE_OPTIONS = [
|
||||||
@@ -319,7 +322,7 @@
|
|||||||
.map((group, index) => {
|
.map((group, index) => {
|
||||||
if (!Array.isArray(group) || group.length === 0) return null;
|
if (!Array.isArray(group) || group.length === 0) return null;
|
||||||
const friends = group;
|
const friends = group;
|
||||||
const instanceId = getFriendsLocations(friends) || `instance-${index + 1}`;
|
const instanceId = getFriendsLocations(friends, lastLocation.value) || `instance-${index + 1}`;
|
||||||
return {
|
return {
|
||||||
instanceId: String(instanceId),
|
instanceId: String(instanceId),
|
||||||
friends
|
friends
|
||||||
|
|||||||
@@ -75,13 +75,14 @@
|
|||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { isRealInstance, parseLocation, userImage, userStatusClass } from '../../../shared/utils';
|
import { isRealInstance, parseLocation } from '../../../shared/utils';
|
||||||
import { useGameStore, useLaunchStore, useLocationStore, useUserStore } from '../../../stores';
|
import { useGameStore, useLaunchStore, useLocationStore, useUserStore } from '../../../stores';
|
||||||
import { instanceRequest, notificationRequest, queryRequest } from '../../../api';
|
import { instanceRequest, notificationRequest, queryRequest } from '../../../api';
|
||||||
import { checkCanInvite, checkCanInviteSelf } from '../../../shared/utils/invite.js';
|
import { useInviteChecks } from '../../../composables/useInviteChecks';
|
||||||
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
|
|
||||||
import Location from '../../../components/Location.vue';
|
import Location from '../../../components/Location.vue';
|
||||||
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { showSendBoopDialog } = useUserStore();
|
const { showSendBoopDialog } = useUserStore();
|
||||||
@@ -89,6 +90,8 @@ import { showUserDialog } from '../../../coordinators/userCoordinator';
|
|||||||
const { lastLocation, lastLocationDestination } = storeToRefs(useLocationStore());
|
const { lastLocation, lastLocationDestination } = storeToRefs(useLocationStore());
|
||||||
const { isGameRunning } = storeToRefs(useGameStore());
|
const { isGameRunning } = storeToRefs(useGameStore());
|
||||||
const { currentUser } = storeToRefs(useUserStore());
|
const { currentUser } = storeToRefs(useUserStore());
|
||||||
|
const { checkCanInvite, checkCanInviteSelf } = useInviteChecks();
|
||||||
|
const { userImage, userStatusClass } = useUserDisplay();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
friend: {
|
friend: {
|
||||||
|
|||||||
@@ -179,11 +179,13 @@
|
|||||||
|
|
||||||
import { useAppearanceSettingsStore, useAuthStore, useVRCXUpdaterStore } from '../../stores';
|
import { useAppearanceSettingsStore, useAuthStore, useVRCXUpdaterStore } from '../../stores';
|
||||||
import { getLanguageName, languageCodes } from '../../localization';
|
import { getLanguageName, languageCodes } from '../../localization';
|
||||||
import { openExternalLink, userImage } from '../../shared/utils';
|
import { openExternalLink } from '../../shared/utils';
|
||||||
|
import { useUserDisplay } from '../../composables/useUserDisplay';
|
||||||
import { watchState } from '../../services/watchState';
|
import { watchState } from '../../services/watchState';
|
||||||
|
|
||||||
import LoginSettingsDialog from './Dialog/LoginSettingsDialog.vue';
|
import LoginSettingsDialog from './Dialog/LoginSettingsDialog.vue';
|
||||||
|
|
||||||
|
const { userImage } = useUserDisplay();
|
||||||
const { showVRCXUpdateDialog } = useVRCXUpdaterStore();
|
const { showVRCXUpdateDialog } = useVRCXUpdaterStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|||||||
@@ -27,10 +27,12 @@ import {
|
|||||||
} from 'lucide-vue-next';
|
} from 'lucide-vue-next';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
import { checkCanInvite, formatDateFilter } from '../../shared/utils';
|
import { formatDateFilter } from '../../shared/utils';
|
||||||
|
import { checkCanInvite } from '../../shared/utils/invite';
|
||||||
import { i18n } from '../../plugins';
|
import { i18n } from '../../plugins';
|
||||||
import {
|
import {
|
||||||
useGameStore,
|
useGameStore,
|
||||||
|
useInstanceStore,
|
||||||
useLocationStore,
|
useLocationStore,
|
||||||
useUiStore,
|
useUiStore,
|
||||||
useUserStore,
|
useUserStore,
|
||||||
@@ -70,10 +72,16 @@ export const createColumns = ({
|
|||||||
const { isGameRunning } = storeToRefs(useGameStore());
|
const { isGameRunning } = storeToRefs(useGameStore());
|
||||||
const { isNotificationExpired } = useNotificationStore();
|
const { isNotificationExpired } = useNotificationStore();
|
||||||
|
|
||||||
|
const { cachedInstances } = storeToRefs(useInstanceStore());
|
||||||
|
|
||||||
const canInvite = () => {
|
const canInvite = () => {
|
||||||
const location = lastLocation.value?.location;
|
const location = lastLocation.value?.location;
|
||||||
return (
|
return (
|
||||||
Boolean(location) && isGameRunning.value && checkCanInvite(location)
|
Boolean(location) && isGameRunning.value && checkCanInvite(location, {
|
||||||
|
currentUserId: currentUser.value?.id,
|
||||||
|
lastLocationStr: lastLocation.value?.location,
|
||||||
|
cachedInstances: cachedInstances.value
|
||||||
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
import Timer from '@/components/Timer.vue';
|
import Timer from '@/components/Timer.vue';
|
||||||
|
|
||||||
import { useAppearanceSettingsStore, useFriendStore, useUserStore } from '../../../stores';
|
import { useAppearanceSettingsStore, useFriendStore, useUserStore } from '../../../stores';
|
||||||
import { userImage, userStatusClass } from '../../../shared/utils';
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
|
|
||||||
import '@/styles/status-icon.css';
|
import '@/styles/status-icon.css';
|
||||||
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
||||||
@@ -90,6 +90,7 @@ import { confirmDeleteFriend } from '../../../coordinators/friendRelationshipCoo
|
|||||||
|
|
||||||
const { hideNicknames } = storeToRefs(useAppearanceSettingsStore());
|
const { hideNicknames } = storeToRefs(useAppearanceSettingsStore());
|
||||||
const { isRefreshFriendsLoading, allFavoriteFriendIds } = storeToRefs(useFriendStore());
|
const { isRefreshFriendsLoading, allFavoriteFriendIds } = storeToRefs(useFriendStore());
|
||||||
|
const { userImage, userStatusClass } = useUserDisplay();
|
||||||
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|||||||
@@ -204,9 +204,10 @@
|
|||||||
useUserStore
|
useUserStore
|
||||||
} from '../../../stores';
|
} from '../../../stores';
|
||||||
import { buildFriendRow, buildInstanceHeaderRow, buildToggleRow, estimateRowSize } from '../friendsSidebarUtils';
|
import { buildFriendRow, buildInstanceHeaderRow, buildToggleRow, estimateRowSize } from '../friendsSidebarUtils';
|
||||||
import { getFriendsSortFunction, isRealInstance, userImage, userStatusClass } from '../../../shared/utils';
|
import { getFriendsSortFunction, isRealInstance } from '../../../shared/utils';
|
||||||
import { instanceRequest, notificationRequest, queryRequest, userRequest } from '../../../api';
|
import { instanceRequest, notificationRequest, queryRequest, userRequest } from '../../../api';
|
||||||
import { checkCanInvite, checkCanInviteSelf } from '../../../shared/utils/invite.js';
|
import { useInviteChecks } from '../../../composables/useInviteChecks';
|
||||||
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
import { getFriendsLocations } from '../../../shared/utils/location.js';
|
import { getFriendsLocations } from '../../../shared/utils/location.js';
|
||||||
import { parseLocation } from '../../../shared/utils';
|
import { parseLocation } from '../../../shared/utils';
|
||||||
|
|
||||||
@@ -246,6 +247,8 @@ import { showUserDialog } from '../../../coordinators/userCoordinator';
|
|||||||
const { lastLocation, lastLocationDestination } = storeToRefs(useLocationStore());
|
const { lastLocation, lastLocationDestination } = storeToRefs(useLocationStore());
|
||||||
const { isGameRunning } = storeToRefs(useGameStore());
|
const { isGameRunning } = storeToRefs(useGameStore());
|
||||||
const { currentUser } = storeToRefs(useUserStore());
|
const { currentUser } = storeToRefs(useUserStore());
|
||||||
|
const { checkCanInvite, checkCanInviteSelf } = useInviteChecks();
|
||||||
|
const { userImage, userStatusClass } = useUserDisplay();
|
||||||
|
|
||||||
const isFriendsGroupMe = ref(true);
|
const isFriendsGroupMe = ref(true);
|
||||||
const isVIPFriends = ref(true);
|
const isVIPFriends = ref(true);
|
||||||
@@ -476,7 +479,7 @@ import { showUserDialog } from '../../../coordinators/userCoordinator';
|
|||||||
if (!friendArr || !friendArr.length) return;
|
if (!friendArr || !friendArr.length) return;
|
||||||
const groupKey = friendArr?.[0]?.ref?.$location?.tag ?? `group-${groupIndex}`;
|
const groupKey = friendArr?.[0]?.ref?.$location?.tag ?? `group-${groupIndex}`;
|
||||||
rows.push(
|
rows.push(
|
||||||
buildInstanceHeaderRow(getFriendsLocations(friendArr), friendArr.length, `instance:${groupKey}`)
|
buildInstanceHeaderRow(getFriendsLocations(friendArr, lastLocation.value), friendArr.length, `instance:${groupKey}`)
|
||||||
);
|
);
|
||||||
friendArr.forEach((friend, idx) => {
|
friendArr.forEach((friend, idx) => {
|
||||||
rows.push(
|
rows.push(
|
||||||
|
|||||||
@@ -95,7 +95,8 @@
|
|||||||
ContextMenuTrigger
|
ContextMenuTrigger
|
||||||
} from '../../../components/ui/context-menu';
|
} from '../../../components/ui/context-menu';
|
||||||
import { buildGroupHeaderRow, buildGroupItemRow, estimateGroupRowSize, getGroupId } from '../groupsSidebarUtils';
|
import { buildGroupHeaderRow, buildGroupItemRow, estimateGroupRowSize, getGroupId } from '../groupsSidebarUtils';
|
||||||
import { checkCanInviteSelf, convertFileUrlToImageUrl, parseLocation } from '../../../shared/utils';
|
import { convertFileUrlToImageUrl, parseLocation } from '../../../shared/utils';
|
||||||
|
import { useInviteChecks } from '../../../composables/useInviteChecks';
|
||||||
import { useAppearanceSettingsStore, useGroupStore, useLaunchStore } from '../../../stores';
|
import { useAppearanceSettingsStore, useGroupStore, useLaunchStore } from '../../../stores';
|
||||||
import { instanceRequest } from '../../../api';
|
import { instanceRequest } from '../../../api';
|
||||||
|
|
||||||
@@ -108,6 +109,7 @@
|
|||||||
const { isAgeGatedInstancesVisible } = storeToRefs(useAppearanceSettingsStore());
|
const { isAgeGatedInstancesVisible } = storeToRefs(useAppearanceSettingsStore());
|
||||||
const { showGroupDialog, sortGroupInstancesByInGame } = useGroupStore();
|
const { showGroupDialog, sortGroupInstancesByInGame } = useGroupStore();
|
||||||
const { groupInstances } = storeToRefs(useGroupStore());
|
const { groupInstances } = storeToRefs(useGroupStore());
|
||||||
|
const { checkCanInviteSelf } = useInviteChecks();
|
||||||
|
|
||||||
const groupInstancesCfg = ref({});
|
const groupInstancesCfg = ref({});
|
||||||
const scrollViewportRef = ref(null);
|
const scrollViewportRef = ref(null);
|
||||||
|
|||||||
@@ -257,7 +257,8 @@
|
|||||||
import { useGameStore, useGroupStore, useLocationStore, useNotificationStore, useUserStore } from '../../../stores';
|
import { useGameStore, useGroupStore, useLocationStore, useNotificationStore, useUserStore } from '../../../stores';
|
||||||
import { showGroupDialog } from '../../../coordinators/groupCoordinator';
|
import { showGroupDialog } from '../../../coordinators/groupCoordinator';
|
||||||
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
||||||
import { checkCanInvite, userImage } from '../../../shared/utils';
|
import { useInviteChecks } from '../../../composables/useInviteChecks';
|
||||||
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
|
|
||||||
import Location from '../../../components/Location.vue';
|
import Location from '../../../components/Location.vue';
|
||||||
|
|
||||||
@@ -275,6 +276,8 @@
|
|||||||
const { lastLocation } = storeToRefs(useLocationStore());
|
const { lastLocation } = storeToRefs(useLocationStore());
|
||||||
const { isGameRunning } = storeToRefs(useGameStore());
|
const { isGameRunning } = storeToRefs(useGameStore());
|
||||||
const { openNotificationLink, isNotificationExpired } = useNotificationStore();
|
const { openNotificationLink, isNotificationExpired } = useNotificationStore();
|
||||||
|
const { checkCanInvite } = useInviteChecks();
|
||||||
|
const { userImage } = useUserDisplay();
|
||||||
|
|
||||||
const senderName = computed(() => {
|
const senderName = computed(() => {
|
||||||
const n = props.notification;
|
const n = props.notification;
|
||||||
|
|||||||
@@ -59,7 +59,8 @@
|
|||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { removeFromArray, userImage, userImageFull } from '../../../shared/utils';
|
import { removeFromArray } from '../../../shared/utils';
|
||||||
|
import { useUserDisplay } from '../../../composables/useUserDisplay';
|
||||||
import { useFriendStore, useGalleryStore, useUserStore } from '../../../stores';
|
import { useFriendStore, useGalleryStore, useUserStore } from '../../../stores';
|
||||||
import { createColumns } from './noteExportColumns.jsx';
|
import { createColumns } from './noteExportColumns.jsx';
|
||||||
import { miscRequest } from '../../../api';
|
import { miscRequest } from '../../../api';
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
import * as workerTimers from 'worker-timers';
|
import * as workerTimers from 'worker-timers';
|
||||||
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
import { showUserDialog } from '../../../coordinators/userCoordinator';
|
||||||
|
|
||||||
|
const { userImage, userImageFull } = useUserDisplay();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const { friends } = storeToRefs(useFriendStore());
|
const { friends } = storeToRefs(useFriendStore());
|
||||||
|
|||||||
Reference in New Issue
Block a user