mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-06 22:46:06 +02:00
refactor: reorganize settings tabs
This commit is contained in:
@@ -658,7 +658,60 @@
|
|||||||
"wrist_overlay": "Wrist Overlay",
|
"wrist_overlay": "Wrist Overlay",
|
||||||
"discord_presence": "Discord Presence",
|
"discord_presence": "Discord Presence",
|
||||||
"pictures": "Pictures",
|
"pictures": "Pictures",
|
||||||
"advanced": "Advanced"
|
"advanced": "Advanced",
|
||||||
|
"system": "System",
|
||||||
|
"interface": "Interface",
|
||||||
|
"social": "Social",
|
||||||
|
"vr": "VR",
|
||||||
|
"media": "Media",
|
||||||
|
"integrations": "Integrations"
|
||||||
|
},
|
||||||
|
"social": {
|
||||||
|
"interaction": {
|
||||||
|
"header": "Interaction"
|
||||||
|
},
|
||||||
|
"favorites": {
|
||||||
|
"header": "Favorites"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"vr": {
|
||||||
|
"vr_core": {
|
||||||
|
"header": "VR Core"
|
||||||
|
},
|
||||||
|
"vr_notifications": {
|
||||||
|
"header": "VR Notifications"
|
||||||
|
},
|
||||||
|
"wrist_overlay": {
|
||||||
|
"header": "Wrist Overlay"
|
||||||
|
},
|
||||||
|
"vr_extras": {
|
||||||
|
"header": "VR Extras"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"interface": {
|
||||||
|
"lists_tables": {
|
||||||
|
"header": "Lists & Tables"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"integrations": {
|
||||||
|
"header": "Integrations"
|
||||||
|
},
|
||||||
|
"advanced_groups": {
|
||||||
|
"system": {
|
||||||
|
"header": "System"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"header": "Security"
|
||||||
|
},
|
||||||
|
"diagnostics": {
|
||||||
|
"header": "Diagnostics"
|
||||||
|
},
|
||||||
|
"database": {
|
||||||
|
"header": "Database"
|
||||||
|
},
|
||||||
|
"nightly": {
|
||||||
|
"header": "Nightly"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -4,27 +4,30 @@
|
|||||||
<span class="text-lg font-semibold text-foreground">{{ t('view.settings.header') }}</span>
|
<span class="text-lg font-semibold text-foreground">{{ t('view.settings.header') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<TabsUnderline
|
<TabsUnderline
|
||||||
default-value="general"
|
default-value="system"
|
||||||
:items="settingsTabs"
|
:items="settingsTabs"
|
||||||
:unmount-on-hide="false"
|
:unmount-on-hide="false"
|
||||||
fill>
|
fill>
|
||||||
<template #general>
|
<template #system>
|
||||||
<GeneralTab />
|
<SystemTab />
|
||||||
</template>
|
</template>
|
||||||
<template #appearance>
|
<template #interface>
|
||||||
<AppearanceTab />
|
<InterfaceTab />
|
||||||
|
</template>
|
||||||
|
<template #social>
|
||||||
|
<SocialTab />
|
||||||
</template>
|
</template>
|
||||||
<template #notifications>
|
<template #notifications>
|
||||||
<NotificationsTab />
|
<NotificationsTab />
|
||||||
</template>
|
</template>
|
||||||
<template #wrist-overlay>
|
<template #vr>
|
||||||
<WristOverlayTab />
|
<VrTab />
|
||||||
</template>
|
</template>
|
||||||
<template #discord>
|
<template #media>
|
||||||
<DiscordPresenceTab />
|
<MediaTab />
|
||||||
</template>
|
</template>
|
||||||
<template #pictures>
|
<template #integrations>
|
||||||
<PicturesTab />
|
<IntegrationsTab />
|
||||||
</template>
|
</template>
|
||||||
<template #advanced>
|
<template #advanced>
|
||||||
<AdvancedTab />
|
<AdvancedTab />
|
||||||
@@ -39,21 +42,23 @@
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import AdvancedTab from './components/Tabs/AdvancedTab.vue';
|
import AdvancedTab from './components/Tabs/AdvancedTab.vue';
|
||||||
import AppearanceTab from './components/Tabs/AppearanceTab.vue';
|
import InterfaceTab from './components/Tabs/InterfaceTab.vue';
|
||||||
import DiscordPresenceTab from './components/Tabs/DiscordPresenceTab.vue';
|
import IntegrationsTab from './components/Tabs/IntegrationsTab.vue';
|
||||||
import GeneralTab from './components/Tabs/GeneralTab.vue';
|
import MediaTab from './components/Tabs/MediaTab.vue';
|
||||||
import NotificationsTab from './components/Tabs/NotificationsTab.vue';
|
import NotificationsTab from './components/Tabs/NotificationsTab.vue';
|
||||||
import PicturesTab from './components/Tabs/PicturesTab.vue';
|
import SocialTab from './components/Tabs/SocialTab.vue';
|
||||||
import WristOverlayTab from './components/Tabs/WristOverlayTab.vue';
|
import SystemTab from './components/Tabs/SystemTab.vue';
|
||||||
|
import VrTab from './components/Tabs/VrTab.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const settingsTabs = computed(() => [
|
const settingsTabs = computed(() => [
|
||||||
{ value: 'general', label: t('view.settings.category.general') },
|
{ value: 'system', label: t('view.settings.category.system') },
|
||||||
{ value: 'appearance', label: t('view.settings.category.appearance') },
|
{ value: 'interface', label: t('view.settings.category.interface') },
|
||||||
|
{ value: 'social', label: t('view.settings.category.social') },
|
||||||
{ value: 'notifications', label: t('view.settings.category.notifications') },
|
{ value: 'notifications', label: t('view.settings.category.notifications') },
|
||||||
{ value: 'wrist-overlay', label: t('view.settings.category.wrist_overlay') },
|
{ value: 'vr', label: t('view.settings.category.vr') },
|
||||||
{ value: 'discord', label: t('view.settings.category.discord_presence') },
|
{ value: 'media', label: t('view.settings.category.media') },
|
||||||
{ value: 'pictures', label: t('view.settings.category.pictures') },
|
{ value: 'integrations', label: t('view.settings.category.integrations') },
|
||||||
{ value: 'advanced', label: t('view.settings.category.advanced') }
|
{ value: 'advanced', label: t('view.settings.category.advanced') }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.advanced.advanced.vrcx_settings.header')">
|
<SettingsGroup :title="t('view.settings.advanced_groups.security.header')">
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.primary_password.header')"
|
<SettingsItem :label="t('view.settings.advanced.advanced.primary_password.header')"
|
||||||
:description="t('view.settings.advanced.advanced.primary_password.description')">
|
:description="t('view.settings.advanced.advanced.primary_password.description')">
|
||||||
<Switch
|
<Switch
|
||||||
@@ -30,13 +30,6 @@
|
|||||||
:disabled="!enablePrimaryPassword"
|
:disabled="!enablePrimaryPassword"
|
||||||
@update:modelValue="enablePrimaryPasswordChange" />
|
@update:modelValue="enablePrimaryPasswordChange" />
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
|
|
||||||
<template v-if="branch === 'Nightly'">
|
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.anonymous_error_reporting.header')"
|
|
||||||
:description="t('view.settings.advanced.advanced.anonymous_error_reporting.description')">
|
|
||||||
<Switch :model-value="sentryErrorReporting" @update:modelValue="setSentryErrorReporting()" />
|
|
||||||
</SettingsItem>
|
|
||||||
</template>
|
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.general.logging.header')">
|
<SettingsGroup :title="t('view.settings.general.logging.header')">
|
||||||
@@ -64,36 +57,6 @@
|
|||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.profile.game_info.header')">
|
|
||||||
<div class="px-1 py-1">
|
|
||||||
<div class="flex-1 cursor-pointer" @click="getVisits">
|
|
||||||
<span class="block truncate font-medium text-sm leading-[18px]">{{
|
|
||||||
t('view.profile.game_info.online_users')
|
|
||||||
}}</span>
|
|
||||||
<span v-if="visits" class="block truncate text-xs text-muted-foreground">{{
|
|
||||||
t('view.profile.game_info.user_online', { count: visits })
|
|
||||||
}}</span>
|
|
||||||
<span v-else class="block truncate text-xs text-muted-foreground">{{
|
|
||||||
t('view.profile.game_info.refresh')
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SettingsGroup>
|
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.advanced.advanced.remote_database.header')">
|
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.remote_database.enable')">
|
|
||||||
<Switch
|
|
||||||
:model-value="avatarRemoteDatabase"
|
|
||||||
@update:modelValue="setAvatarRemoteDatabase(!avatarRemoteDatabase)" />
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.remote_database.avatar_database_provider')">
|
|
||||||
<Button size="sm" variant="outline" @click="showAvatarProviderDialog">{{
|
|
||||||
t('view.settings.advanced.advanced.remote_database.avatar_database_provider')
|
|
||||||
}}</Button>
|
|
||||||
</SettingsItem>
|
|
||||||
</SettingsGroup>
|
|
||||||
|
|
||||||
<template v-if="!isLinux">
|
<template v-if="!isLinux">
|
||||||
<SettingsGroup :title="t('view.settings.advanced.advanced.app_launcher.header')">
|
<SettingsGroup :title="t('view.settings.advanced.advanced.app_launcher.header')">
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.app_launcher.folder')">
|
<SettingsItem :label="t('view.settings.advanced.advanced.app_launcher.folder')">
|
||||||
@@ -121,50 +84,6 @@
|
|||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.advanced.advanced.youtube_api.header')">
|
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.youtube_api.enable')"
|
|
||||||
:description="t('view.settings.advanced.advanced.youtube_api.enable_tooltip')">
|
|
||||||
<Switch :model-value="youTubeApi" @update:modelValue="changeYouTubeApi('VRCX_youtubeAPI')" />
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.youtube_api.youtube_api_key')">
|
|
||||||
<Button size="sm" variant="outline" @click="showYouTubeApiDialog">{{
|
|
||||||
t('view.settings.advanced.advanced.youtube_api.youtube_api_key')
|
|
||||||
}}</Button>
|
|
||||||
</SettingsItem>
|
|
||||||
</SettingsGroup>
|
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.advanced.advanced.translation_api.header')">
|
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.translation_api.enable')"
|
|
||||||
:description="t('view.settings.advanced.advanced.translation_api.enable_tooltip')">
|
|
||||||
<Switch :model-value="translationApi" @update:modelValue="changeTranslationAPI('VRCX_translationAPI')" />
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.translation_api.translation_api_key')">
|
|
||||||
<Button size="sm" variant="outline" @click="showTranslationApiDialog">
|
|
||||||
<Languages class="h-4 w-4 mr-1.5" />
|
|
||||||
{{ t('view.settings.advanced.advanced.translation_api.translation_api_key') }}
|
|
||||||
</Button>
|
|
||||||
</SettingsItem>
|
|
||||||
</SettingsGroup>
|
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.advanced.advanced.video_progress_pie.header')">
|
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.video_progress_pie.enable')"
|
|
||||||
:description="t('view.settings.advanced.advanced.video_progress_pie.enable_tooltip')">
|
|
||||||
<Switch
|
|
||||||
:model-value="progressPie"
|
|
||||||
:disabled="!openVR"
|
|
||||||
@update:modelValue="changeYouTubeApi('VRCX_progressPie')" />
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.video_progress_pie.dance_world_only')">
|
|
||||||
<Switch
|
|
||||||
:model-value="progressPieFilter"
|
|
||||||
:disabled="!openVR"
|
|
||||||
@update:modelValue="changeYouTubeApi('VRCX_progressPieFilter')" />
|
|
||||||
</SettingsItem>
|
|
||||||
</SettingsGroup>
|
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.advanced.advanced.launch_commands.header')">
|
<SettingsGroup :title="t('view.settings.advanced.advanced.launch_commands.header')">
|
||||||
<SettingsItem
|
<SettingsItem
|
||||||
:label="t('view.settings.advanced.advanced.launch_commands.show_confirmation_on_switch_avatar_enable')"
|
:label="t('view.settings.advanced.advanced.launch_commands.show_confirmation_on_switch_avatar_enable')"
|
||||||
@@ -224,7 +143,7 @@
|
|||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.advanced.advanced.sqlite_table_size.header')">
|
<SettingsGroup :title="t('view.settings.advanced_groups.database.header')">
|
||||||
<SettingsItem :label="t('view.settings.advanced.advanced.sqlite_table_size.refresh')">
|
<SettingsItem :label="t('view.settings.advanced.advanced.sqlite_table_size.refresh')">
|
||||||
<Button size="sm" variant="outline" @click="getSqliteTableSizes">{{
|
<Button size="sm" variant="outline" @click="getSqliteTableSizes">{{
|
||||||
t('view.settings.advanced.advanced.sqlite_table_size.refresh')
|
t('view.settings.advanced.advanced.sqlite_table_size.refresh')
|
||||||
@@ -245,9 +164,7 @@
|
|||||||
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.video_play') }} <span v-text="sqliteTableSizes.videoPlay"></span></span>
|
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.video_play') }} <span v-text="sqliteTableSizes.videoPlay"></span></span>
|
||||||
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.event') }} <span v-text="sqliteTableSizes.event"></span></span>
|
<span>{{ t('view.settings.advanced.advanced.sqlite_table_size.event') }} <span v-text="sqliteTableSizes.event"></span></span>
|
||||||
</div>
|
</div>
|
||||||
</SettingsGroup>
|
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.advanced.advanced.database_cleanup.header')">
|
|
||||||
<SettingsItem
|
<SettingsItem
|
||||||
:label="t('view.settings.advanced.advanced.database_cleanup.auto_cleanup')"
|
:label="t('view.settings.advanced.advanced.database_cleanup.auto_cleanup')"
|
||||||
:description="t('view.settings.advanced.advanced.database_cleanup.auto_cleanup_description')">
|
:description="t('view.settings.advanced.advanced.database_cleanup.auto_cleanup_description')">
|
||||||
@@ -320,8 +237,24 @@
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.profile.config_json')">
|
<SettingsGroup :title="t('view.settings.advanced_groups.diagnostics.header')">
|
||||||
|
<SettingsGroup :title="t('view.profile.game_info.header')">
|
||||||
|
<div class="px-1 py-1">
|
||||||
|
<div class="flex-1 cursor-pointer" @click="getVisits">
|
||||||
|
<span class="block truncate font-medium text-sm leading-[18px]">{{
|
||||||
|
t('view.profile.game_info.online_users')
|
||||||
|
}}</span>
|
||||||
|
<span v-if="visits" class="block truncate text-xs text-muted-foreground">{{
|
||||||
|
t('view.profile.game_info.user_online', { count: visits })
|
||||||
|
}}</span>
|
||||||
|
<span v-else class="block truncate text-xs text-muted-foreground">{{
|
||||||
|
t('view.profile.game_info.refresh')
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<SettingsGroup :title="t('view.profile.config_json')">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<TooltipWrapper side="top" :content="t('view.profile.refresh_tooltip')">
|
<TooltipWrapper side="top" :content="t('view.profile.refresh_tooltip')">
|
||||||
<Button class="rounded-full" size="icon-sm" variant="outline" @click="refreshConfigTreeData()">
|
<Button class="rounded-full" size="icon-sm" variant="outline" @click="refreshConfigTreeData()">
|
||||||
@@ -344,17 +277,24 @@
|
|||||||
virtual
|
virtual
|
||||||
show-icon />
|
show-icon />
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<template v-if="branch === 'Nightly'">
|
||||||
|
<SettingsGroup :title="t('view.settings.advanced_groups.nightly.header')">
|
||||||
|
<SettingsItem :label="t('view.settings.advanced.advanced.anonymous_error_reporting.header')"
|
||||||
|
:description="t('view.settings.advanced.advanced.anonymous_error_reporting.description')">
|
||||||
|
<Switch :model-value="sentryErrorReporting" @update:modelValue="setSentryErrorReporting()" />
|
||||||
|
</SettingsItem>
|
||||||
|
</SettingsGroup>
|
||||||
|
</template>
|
||||||
|
|
||||||
<RegistryBackupDialog />
|
<RegistryBackupDialog />
|
||||||
<YouTubeApiDialog v-model:isYouTubeApiDialogVisible="isYouTubeApiDialogVisible" />
|
|
||||||
<TranslationApiDialog v-model:isTranslationApiDialogVisible="isTranslationApiDialogVisible" />
|
|
||||||
<AvatarProviderDialog v-model:isAvatarProviderDialogVisible="isAvatarProviderDialogVisible" />
|
|
||||||
<PhotonSettings v-if="photonLoggingEnabled" />
|
<PhotonSettings v-if="photonLoggingEnabled" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Languages, RefreshCcw, Trash2, TriangleAlert } from 'lucide-vue-next';
|
import { RefreshCcw, Trash2, TriangleAlert } from 'lucide-vue-next';
|
||||||
import { computed, reactive, ref } from 'vue';
|
import { computed, reactive, ref } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
@@ -370,17 +310,14 @@
|
|||||||
useAdvancedSettingsStore,
|
useAdvancedSettingsStore,
|
||||||
useAppearanceSettingsStore,
|
useAppearanceSettingsStore,
|
||||||
useAuthStore,
|
useAuthStore,
|
||||||
useAvatarProviderStore,
|
|
||||||
useAvatarStore,
|
useAvatarStore,
|
||||||
useGeneralSettingsStore,
|
useGeneralSettingsStore,
|
||||||
useGroupStore,
|
useGroupStore,
|
||||||
useInstanceStore,
|
useInstanceStore,
|
||||||
useNotificationsSettingsStore,
|
|
||||||
usePhotonStore,
|
usePhotonStore,
|
||||||
useUiStore,
|
useUiStore,
|
||||||
useUserStore,
|
useUserStore,
|
||||||
useVRCXUpdaterStore,
|
useVRCXUpdaterStore,
|
||||||
useVrStore,
|
|
||||||
useWorldStore
|
useWorldStore
|
||||||
} from '@/stores';
|
} from '@/stores';
|
||||||
import { authRequest, queryRequest } from '@/api';
|
import { authRequest, queryRequest } from '@/api';
|
||||||
@@ -388,19 +325,15 @@
|
|||||||
import { clearVRCXCache } from '@/coordinators/vrcxCoordinator';
|
import { clearVRCXCache } from '@/coordinators/vrcxCoordinator';
|
||||||
import { openExternalLink } from '@/shared/utils';
|
import { openExternalLink } from '@/shared/utils';
|
||||||
|
|
||||||
import AvatarProviderDialog from '../../dialogs/AvatarProviderDialog.vue';
|
|
||||||
import PhotonSettings from '../PhotonSettings.vue';
|
import PhotonSettings from '../PhotonSettings.vue';
|
||||||
import RegistryBackupDialog from '../../../Tools/dialogs/RegistryBackupDialog.vue';
|
import RegistryBackupDialog from '../../../Tools/dialogs/RegistryBackupDialog.vue';
|
||||||
import TranslationApiDialog from '../../dialogs/TranslationApiDialog.vue';
|
|
||||||
import YouTubeApiDialog from '../../dialogs/YouTubeApiDialog.vue';
|
|
||||||
import SettingsGroup from '../SettingsGroup.vue';
|
import SettingsGroup from '../SettingsGroup.vue';
|
||||||
import SettingsItem from '../SettingsItem.vue';
|
import SettingsItem from '../SettingsItem.vue';
|
||||||
|
import { TooltipWrapper } from '@/components/ui/tooltip';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const advancedSettingsStore = useAdvancedSettingsStore();
|
const advancedSettingsStore = useAdvancedSettingsStore();
|
||||||
const notificationsSettingsStore = useNotificationsSettingsStore();
|
|
||||||
const { updateVRLastLocation, updateOpenVR } = useVrStore();
|
|
||||||
const { enablePrimaryPasswordChange } = useAuthStore();
|
const { enablePrimaryPasswordChange } = useAuthStore();
|
||||||
const { cachedConfig } = storeToRefs(useAuthStore());
|
const { cachedConfig } = storeToRefs(useAuthStore());
|
||||||
const { showConsole } = useUiStore();
|
const { showConsole } = useUiStore();
|
||||||
@@ -424,7 +357,6 @@
|
|||||||
|
|
||||||
const { photonLoggingEnabled } = storeToRefs(usePhotonStore());
|
const { photonLoggingEnabled } = storeToRefs(usePhotonStore());
|
||||||
const { branch } = storeToRefs(useVRCXUpdaterStore());
|
const { branch } = storeToRefs(useVRCXUpdaterStore());
|
||||||
const { openVR } = storeToRefs(notificationsSettingsStore);
|
|
||||||
|
|
||||||
const { isDarkMode } = storeToRefs(useAppearanceSettingsStore());
|
const { isDarkMode } = storeToRefs(useAppearanceSettingsStore());
|
||||||
|
|
||||||
@@ -434,14 +366,9 @@
|
|||||||
vrcQuitFix,
|
vrcQuitFix,
|
||||||
autoSweepVRChatCache,
|
autoSweepVRChatCache,
|
||||||
selfInviteOverride,
|
selfInviteOverride,
|
||||||
avatarRemoteDatabase,
|
|
||||||
enableAppLauncher,
|
enableAppLauncher,
|
||||||
enableAppLauncherAutoClose,
|
enableAppLauncherAutoClose,
|
||||||
enableAppLauncherRunProcessOnce,
|
enableAppLauncherRunProcessOnce,
|
||||||
youTubeApi,
|
|
||||||
translationApi,
|
|
||||||
progressPie,
|
|
||||||
progressPieFilter,
|
|
||||||
showConfirmationOnSwitchAvatar,
|
showConfirmationOnSwitchAvatar,
|
||||||
gameLogDisabled,
|
gameLogDisabled,
|
||||||
sqliteTableSizes,
|
sqliteTableSizes,
|
||||||
@@ -455,7 +382,6 @@
|
|||||||
setVrcQuitFix,
|
setVrcQuitFix,
|
||||||
setAutoSweepVRChatCache,
|
setAutoSweepVRChatCache,
|
||||||
setSelfInviteOverride,
|
setSelfInviteOverride,
|
||||||
setAvatarRemoteDatabase,
|
|
||||||
setEnableAppLauncher,
|
setEnableAppLauncher,
|
||||||
setEnableAppLauncherAutoClose,
|
setEnableAppLauncherAutoClose,
|
||||||
setEnableAppLauncherRunProcessOnce,
|
setEnableAppLauncherRunProcessOnce,
|
||||||
@@ -463,16 +389,10 @@
|
|||||||
getSqliteTableSizes,
|
getSqliteTableSizes,
|
||||||
setAvatarAutoCleanup,
|
setAvatarAutoCleanup,
|
||||||
purgeAvatarFeedData,
|
purgeAvatarFeedData,
|
||||||
showVRChatConfig,
|
|
||||||
promptAutoClearVRCXCacheFrequency,
|
promptAutoClearVRCXCacheFrequency,
|
||||||
setSentryErrorReporting
|
setSentryErrorReporting
|
||||||
} = advancedSettingsStore;
|
} = advancedSettingsStore;
|
||||||
|
|
||||||
const { isAvatarProviderDialogVisible } = storeToRefs(useAvatarProviderStore());
|
|
||||||
const { showAvatarProviderDialog } = useAvatarProviderStore();
|
|
||||||
|
|
||||||
const isYouTubeApiDialogVisible = ref(false);
|
|
||||||
const isTranslationApiDialogVisible = ref(false);
|
|
||||||
const configTreeData = ref({});
|
const configTreeData = ref({});
|
||||||
const visits = ref(0);
|
const visits = ref(0);
|
||||||
const selectedPurgePeriod = ref('180');
|
const selectedPurgePeriod = ref('180');
|
||||||
@@ -505,20 +425,6 @@
|
|||||||
AppApi.OpenShortcutFolder();
|
AppApi.OpenShortcutFolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function showYouTubeApiDialog() {
|
|
||||||
isYouTubeApiDialogVisible.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function showTranslationApiDialog() {
|
|
||||||
isTranslationApiDialogVisible.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -531,32 +437,6 @@
|
|||||||
cacheSize.cachedInstances = cachedInstances.size;
|
cacheSize.cachedInstances = cachedInstances.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param configKey
|
|
||||||
*/
|
|
||||||
async function changeYouTubeApi(configKey = '') {
|
|
||||||
if (configKey === 'VRCX_youtubeAPI') {
|
|
||||||
advancedSettingsStore.setYouTubeApi();
|
|
||||||
} else if (configKey === 'VRCX_progressPie') {
|
|
||||||
advancedSettingsStore.setProgressPie();
|
|
||||||
} else if (configKey === 'VRCX_progressPieFilter') {
|
|
||||||
advancedSettingsStore.setProgressPieFilter();
|
|
||||||
}
|
|
||||||
updateVRLastLocation();
|
|
||||||
updateOpenVR();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param configKey
|
|
||||||
*/
|
|
||||||
async function changeTranslationAPI(configKey = '') {
|
|
||||||
if (configKey === 'VRCX_translationAPI') {
|
|
||||||
advancedSettingsStore.setTranslationApi();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|||||||
+117
-2
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-10 py-2">
|
<div class="flex flex-col gap-10 py-2">
|
||||||
|
<!-- Discord Rich Presence -->
|
||||||
<SettingsGroup :title="t('view.settings.discord_presence.discord_presence.header')">
|
<SettingsGroup :title="t('view.settings.discord_presence.discord_presence.header')">
|
||||||
<template #description>
|
<template #description>
|
||||||
<p class="m-0">{{ t('view.settings.discord_presence.discord_presence.description') }}</p>
|
<p class="m-0">{{ t('view.settings.discord_presence.discord_presence.description') }}</p>
|
||||||
@@ -94,21 +95,83 @@
|
|||||||
" />
|
" />
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<!-- Translation API -->
|
||||||
|
<SettingsGroup :title="t('view.settings.advanced.advanced.translation_api.header')">
|
||||||
|
<SettingsItem :label="t('view.settings.advanced.advanced.translation_api.enable')"
|
||||||
|
:description="t('view.settings.advanced.advanced.translation_api.enable_tooltip')">
|
||||||
|
<Switch :model-value="translationApi" @update:modelValue="changeTranslationAPI('VRCX_translationAPI')" />
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem :label="t('view.settings.advanced.advanced.translation_api.translation_api_key')">
|
||||||
|
<Button size="sm" variant="outline" @click="showTranslationApiDialog">
|
||||||
|
<Languages class="h-4 w-4 mr-1.5" />
|
||||||
|
{{ t('view.settings.advanced.advanced.translation_api.translation_api_key') }}
|
||||||
|
</Button>
|
||||||
|
</SettingsItem>
|
||||||
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<!-- YouTube API -->
|
||||||
|
<SettingsGroup :title="t('view.settings.advanced.advanced.youtube_api.header')">
|
||||||
|
<SettingsItem :label="t('view.settings.advanced.advanced.youtube_api.enable')"
|
||||||
|
:description="t('view.settings.advanced.advanced.youtube_api.enable_tooltip')">
|
||||||
|
<Switch :model-value="youTubeApi" @update:modelValue="changeYouTubeApi('VRCX_youtubeAPI')" />
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem :label="t('view.settings.advanced.advanced.youtube_api.youtube_api_key')">
|
||||||
|
<Button size="sm" variant="outline" @click="showYouTubeApiDialog">{{
|
||||||
|
t('view.settings.advanced.advanced.youtube_api.youtube_api_key')
|
||||||
|
}}</Button>
|
||||||
|
</SettingsItem>
|
||||||
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<!-- Remote Database -->
|
||||||
|
<SettingsGroup :title="t('view.settings.advanced.advanced.remote_database.header')">
|
||||||
|
<SettingsItem :label="t('view.settings.advanced.advanced.remote_database.enable')">
|
||||||
|
<Switch
|
||||||
|
:model-value="avatarRemoteDatabase"
|
||||||
|
@update:modelValue="setAvatarRemoteDatabase(!avatarRemoteDatabase)" />
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem :label="t('view.settings.advanced.advanced.remote_database.avatar_database_provider')">
|
||||||
|
<Button size="sm" variant="outline" @click="showAvatarProviderDialog">{{
|
||||||
|
t('view.settings.advanced.advanced.remote_database.avatar_database_provider')
|
||||||
|
}}</Button>
|
||||||
|
</SettingsItem>
|
||||||
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<TranslationApiDialog v-model:isTranslationApiDialogVisible="isTranslationApiDialogVisible" />
|
||||||
|
<YouTubeApiDialog v-model:isYouTubeApiDialogVisible="isYouTubeApiDialogVisible" />
|
||||||
|
<AvatarProviderDialog v-model:isAvatarProviderDialogVisible="isAvatarProviderDialogVisible" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { Languages } from 'lucide-vue-next';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useAdvancedSettingsStore, useDiscordPresenceSettingsStore } from '@/stores';
|
import {
|
||||||
|
useAdvancedSettingsStore,
|
||||||
|
useAvatarProviderStore,
|
||||||
|
useDiscordPresenceSettingsStore,
|
||||||
|
useVrStore
|
||||||
|
} from '@/stores';
|
||||||
|
|
||||||
|
import AvatarProviderDialog from '../../dialogs/AvatarProviderDialog.vue';
|
||||||
|
import TranslationApiDialog from '../../dialogs/TranslationApiDialog.vue';
|
||||||
|
import YouTubeApiDialog from '../../dialogs/YouTubeApiDialog.vue';
|
||||||
import SettingsGroup from '../SettingsGroup.vue';
|
import SettingsGroup from '../SettingsGroup.vue';
|
||||||
import SettingsItem from '../SettingsItem.vue';
|
import SettingsItem from '../SettingsItem.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const advancedSettingsStore = useAdvancedSettingsStore();
|
||||||
|
const { updateVRLastLocation, updateOpenVR } = useVrStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setDiscordActive,
|
setDiscordActive,
|
||||||
setDiscordInstance,
|
setDiscordInstance,
|
||||||
@@ -132,5 +195,57 @@
|
|||||||
discordWorldNameAsDiscordStatus
|
discordWorldNameAsDiscordStatus
|
||||||
} = storeToRefs(useDiscordPresenceSettingsStore());
|
} = storeToRefs(useDiscordPresenceSettingsStore());
|
||||||
|
|
||||||
const { showVRChatConfig } = useAdvancedSettingsStore();
|
const { showVRChatConfig } = advancedSettingsStore;
|
||||||
|
|
||||||
|
const {
|
||||||
|
avatarRemoteDatabase,
|
||||||
|
youTubeApi,
|
||||||
|
translationApi
|
||||||
|
} = storeToRefs(advancedSettingsStore);
|
||||||
|
|
||||||
|
const {
|
||||||
|
setAvatarRemoteDatabase
|
||||||
|
} = advancedSettingsStore;
|
||||||
|
|
||||||
|
const { isAvatarProviderDialogVisible } = storeToRefs(useAvatarProviderStore());
|
||||||
|
const { showAvatarProviderDialog } = useAvatarProviderStore();
|
||||||
|
|
||||||
|
const isYouTubeApiDialogVisible = ref(false);
|
||||||
|
const isTranslationApiDialogVisible = ref(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function showYouTubeApiDialog() {
|
||||||
|
isYouTubeApiDialogVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function showTranslationApiDialog() {
|
||||||
|
isTranslationApiDialogVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param configKey
|
||||||
|
*/
|
||||||
|
async function changeYouTubeApi(configKey = '') {
|
||||||
|
if (configKey === 'VRCX_youtubeAPI') {
|
||||||
|
advancedSettingsStore.setYouTubeApi();
|
||||||
|
}
|
||||||
|
updateVRLastLocation();
|
||||||
|
updateOpenVR();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param configKey
|
||||||
|
*/
|
||||||
|
async function changeTranslationAPI(configKey = '') {
|
||||||
|
if (configKey === 'VRCX_translationAPI') {
|
||||||
|
advancedSettingsStore.setTranslationApi();
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
+2
-36
@@ -134,7 +134,7 @@
|
|||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.appearance.sorting_tables.header')">
|
<SettingsGroup :title="t('view.settings.interface.lists_tables.header')">
|
||||||
<SettingsItem :label="t('view.settings.appearance.appearance.sort_favorite_by')">
|
<SettingsItem :label="t('view.settings.appearance.appearance.sort_favorite_by')">
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
:model-value="sortFavorites ? 'true' : 'false'"
|
:model-value="sortFavorites ? 'true' : 'false'"
|
||||||
@@ -264,31 +264,6 @@
|
|||||||
<SettingsItem :label="t('view.settings.appearance.user_dialog.vrcx_memos')">
|
<SettingsItem :label="t('view.settings.appearance.user_dialog.vrcx_memos')">
|
||||||
<Switch :model-value="!hideUserMemos" @update:modelValue="setHideUserMemos" />
|
<Switch :model-value="!hideUserMemos" @update:modelValue="setHideUserMemos" />
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
|
|
||||||
<SettingsItem
|
|
||||||
:label="t('view.settings.appearance.user_dialog.recent_action_cooldown')"
|
|
||||||
:description="t('view.settings.appearance.user_dialog.recent_action_cooldown_description')">
|
|
||||||
<Switch :model-value="recentActionCooldownEnabled" @update:modelValue="setRecentActionCooldownEnabled" />
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem
|
|
||||||
v-if="recentActionCooldownEnabled"
|
|
||||||
:label="t('view.settings.appearance.user_dialog.recent_action_cooldown_minutes')">
|
|
||||||
<NumberField
|
|
||||||
:model-value="recentActionCooldownMinutes"
|
|
||||||
:min="1"
|
|
||||||
:max="1440"
|
|
||||||
:step="1"
|
|
||||||
:format-options="{ maximumFractionDigits: 0 }"
|
|
||||||
class="w-32"
|
|
||||||
@update:modelValue="setRecentActionCooldownMinutes">
|
|
||||||
<NumberFieldContent>
|
|
||||||
<NumberFieldDecrement />
|
|
||||||
<NumberFieldInput />
|
|
||||||
<NumberFieldIncrement />
|
|
||||||
</NumberFieldContent>
|
|
||||||
</NumberField>
|
|
||||||
</SettingsItem>
|
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.appearance.friend_log.header')">
|
<SettingsGroup :title="t('view.settings.appearance.friend_log.header')">
|
||||||
@@ -360,7 +335,7 @@
|
|||||||
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||||
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||||
import { CheckIcon, ChevronDown } from 'lucide-vue-next';
|
import { CheckIcon, ChevronDown } from 'lucide-vue-next';
|
||||||
import { useAppearanceSettingsStore, useFavoriteStore, useGeneralSettingsStore, useVrStore } from '@/stores';
|
import { useAppearanceSettingsStore, useFavoriteStore, useVrStore } from '@/stores';
|
||||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { getLanguageName, languageCodes } from '@/localization';
|
import { getLanguageName, languageCodes } from '@/localization';
|
||||||
@@ -380,7 +355,6 @@
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||||
const generalSettingsStore = useGeneralSettingsStore();
|
|
||||||
const { saveOpenVROption, updateVRConfigVars } = useVrStore();
|
const { saveOpenVROption, updateVRConfigVars } = useVrStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -432,15 +406,7 @@
|
|||||||
setAppCjkFontPack
|
setAppCjkFontPack
|
||||||
} = appearanceSettingsStore;
|
} = appearanceSettingsStore;
|
||||||
|
|
||||||
const {
|
|
||||||
recentActionCooldownEnabled,
|
|
||||||
recentActionCooldownMinutes
|
|
||||||
} = storeToRefs(generalSettingsStore);
|
|
||||||
|
|
||||||
const {
|
|
||||||
setRecentActionCooldownEnabled,
|
|
||||||
setRecentActionCooldownMinutes
|
|
||||||
} = generalSettingsStore;
|
|
||||||
|
|
||||||
const trustColorEntries = [
|
const trustColorEntries = [
|
||||||
{
|
{
|
||||||
@@ -14,172 +14,6 @@
|
|||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.notifications.notifications.steamvr_notifications.header')">
|
|
||||||
<SettingsItem
|
|
||||||
:label="t('view.settings.notifications.notifications.desktop_notifications.when_to_display')">
|
|
||||||
<ToggleGroup
|
|
||||||
type="single"
|
|
||||||
required
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
:model-value="overlayToast"
|
|
||||||
:disabled="
|
|
||||||
(!overlayNotifications || !openVR) &&
|
|
||||||
!xsNotifications &&
|
|
||||||
!ovrtHudNotifications &&
|
|
||||||
!ovrtWristNotifications
|
|
||||||
"
|
|
||||||
@update:model-value="
|
|
||||||
setOverlayToast($event);
|
|
||||||
saveOpenVROption();
|
|
||||||
">
|
|
||||||
<ToggleGroupItem value="Never">{{
|
|
||||||
t('view.settings.notifications.notifications.conditions.never')
|
|
||||||
}}</ToggleGroupItem>
|
|
||||||
<ToggleGroupItem value="Game Running">{{
|
|
||||||
t('view.settings.notifications.notifications.conditions.inside_vrchat')
|
|
||||||
}}</ToggleGroupItem>
|
|
||||||
<ToggleGroupItem value="Game Closed">{{
|
|
||||||
t('view.settings.notifications.notifications.conditions.outside_vrchat')
|
|
||||||
}}</ToggleGroupItem>
|
|
||||||
<ToggleGroupItem value="Always">{{
|
|
||||||
t('view.settings.notifications.notifications.conditions.always')
|
|
||||||
}}</ToggleGroupItem>
|
|
||||||
</ToggleGroup>
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem
|
|
||||||
:label="t('view.settings.notifications.notifications.steamvr_notifications.steamvr_overlay')">
|
|
||||||
<Switch
|
|
||||||
:model-value="openVR"
|
|
||||||
@update:modelValue="
|
|
||||||
setOpenVR();
|
|
||||||
saveOpenVROption();
|
|
||||||
" />
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<template v-if="openVR">
|
|
||||||
<SettingsItem
|
|
||||||
:label="
|
|
||||||
t('view.settings.notifications.notifications.steamvr_notifications.overlay_notifications')
|
|
||||||
">
|
|
||||||
<Switch
|
|
||||||
:model-value="overlayNotifications"
|
|
||||||
:disabled="!openVR"
|
|
||||||
@update:modelValue="
|
|
||||||
setOverlayNotifications();
|
|
||||||
saveOpenVROption();
|
|
||||||
" />
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem
|
|
||||||
:label="
|
|
||||||
t('view.settings.notifications.notifications.steamvr_notifications.notification_position')
|
|
||||||
">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
:disabled="!overlayNotifications || !openVR"
|
|
||||||
@click="showNotificationPositionDialog"
|
|
||||||
>{{
|
|
||||||
t('view.settings.notifications.notifications.steamvr_notifications.notification_position')
|
|
||||||
}}</Button
|
|
||||||
>
|
|
||||||
</SettingsItem>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<SettingsItem
|
|
||||||
:label="
|
|
||||||
t('view.settings.notifications.notifications.steamvr_notifications.notification_opacity')
|
|
||||||
">
|
|
||||||
<div class="w-75 max-w-full pt-1">
|
|
||||||
<Slider v-model="notificationOpacityValue" :min="0" :max="100" />
|
|
||||||
</div>
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem
|
|
||||||
:label="
|
|
||||||
t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout')
|
|
||||||
">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
:disabled="(!overlayNotifications || !openVR) && !xsNotifications"
|
|
||||||
@click="promptNotificationTimeout"
|
|
||||||
>{{
|
|
||||||
t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout')
|
|
||||||
}}</Button
|
|
||||||
>
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem
|
|
||||||
:label="t('view.settings.notifications.notifications.steamvr_notifications.user_images')">
|
|
||||||
<Switch
|
|
||||||
:model-value="imageNotifications"
|
|
||||||
@update:modelValue="
|
|
||||||
setImageNotifications();
|
|
||||||
saveOpenVROption();
|
|
||||||
" />
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<template v-if="!isLinux">
|
|
||||||
<SettingsItem
|
|
||||||
:label="
|
|
||||||
t('view.settings.notifications.notifications.steamvr_notifications.xsoverlay_notifications')
|
|
||||||
">
|
|
||||||
<Switch
|
|
||||||
:model-value="xsNotifications"
|
|
||||||
@update:modelValue="
|
|
||||||
setXsNotifications();
|
|
||||||
saveOpenVROption();
|
|
||||||
" />
|
|
||||||
</SettingsItem>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<SettingsItem
|
|
||||||
:label="
|
|
||||||
t('view.settings.notifications.notifications.steamvr_notifications.wayvr_notifications')
|
|
||||||
">
|
|
||||||
<Switch
|
|
||||||
:model-value="xsNotifications"
|
|
||||||
@update:modelValue="
|
|
||||||
setXsNotifications();
|
|
||||||
saveOpenVROption();
|
|
||||||
" />
|
|
||||||
</SettingsItem>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="!isLinux">
|
|
||||||
<SettingsItem
|
|
||||||
:label="
|
|
||||||
t(
|
|
||||||
'view.settings.notifications.notifications.steamvr_notifications.ovrtoolkit_hud_notifications'
|
|
||||||
)
|
|
||||||
">
|
|
||||||
<Switch
|
|
||||||
:model-value="ovrtHudNotifications"
|
|
||||||
@update:modelValue="
|
|
||||||
setOvrtHudNotifications();
|
|
||||||
saveOpenVROption();
|
|
||||||
" />
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem
|
|
||||||
:label="
|
|
||||||
t(
|
|
||||||
'view.settings.notifications.notifications.steamvr_notifications.ovrtoolkit_wrist_notifications'
|
|
||||||
)
|
|
||||||
">
|
|
||||||
<Switch
|
|
||||||
:model-value="ovrtWristNotifications"
|
|
||||||
@update:modelValue="
|
|
||||||
setOvrtWristNotifications();
|
|
||||||
saveOpenVROption();
|
|
||||||
" />
|
|
||||||
</SettingsItem>
|
|
||||||
</template>
|
|
||||||
</SettingsGroup>
|
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.notifications.notifications.desktop_notifications.header')">
|
<SettingsGroup :title="t('view.settings.notifications.notifications.desktop_notifications.header')">
|
||||||
<SettingsItem
|
<SettingsItem
|
||||||
:label="t('view.settings.notifications.notifications.desktop_notifications.when_to_display')">
|
:label="t('view.settings.notifications.notifications.desktop_notifications.when_to_display')">
|
||||||
@@ -294,7 +128,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<NotificationPositionDialog v-model:isNotificationPositionDialogVisible="isNotificationPositionDialogVisible" />
|
|
||||||
<FeedFiltersDialog v-model:feedFiltersDialogMode="feedFiltersDialogMode" />
|
<FeedFiltersDialog v-model:feedFiltersDialogMode="feedFiltersDialogMode" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -303,7 +136,6 @@
|
|||||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { Slider } from '@/components/ui/slider';
|
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { InputGroupTextareaField } from '@/components/ui/input-group';
|
import { InputGroupTextareaField } from '@/components/ui/input-group';
|
||||||
@@ -312,31 +144,19 @@
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useAdvancedSettingsStore,
|
|
||||||
useNotificationStore,
|
useNotificationStore,
|
||||||
useNotificationsSettingsStore,
|
useNotificationsSettingsStore
|
||||||
useVrStore
|
|
||||||
} from '@/stores';
|
} from '@/stores';
|
||||||
|
|
||||||
import FeedFiltersDialog from '../../dialogs/FeedFiltersDialog.vue';
|
import FeedFiltersDialog from '../../dialogs/FeedFiltersDialog.vue';
|
||||||
import NotificationPositionDialog from '../../dialogs/NotificationPositionDialog.vue';
|
|
||||||
import SettingsGroup from '../SettingsGroup.vue';
|
import SettingsGroup from '../SettingsGroup.vue';
|
||||||
import SettingsItem from '../SettingsItem.vue';
|
import SettingsItem from '../SettingsItem.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const notificationsSettingsStore = useNotificationsSettingsStore();
|
const notificationsSettingsStore = useNotificationsSettingsStore();
|
||||||
const advancedSettingsStore = useAdvancedSettingsStore();
|
|
||||||
const { saveOpenVROption } = useVrStore();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
overlayToast,
|
|
||||||
openVR,
|
|
||||||
overlayNotifications,
|
|
||||||
xsNotifications,
|
|
||||||
ovrtHudNotifications,
|
|
||||||
ovrtWristNotifications,
|
|
||||||
imageNotifications,
|
|
||||||
desktopToast,
|
desktopToast,
|
||||||
afkDesktopToast,
|
afkDesktopToast,
|
||||||
notificationTTS,
|
notificationTTS,
|
||||||
@@ -346,42 +166,19 @@
|
|||||||
TTSvoices
|
TTSvoices
|
||||||
} = storeToRefs(notificationsSettingsStore);
|
} = storeToRefs(notificationsSettingsStore);
|
||||||
|
|
||||||
const { notificationOpacity } = storeToRefs(advancedSettingsStore);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setOverlayToast,
|
|
||||||
setOpenVR,
|
|
||||||
setOverlayNotifications,
|
|
||||||
setXsNotifications,
|
|
||||||
setOvrtHudNotifications,
|
|
||||||
setOvrtWristNotifications,
|
|
||||||
setImageNotifications,
|
|
||||||
setDesktopToast,
|
setDesktopToast,
|
||||||
setAfkDesktopToast,
|
setAfkDesktopToast,
|
||||||
setNotificationTTSNickName,
|
setNotificationTTSNickName,
|
||||||
getTTSVoiceName,
|
getTTSVoiceName,
|
||||||
changeTTSVoice,
|
changeTTSVoice,
|
||||||
saveNotificationTTS,
|
saveNotificationTTS,
|
||||||
testNotificationTTS,
|
testNotificationTTS
|
||||||
promptNotificationTimeout
|
|
||||||
} = notificationsSettingsStore;
|
} = notificationsSettingsStore;
|
||||||
|
|
||||||
const { testNotification } = useNotificationStore();
|
const { testNotification } = useNotificationStore();
|
||||||
|
|
||||||
const { setNotificationOpacity } = advancedSettingsStore;
|
|
||||||
|
|
||||||
const feedFiltersDialogMode = ref('');
|
const feedFiltersDialogMode = ref('');
|
||||||
const isNotificationPositionDialogVisible = ref(false);
|
|
||||||
const isLinux = computed(() => LINUX);
|
|
||||||
const notificationOpacityValue = computed({
|
|
||||||
get: () => [notificationOpacity.value],
|
|
||||||
set: (value) => {
|
|
||||||
const next = value?.[0];
|
|
||||||
if (typeof next === 'number') {
|
|
||||||
setNotificationOpacity(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const ttsVoiceIndex = computed({
|
const ttsVoiceIndex = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
@@ -402,11 +199,4 @@
|
|||||||
function showNotyFeedFiltersDialog() {
|
function showNotyFeedFiltersDialog() {
|
||||||
feedFiltersDialogMode.value = 'noty';
|
feedFiltersDialogMode.value = 'noty';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function showNotificationPositionDialog() {
|
|
||||||
isNotificationPositionDialogVisible.value = true;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col gap-10 py-2">
|
||||||
|
<SettingsGroup :title="t('view.settings.social.interaction.header')">
|
||||||
|
<SettingsItem
|
||||||
|
:label="t('view.settings.appearance.user_dialog.recent_action_cooldown')"
|
||||||
|
:description="t('view.settings.appearance.user_dialog.recent_action_cooldown_description')">
|
||||||
|
<Switch :model-value="recentActionCooldownEnabled" @update:modelValue="setRecentActionCooldownEnabled" />
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem
|
||||||
|
v-if="recentActionCooldownEnabled"
|
||||||
|
:label="t('view.settings.appearance.user_dialog.recent_action_cooldown_minutes')">
|
||||||
|
<NumberField
|
||||||
|
:model-value="recentActionCooldownMinutes"
|
||||||
|
:min="1"
|
||||||
|
:max="1440"
|
||||||
|
:step="1"
|
||||||
|
:format-options="{ maximumFractionDigits: 0 }"
|
||||||
|
class="w-32"
|
||||||
|
@update:modelValue="setRecentActionCooldownMinutes">
|
||||||
|
<NumberFieldContent>
|
||||||
|
<NumberFieldDecrement />
|
||||||
|
<NumberFieldInput />
|
||||||
|
<NumberFieldIncrement />
|
||||||
|
</NumberFieldContent>
|
||||||
|
</NumberField>
|
||||||
|
</SettingsItem>
|
||||||
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<SettingsGroup>
|
||||||
|
<template #description>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<span class="text-base font-semibold text-foreground">{{ t('view.settings.general.favorites.header') }}</span>
|
||||||
|
<TooltipWrapper side="top" :content="t('view.settings.general.favorites.header_tooltip')">
|
||||||
|
<Info class="size-3 text-muted-foreground cursor-help" />
|
||||||
|
</TooltipWrapper>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
:model-value="localFavoriteFriendsGroups"
|
||||||
|
multiple
|
||||||
|
@update:modelValue="setLocalFavoriteFriendsGroups">
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue :placeholder="t('view.settings.general.favorites.group_placeholder')" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectItem v-for="group in favoriteFriendGroups" :key="group.key" :value="group.key">
|
||||||
|
{{ group.displayName }}
|
||||||
|
</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
<template v-if="localFriendFavoriteGroups.length">
|
||||||
|
<SelectSeparator />
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectItem
|
||||||
|
v-for="group in localFriendFavoriteGroups"
|
||||||
|
:key="'local:' + group"
|
||||||
|
:value="'local:' + group">
|
||||||
|
{{ group }}
|
||||||
|
</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
</template>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</SettingsGroup>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import { Info } from 'lucide-vue-next';
|
||||||
|
import {
|
||||||
|
NumberField,
|
||||||
|
NumberFieldContent,
|
||||||
|
NumberFieldDecrement,
|
||||||
|
NumberFieldIncrement,
|
||||||
|
NumberFieldInput
|
||||||
|
} from '@/components/ui/number-field';
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectGroup,
|
||||||
|
SelectItem,
|
||||||
|
SelectSeparator,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue
|
||||||
|
} from '@/components/ui/select';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import { useFavoriteStore, useGeneralSettingsStore } from '@/stores';
|
||||||
|
|
||||||
|
import SettingsGroup from '../SettingsGroup.vue';
|
||||||
|
import SettingsItem from '../SettingsItem.vue';
|
||||||
|
import { TooltipWrapper } from '@/components/ui/tooltip';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const generalSettingsStore = useGeneralSettingsStore();
|
||||||
|
const favoriteStore = useFavoriteStore();
|
||||||
|
|
||||||
|
const {
|
||||||
|
recentActionCooldownEnabled,
|
||||||
|
recentActionCooldownMinutes,
|
||||||
|
localFavoriteFriendsGroups
|
||||||
|
} = storeToRefs(generalSettingsStore);
|
||||||
|
|
||||||
|
const {
|
||||||
|
setRecentActionCooldownEnabled,
|
||||||
|
setRecentActionCooldownMinutes,
|
||||||
|
setLocalFavoriteFriendsGroups
|
||||||
|
} = generalSettingsStore;
|
||||||
|
|
||||||
|
const { favoriteFriendGroups, localFriendFavoriteGroups } = storeToRefs(favoriteStore);
|
||||||
|
</script>
|
||||||
+2
-55
@@ -121,44 +121,6 @@
|
|||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
<SettingsGroup>
|
|
||||||
<template #description>
|
|
||||||
<div class="flex items-center gap-1.5">
|
|
||||||
<span class="text-base font-semibold text-foreground">{{ t('view.settings.general.favorites.header') }}</span>
|
|
||||||
<TooltipWrapper side="top" :content="t('view.settings.general.favorites.header_tooltip')">
|
|
||||||
<Info class="size-3 text-muted-foreground cursor-help" />
|
|
||||||
</TooltipWrapper>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<Select
|
|
||||||
:model-value="localFavoriteFriendsGroups"
|
|
||||||
multiple
|
|
||||||
@update:modelValue="setLocalFavoriteFriendsGroups">
|
|
||||||
<SelectTrigger>
|
|
||||||
<SelectValue :placeholder="t('view.settings.general.favorites.group_placeholder')" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectGroup>
|
|
||||||
<SelectItem v-for="group in favoriteFriendGroups" :key="group.key" :value="group.key">
|
|
||||||
{{ group.displayName }}
|
|
||||||
</SelectItem>
|
|
||||||
</SelectGroup>
|
|
||||||
<template v-if="localFriendFavoriteGroups.length">
|
|
||||||
<SelectSeparator />
|
|
||||||
<SelectGroup>
|
|
||||||
<SelectItem
|
|
||||||
v-for="group in localFriendFavoriteGroups"
|
|
||||||
:key="'local:' + group"
|
|
||||||
:value="'local:' + group">
|
|
||||||
{{ group }}
|
|
||||||
</SelectItem>
|
|
||||||
</SelectGroup>
|
|
||||||
</template>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</SettingsGroup>
|
|
||||||
|
|
||||||
<SettingsGroup :title="t('view.settings.general.contributors.header')">
|
<SettingsGroup :title="t('view.settings.general.contributors.header')">
|
||||||
<div>
|
<div>
|
||||||
<img
|
<img
|
||||||
@@ -198,21 +160,11 @@
|
|||||||
import { computed, defineAsyncComponent, ref } from 'vue';
|
import { computed, defineAsyncComponent, ref } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { Info } from 'lucide-vue-next';
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectGroup,
|
|
||||||
SelectItem,
|
|
||||||
SelectSeparator,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue
|
|
||||||
} from '@/components/ui/select';
|
|
||||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||||
import { useFavoriteStore, useGeneralSettingsStore, useVRCXUpdaterStore } from '@/stores';
|
import { useGeneralSettingsStore, useVRCXUpdaterStore } from '@/stores';
|
||||||
import { links } from '@/shared/constants';
|
import { links } from '@/shared/constants';
|
||||||
import { openExternalLink } from '@/shared/utils';
|
import { openExternalLink } from '@/shared/utils';
|
||||||
|
|
||||||
@@ -223,15 +175,13 @@
|
|||||||
|
|
||||||
const generalSettingsStore = useGeneralSettingsStore();
|
const generalSettingsStore = useGeneralSettingsStore();
|
||||||
const vrcxUpdaterStore = useVRCXUpdaterStore();
|
const vrcxUpdaterStore = useVRCXUpdaterStore();
|
||||||
const favoriteStore = useFavoriteStore();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isStartAtWindowsStartup,
|
isStartAtWindowsStartup,
|
||||||
isStartAsMinimizedState,
|
isStartAsMinimizedState,
|
||||||
isCloseToTray,
|
isCloseToTray,
|
||||||
disableGpuAcceleration,
|
disableGpuAcceleration,
|
||||||
disableVrOverlayGpuAcceleration,
|
disableVrOverlayGpuAcceleration
|
||||||
localFavoriteFriendsGroups
|
|
||||||
} = storeToRefs(generalSettingsStore);
|
} = storeToRefs(generalSettingsStore);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -240,12 +190,9 @@
|
|||||||
setIsCloseToTray,
|
setIsCloseToTray,
|
||||||
setDisableGpuAcceleration,
|
setDisableGpuAcceleration,
|
||||||
setDisableVrOverlayGpuAcceleration,
|
setDisableVrOverlayGpuAcceleration,
|
||||||
setLocalFavoriteFriendsGroups,
|
|
||||||
promptProxySettings
|
promptProxySettings
|
||||||
} = generalSettingsStore;
|
} = generalSettingsStore;
|
||||||
|
|
||||||
const { favoriteFriendGroups, localFriendFavoriteGroups } = storeToRefs(favoriteStore);
|
|
||||||
|
|
||||||
const { appVersion, autoUpdateVRCX, latestAppVersion, noUpdater } = storeToRefs(vrcxUpdaterStore);
|
const { appVersion, autoUpdateVRCX, latestAppVersion, noUpdater } = storeToRefs(vrcxUpdaterStore);
|
||||||
const { setAutoUpdateVRCX, checkForVRCXUpdate, showVRCXUpdateDialog, showChangeLogDialog } = vrcxUpdaterStore;
|
const { setAutoUpdateVRCX, checkForVRCXUpdate, showVRCXUpdateDialog, showChangeLogDialog } = vrcxUpdaterStore;
|
||||||
|
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col gap-10 py-2">
|
||||||
|
<!-- VR Core -->
|
||||||
|
<SettingsGroup :title="t('view.settings.vr.vr_core.header')">
|
||||||
|
<SettingsItem
|
||||||
|
:label="t('view.settings.notifications.notifications.steamvr_notifications.steamvr_overlay')">
|
||||||
|
<Switch
|
||||||
|
:model-value="openVR"
|
||||||
|
@update:modelValue="
|
||||||
|
setOpenVR();
|
||||||
|
saveOpenVROption();
|
||||||
|
" />
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem
|
||||||
|
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.start_overlay_with')">
|
||||||
|
<RadioGroup
|
||||||
|
:model-value="openVRAlways ? 'true' : 'false'"
|
||||||
|
:disabled="!openVR"
|
||||||
|
class="gap-2 flex"
|
||||||
|
@update:modelValue="handleOpenVRAlwaysRadio">
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<RadioGroupItem id="openVRAlways-false" value="false" />
|
||||||
|
<label for="openVRAlways-false">{{ 'VRChat' }}</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<RadioGroupItem id="openVRAlways-true" value="true" />
|
||||||
|
<label for="openVRAlways-true">{{ 'SteamVR' }}</label>
|
||||||
|
</div>
|
||||||
|
</RadioGroup>
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<template v-if="!isLinux">
|
||||||
|
<SettingsItem
|
||||||
|
:label="
|
||||||
|
t('view.settings.notifications.notifications.steamvr_notifications.xsoverlay_notifications')
|
||||||
|
">
|
||||||
|
<Switch
|
||||||
|
:model-value="xsNotifications"
|
||||||
|
@update:modelValue="
|
||||||
|
setXsNotifications();
|
||||||
|
saveOpenVROption();
|
||||||
|
" />
|
||||||
|
</SettingsItem>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<SettingsItem
|
||||||
|
:label="
|
||||||
|
t('view.settings.notifications.notifications.steamvr_notifications.wayvr_notifications')
|
||||||
|
">
|
||||||
|
<Switch
|
||||||
|
:model-value="xsNotifications"
|
||||||
|
@update:modelValue="
|
||||||
|
setXsNotifications();
|
||||||
|
saveOpenVROption();
|
||||||
|
" />
|
||||||
|
</SettingsItem>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="!isLinux">
|
||||||
|
<SettingsItem
|
||||||
|
:label="
|
||||||
|
t(
|
||||||
|
'view.settings.notifications.notifications.steamvr_notifications.ovrtoolkit_hud_notifications'
|
||||||
|
)
|
||||||
|
">
|
||||||
|
<Switch
|
||||||
|
:model-value="ovrtHudNotifications"
|
||||||
|
@update:modelValue="
|
||||||
|
setOvrtHudNotifications();
|
||||||
|
saveOpenVROption();
|
||||||
|
" />
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem
|
||||||
|
:label="
|
||||||
|
t(
|
||||||
|
'view.settings.notifications.notifications.steamvr_notifications.ovrtoolkit_wrist_notifications'
|
||||||
|
)
|
||||||
|
">
|
||||||
|
<Switch
|
||||||
|
:model-value="ovrtWristNotifications"
|
||||||
|
@update:modelValue="
|
||||||
|
setOvrtWristNotifications();
|
||||||
|
saveOpenVROption();
|
||||||
|
" />
|
||||||
|
</SettingsItem>
|
||||||
|
</template>
|
||||||
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<!-- VR Notifications -->
|
||||||
|
<SettingsGroup :title="t('view.settings.vr.vr_notifications.header')">
|
||||||
|
<SettingsItem
|
||||||
|
:label="t('view.settings.notifications.notifications.desktop_notifications.when_to_display')">
|
||||||
|
<ToggleGroup
|
||||||
|
type="single"
|
||||||
|
required
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
:model-value="overlayToast"
|
||||||
|
:disabled="
|
||||||
|
(!overlayNotifications || !openVR) &&
|
||||||
|
!xsNotifications &&
|
||||||
|
!ovrtHudNotifications &&
|
||||||
|
!ovrtWristNotifications
|
||||||
|
"
|
||||||
|
@update:model-value="
|
||||||
|
setOverlayToast($event);
|
||||||
|
saveOpenVROption();
|
||||||
|
">
|
||||||
|
<ToggleGroupItem value="Never">{{
|
||||||
|
t('view.settings.notifications.notifications.conditions.never')
|
||||||
|
}}</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="Game Running">{{
|
||||||
|
t('view.settings.notifications.notifications.conditions.inside_vrchat')
|
||||||
|
}}</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="Game Closed">{{
|
||||||
|
t('view.settings.notifications.notifications.conditions.outside_vrchat')
|
||||||
|
}}</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="Always">{{
|
||||||
|
t('view.settings.notifications.notifications.conditions.always')
|
||||||
|
}}</ToggleGroupItem>
|
||||||
|
</ToggleGroup>
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem
|
||||||
|
:label="
|
||||||
|
t('view.settings.notifications.notifications.steamvr_notifications.overlay_notifications')
|
||||||
|
">
|
||||||
|
<Switch
|
||||||
|
:model-value="overlayNotifications"
|
||||||
|
:disabled="!openVR"
|
||||||
|
@update:modelValue="
|
||||||
|
setOverlayNotifications();
|
||||||
|
saveOpenVROption();
|
||||||
|
" />
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem
|
||||||
|
:label="
|
||||||
|
t('view.settings.notifications.notifications.steamvr_notifications.notification_position')
|
||||||
|
">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
:disabled="!overlayNotifications || !openVR"
|
||||||
|
@click="showNotificationPositionDialog"
|
||||||
|
>{{
|
||||||
|
t('view.settings.notifications.notifications.steamvr_notifications.notification_position')
|
||||||
|
}}</Button
|
||||||
|
>
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem
|
||||||
|
:label="
|
||||||
|
t('view.settings.notifications.notifications.steamvr_notifications.notification_opacity')
|
||||||
|
">
|
||||||
|
<div class="w-75 max-w-full pt-1">
|
||||||
|
<Slider v-model="notificationOpacityValue" :min="0" :max="100" />
|
||||||
|
</div>
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem
|
||||||
|
:label="
|
||||||
|
t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout')
|
||||||
|
">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
:disabled="(!overlayNotifications || !openVR) && !xsNotifications"
|
||||||
|
@click="promptNotificationTimeout"
|
||||||
|
>{{
|
||||||
|
t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout')
|
||||||
|
}}</Button
|
||||||
|
>
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem
|
||||||
|
:label="t('view.settings.notifications.notifications.steamvr_notifications.user_images')">
|
||||||
|
<Switch
|
||||||
|
:model-value="imageNotifications"
|
||||||
|
@update:modelValue="
|
||||||
|
setImageNotifications();
|
||||||
|
saveOpenVROption();
|
||||||
|
" />
|
||||||
|
</SettingsItem>
|
||||||
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<!-- Wrist Overlay -->
|
||||||
|
<WristOverlaySettings @open-feed-filters="showWristFeedFiltersDialog" />
|
||||||
|
|
||||||
|
<!-- VR Extras -->
|
||||||
|
<SettingsGroup :title="t('view.settings.vr.vr_extras.header')">
|
||||||
|
<SettingsItem :label="t('view.settings.advanced.advanced.video_progress_pie.header')"
|
||||||
|
:description="t('view.settings.advanced.advanced.video_progress_pie.enable_tooltip')">
|
||||||
|
<Switch
|
||||||
|
:model-value="progressPie"
|
||||||
|
:disabled="!openVR"
|
||||||
|
@update:modelValue="changeYouTubeApi('VRCX_progressPie')" />
|
||||||
|
</SettingsItem>
|
||||||
|
|
||||||
|
<SettingsItem :label="t('view.settings.advanced.advanced.video_progress_pie.dance_world_only')">
|
||||||
|
<Switch
|
||||||
|
:model-value="progressPieFilter"
|
||||||
|
:disabled="!openVR"
|
||||||
|
@update:modelValue="changeYouTubeApi('VRCX_progressPieFilter')" />
|
||||||
|
</SettingsItem>
|
||||||
|
</SettingsGroup>
|
||||||
|
|
||||||
|
<NotificationPositionDialog v-model:isNotificationPositionDialogVisible="isNotificationPositionDialogVisible" />
|
||||||
|
<FeedFiltersDialog v-model:feedFiltersDialogMode="feedFiltersDialogMode" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import { Slider } from '@/components/ui/slider';
|
||||||
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||||
|
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import {
|
||||||
|
useAdvancedSettingsStore,
|
||||||
|
useNotificationsSettingsStore,
|
||||||
|
useVrStore,
|
||||||
|
useWristOverlaySettingsStore
|
||||||
|
} from '@/stores';
|
||||||
|
|
||||||
|
import FeedFiltersDialog from '../../dialogs/FeedFiltersDialog.vue';
|
||||||
|
import NotificationPositionDialog from '../../dialogs/NotificationPositionDialog.vue';
|
||||||
|
import WristOverlaySettings from '../WristOverlaySettings.vue';
|
||||||
|
import SettingsGroup from '../SettingsGroup.vue';
|
||||||
|
import SettingsItem from '../SettingsItem.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const notificationsSettingsStore = useNotificationsSettingsStore();
|
||||||
|
const advancedSettingsStore = useAdvancedSettingsStore();
|
||||||
|
const wristOverlaySettingsStore = useWristOverlaySettingsStore();
|
||||||
|
const { saveOpenVROption } = useVrStore();
|
||||||
|
const { updateVRLastLocation, updateOpenVR } = useVrStore();
|
||||||
|
|
||||||
|
const {
|
||||||
|
overlayToast,
|
||||||
|
openVR,
|
||||||
|
overlayNotifications,
|
||||||
|
xsNotifications,
|
||||||
|
ovrtHudNotifications,
|
||||||
|
ovrtWristNotifications,
|
||||||
|
imageNotifications
|
||||||
|
} = storeToRefs(notificationsSettingsStore);
|
||||||
|
|
||||||
|
const { notificationOpacity } = storeToRefs(advancedSettingsStore);
|
||||||
|
|
||||||
|
const { openVRAlways } = storeToRefs(wristOverlaySettingsStore);
|
||||||
|
const { setOpenVRAlways } = wristOverlaySettingsStore;
|
||||||
|
|
||||||
|
const {
|
||||||
|
progressPie,
|
||||||
|
progressPieFilter
|
||||||
|
} = storeToRefs(advancedSettingsStore);
|
||||||
|
|
||||||
|
const {
|
||||||
|
setOverlayToast,
|
||||||
|
setOpenVR,
|
||||||
|
setOverlayNotifications,
|
||||||
|
setXsNotifications,
|
||||||
|
setOvrtHudNotifications,
|
||||||
|
setOvrtWristNotifications,
|
||||||
|
setImageNotifications,
|
||||||
|
promptNotificationTimeout
|
||||||
|
} = notificationsSettingsStore;
|
||||||
|
|
||||||
|
const { setNotificationOpacity } = advancedSettingsStore;
|
||||||
|
|
||||||
|
const isNotificationPositionDialogVisible = ref(false);
|
||||||
|
const feedFiltersDialogMode = ref('');
|
||||||
|
const isLinux = computed(() => LINUX);
|
||||||
|
|
||||||
|
const notificationOpacityValue = computed({
|
||||||
|
get: () => [notificationOpacity.value],
|
||||||
|
set: (value) => {
|
||||||
|
const next = value?.[0];
|
||||||
|
if (typeof next === 'number') {
|
||||||
|
setNotificationOpacity(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function showNotificationPositionDialog() {
|
||||||
|
isNotificationPositionDialogVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function showWristFeedFiltersDialog() {
|
||||||
|
feedFiltersDialogMode.value = 'wrist';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
function handleOpenVRAlwaysRadio(value) {
|
||||||
|
const nextValue = value === 'true';
|
||||||
|
if (nextValue !== openVRAlways.value) {
|
||||||
|
setOpenVRAlways();
|
||||||
|
saveOpenVROption();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param configKey
|
||||||
|
*/
|
||||||
|
async function changeYouTubeApi(configKey = '') {
|
||||||
|
if (configKey === 'VRCX_progressPie') {
|
||||||
|
advancedSettingsStore.setProgressPie();
|
||||||
|
} else if (configKey === 'VRCX_progressPieFilter') {
|
||||||
|
advancedSettingsStore.setProgressPieFilter();
|
||||||
|
}
|
||||||
|
updateVRLastLocation();
|
||||||
|
updateOpenVR();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<WristOverlaySettings @open-feed-filters="showWristFeedFiltersDialog" />
|
|
||||||
<FeedFiltersDialog v-model:feedFiltersDialogMode="feedFiltersDialogMode" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
import FeedFiltersDialog from '../../dialogs/FeedFiltersDialog.vue';
|
|
||||||
import WristOverlaySettings from '../WristOverlaySettings.vue';
|
|
||||||
|
|
||||||
const feedFiltersDialogMode = ref('');
|
|
||||||
|
|
||||||
function showWristFeedFiltersDialog() {
|
|
||||||
feedFiltersDialogMode.value = 'wrist';
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
||||||
import { mount } from '@vue/test-utils';
|
|
||||||
|
|
||||||
const mocks = vi.hoisted(() => ({
|
|
||||||
discordStore: {
|
|
||||||
setDiscordActive: vi.fn(),
|
|
||||||
setDiscordInstance: vi.fn(),
|
|
||||||
setDiscordHideInvite: vi.fn(),
|
|
||||||
setDiscordJoinButton: vi.fn(),
|
|
||||||
setDiscordHideImage: vi.fn(),
|
|
||||||
setDiscordShowPlatform: vi.fn(),
|
|
||||||
setDiscordWorldIntegration: vi.fn(),
|
|
||||||
setDiscordWorldNameAsDiscordStatus: vi.fn(),
|
|
||||||
saveDiscordOption: vi.fn(),
|
|
||||||
discordActive: { __v_isRef: true, value: true },
|
|
||||||
discordInstance: { __v_isRef: true, value: true },
|
|
||||||
discordHideInvite: { __v_isRef: true, value: false },
|
|
||||||
discordJoinButton: { __v_isRef: true, value: true },
|
|
||||||
discordHideImage: { __v_isRef: true, value: false },
|
|
||||||
discordShowPlatform: { __v_isRef: true, value: true },
|
|
||||||
discordWorldIntegration: { __v_isRef: true, value: true },
|
|
||||||
discordWorldNameAsDiscordStatus: { __v_isRef: true, value: false }
|
|
||||||
},
|
|
||||||
showVRChatConfig: vi.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock('pinia', async (i) => ({ ...(await i()), storeToRefs: (s) => s }));
|
|
||||||
vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (k) => k }) }));
|
|
||||||
vi.mock('../../../../../stores', () => ({
|
|
||||||
useDiscordPresenceSettingsStore: () => mocks.discordStore,
|
|
||||||
useAdvancedSettingsStore: () => ({
|
|
||||||
showVRChatConfig: (...a) => mocks.showVRChatConfig(...a)
|
|
||||||
})
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock('@/components/ui/switch', () => ({
|
|
||||||
Switch: {
|
|
||||||
props: ['modelValue', 'disabled'],
|
|
||||||
emits: ['update:modelValue'],
|
|
||||||
template:
|
|
||||||
'<button data-testid="switch" :data-disabled="disabled || undefined" @click="$emit(\'update:modelValue\', !modelValue)"><slot /></button>'
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock('../../SettingsGroup.vue', () => ({
|
|
||||||
default: { template: '<div><slot /><slot name="description" /></div>' }
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock('../../SettingsItem.vue', () => ({
|
|
||||||
default: {
|
|
||||||
props: ['label', 'description'],
|
|
||||||
template: '<div :data-label="label"><slot /></div>'
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
import DiscordPresenceTab from '../DiscordPresenceTab.vue';
|
|
||||||
|
|
||||||
describe('DiscordPresenceTab.vue', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
mocks.discordStore.discordActive.value = true;
|
|
||||||
mocks.discordStore.discordInstance.value = true;
|
|
||||||
mocks.discordStore.setDiscordActive.mockClear();
|
|
||||||
mocks.discordStore.saveDiscordOption.mockClear();
|
|
||||||
mocks.showVRChatConfig.mockClear();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('opens VRChat config and handles switch changes', async () => {
|
|
||||||
const wrapper = mount(DiscordPresenceTab);
|
|
||||||
|
|
||||||
const tooltipRow = wrapper
|
|
||||||
.findAll('p')
|
|
||||||
.find((node) =>
|
|
||||||
node
|
|
||||||
.text()
|
|
||||||
.includes(
|
|
||||||
'view.settings.discord_presence.discord_presence.enable_tooltip'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
expect(tooltipRow).toBeTruthy();
|
|
||||||
await tooltipRow.trigger('click');
|
|
||||||
|
|
||||||
expect(mocks.showVRChatConfig).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
const switches = wrapper.findAll('[data-testid="switch"]');
|
|
||||||
await switches[0].trigger('click');
|
|
||||||
expect(mocks.discordStore.setDiscordActive).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mocks.discordStore.saveDiscordOption).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes disabled state to dependent switches when discord is disabled', () => {
|
|
||||||
mocks.discordStore.discordActive.value = false;
|
|
||||||
const wrapper = mount(DiscordPresenceTab);
|
|
||||||
|
|
||||||
const switches = wrapper.findAll('[data-testid="switch"]');
|
|
||||||
const worldIntegrationSwitch = switches[1];
|
|
||||||
|
|
||||||
expect(worldIntegrationSwitch?.attributes('data-disabled')).toBe('true');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import { describe, expect, it, vi } from 'vitest';
|
|
||||||
import { mount } from '@vue/test-utils';
|
|
||||||
|
|
||||||
vi.mock('../../WristOverlaySettings.vue', () => ({
|
|
||||||
default: {
|
|
||||||
emits: ['open-feed-filters'],
|
|
||||||
template:
|
|
||||||
'<button data-testid="open-filters" @click="$emit(\'open-feed-filters\')">open</button>'
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock('../../../dialogs/FeedFiltersDialog.vue', () => ({
|
|
||||||
default: {
|
|
||||||
props: ['feedFiltersDialogMode'],
|
|
||||||
template:
|
|
||||||
'<div data-testid="feed-dialog" :data-mode="feedFiltersDialogMode" />'
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
import WristOverlayTab from '../WristOverlayTab.vue';
|
|
||||||
|
|
||||||
describe('WristOverlayTab.vue', () => {
|
|
||||||
it('sets feed dialog mode to wrist when child emits open-feed-filters', async () => {
|
|
||||||
const wrapper = mount(WristOverlayTab);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
wrapper.get('[data-testid="feed-dialog"]').attributes('data-mode')
|
|
||||||
).toBe('');
|
|
||||||
|
|
||||||
await wrapper.get('[data-testid="open-filters"]').trigger('click');
|
|
||||||
|
|
||||||
expect(
|
|
||||||
wrapper.get('[data-testid="feed-dialog"]').attributes('data-mode')
|
|
||||||
).toBe('wrist');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -17,15 +17,6 @@
|
|||||||
>
|
>
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
|
|
||||||
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.steamvr_overlay')">
|
|
||||||
<Switch
|
|
||||||
:model-value="openVR"
|
|
||||||
@update:modelValue="
|
|
||||||
setOpenVR();
|
|
||||||
saveOpenVROption();
|
|
||||||
" />
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_overlay')">
|
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_overlay')">
|
||||||
<Switch
|
<Switch
|
||||||
:model-value="overlayWrist"
|
:model-value="overlayWrist"
|
||||||
@@ -46,24 +37,6 @@
|
|||||||
" />
|
" />
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
|
|
||||||
<SettingsItem
|
|
||||||
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.start_overlay_with')">
|
|
||||||
<RadioGroup
|
|
||||||
:model-value="openVRAlways ? 'true' : 'false'"
|
|
||||||
:disabled="!openVR"
|
|
||||||
class="gap-2 flex"
|
|
||||||
@update:modelValue="handleOpenVRAlwaysRadio">
|
|
||||||
<div class="flex items-center space-x-2">
|
|
||||||
<RadioGroupItem id="openVRAlways-false" value="false" />
|
|
||||||
<label for="openVRAlways-false">{{ 'VRChat' }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center space-x-2">
|
|
||||||
<RadioGroupItem id="openVRAlways-true" value="true" />
|
|
||||||
<label for="openVRAlways-true">{{ 'SteamVR' }}</label>
|
|
||||||
</div>
|
|
||||||
</RadioGroup>
|
|
||||||
</SettingsItem>
|
|
||||||
|
|
||||||
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button')">
|
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button')">
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
:model-value="overlaybutton ? 'true' : 'false'"
|
:model-value="overlaybutton ? 'true' : 'false'"
|
||||||
@@ -196,10 +169,10 @@
|
|||||||
|
|
||||||
const { openVR } = storeToRefs(notificationsSettingsStore);
|
const { openVR } = storeToRefs(notificationsSettingsStore);
|
||||||
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
overlayWrist,
|
overlayWrist,
|
||||||
hidePrivateFromFeed,
|
hidePrivateFromFeed,
|
||||||
openVRAlways,
|
|
||||||
overlaybutton,
|
overlaybutton,
|
||||||
overlayHand,
|
overlayHand,
|
||||||
vrBackgroundEnabled,
|
vrBackgroundEnabled,
|
||||||
@@ -210,12 +183,9 @@
|
|||||||
pcUptimeOnFeed
|
pcUptimeOnFeed
|
||||||
} = storeToRefs(wristOverlaySettingsStore);
|
} = storeToRefs(wristOverlaySettingsStore);
|
||||||
|
|
||||||
const { setOpenVR } = notificationsSettingsStore;
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setOverlayWrist,
|
setOverlayWrist,
|
||||||
setHidePrivateFromFeed,
|
setHidePrivateFromFeed,
|
||||||
setOpenVRAlways,
|
|
||||||
setOverlaybutton,
|
setOverlaybutton,
|
||||||
setOverlayHand,
|
setOverlayHand,
|
||||||
setVrBackgroundEnabled,
|
setVrBackgroundEnabled,
|
||||||
@@ -228,18 +198,6 @@
|
|||||||
|
|
||||||
const { saveOpenVROption } = useVrStore();
|
const { saveOpenVROption } = useVrStore();
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
function handleOpenVRAlwaysRadio(value) {
|
|
||||||
const nextValue = value === 'true';
|
|
||||||
if (nextValue !== openVRAlways.value) {
|
|
||||||
setOpenVRAlways();
|
|
||||||
saveOpenVROption();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param value
|
* @param value
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ const mocks = vi.hoisted(() => ({
|
|||||||
wristStore: {
|
wristStore: {
|
||||||
overlayWrist: { value: true },
|
overlayWrist: { value: true },
|
||||||
hidePrivateFromFeed: { value: false },
|
hidePrivateFromFeed: { value: false },
|
||||||
openVRAlways: { value: false },
|
|
||||||
overlaybutton: { value: false },
|
overlaybutton: { value: false },
|
||||||
overlayHand: { value: '1' },
|
overlayHand: { value: '1' },
|
||||||
vrBackgroundEnabled: { value: false },
|
vrBackgroundEnabled: { value: false },
|
||||||
@@ -20,7 +19,6 @@ const mocks = vi.hoisted(() => ({
|
|||||||
pcUptimeOnFeed: { value: false },
|
pcUptimeOnFeed: { value: false },
|
||||||
setOverlayWrist: vi.fn(),
|
setOverlayWrist: vi.fn(),
|
||||||
setHidePrivateFromFeed: vi.fn(),
|
setHidePrivateFromFeed: vi.fn(),
|
||||||
setOpenVRAlways: vi.fn(),
|
|
||||||
setOverlaybutton: vi.fn(),
|
setOverlaybutton: vi.fn(),
|
||||||
setOverlayHand: vi.fn(),
|
setOverlayHand: vi.fn(),
|
||||||
setVrBackgroundEnabled: vi.fn(),
|
setVrBackgroundEnabled: vi.fn(),
|
||||||
@@ -95,10 +93,9 @@ describe('WristOverlaySettings.vue', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocks.notificationsStore.openVR.value = true;
|
mocks.notificationsStore.openVR.value = true;
|
||||||
mocks.wristStore.overlayWrist.value = true;
|
mocks.wristStore.overlayWrist.value = true;
|
||||||
mocks.wristStore.openVRAlways.value = false;
|
|
||||||
mocks.wristStore.overlaybutton.value = false;
|
mocks.wristStore.overlaybutton.value = false;
|
||||||
mocks.notificationsStore.setOpenVR.mockClear();
|
mocks.wristStore.setOverlayWrist.mockClear();
|
||||||
mocks.wristStore.setOpenVRAlways.mockClear();
|
mocks.wristStore.setHidePrivateFromFeed.mockClear();
|
||||||
mocks.wristStore.setOverlaybutton.mockClear();
|
mocks.wristStore.setOverlaybutton.mockClear();
|
||||||
mocks.wristStore.setOverlayHand.mockClear();
|
mocks.wristStore.setOverlayHand.mockClear();
|
||||||
mocks.saveOpenVROption.mockClear();
|
mocks.saveOpenVROption.mockClear();
|
||||||
@@ -107,32 +104,33 @@ describe('WristOverlaySettings.vue', () => {
|
|||||||
it('emits open-feed-filters and handles switch/radio/toggle updates', async () => {
|
it('emits open-feed-filters and handles switch/radio/toggle updates', async () => {
|
||||||
const wrapper = mount(WristOverlaySettings);
|
const wrapper = mount(WristOverlaySettings);
|
||||||
|
|
||||||
|
// Feed filters button emits event
|
||||||
await wrapper.get('[data-testid="filters-btn"]').trigger('click');
|
await wrapper.get('[data-testid="filters-btn"]').trigger('click');
|
||||||
expect(wrapper.emitted('open-feed-filters')).toBeTruthy();
|
expect(wrapper.emitted('open-feed-filters')).toBeTruthy();
|
||||||
|
|
||||||
|
// First switch is now overlayWrist (SteamVR Overlay moved to VrTab)
|
||||||
const switches = wrapper.findAll('[data-testid="switch"]');
|
const switches = wrapper.findAll('[data-testid="switch"]');
|
||||||
await switches[0].trigger('click');
|
await switches[0].trigger('click');
|
||||||
expect(mocks.notificationsStore.setOpenVR).toHaveBeenCalledTimes(1);
|
expect(mocks.wristStore.setOverlayWrist).toHaveBeenCalledTimes(1);
|
||||||
expect(mocks.saveOpenVROption).toHaveBeenCalled();
|
expect(mocks.saveOpenVROption).toHaveBeenCalled();
|
||||||
|
|
||||||
|
// First (and only) radio group is now overlay button (Start Overlay With moved to VrTab)
|
||||||
const radioGroups = wrapper.findAll('[data-testid="radio-group"]');
|
const radioGroups = wrapper.findAll('[data-testid="radio-group"]');
|
||||||
await radioGroups[0].get('[data-testid="radio-true"]').trigger('click');
|
await radioGroups[0].get('[data-testid="radio-true"]').trigger('click');
|
||||||
expect(mocks.wristStore.setOpenVRAlways).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
await radioGroups[1].get('[data-testid="radio-true"]').trigger('click');
|
|
||||||
expect(mocks.wristStore.setOverlaybutton).toHaveBeenCalledTimes(1);
|
expect(mocks.wristStore.setOverlaybutton).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
// Toggle group for overlay hand
|
||||||
await wrapper.get('[data-testid="toggle-right"]').trigger('click');
|
await wrapper.get('[data-testid="toggle-right"]').trigger('click');
|
||||||
expect(mocks.wristStore.setOverlayHand).toHaveBeenCalledWith('2');
|
expect(mocks.wristStore.setOverlayHand).toHaveBeenCalledWith('2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not toggle openVRAlways when the value is unchanged', async () => {
|
it('does not toggle overlaybutton when the value is unchanged', async () => {
|
||||||
mocks.wristStore.openVRAlways.value = true;
|
mocks.wristStore.overlaybutton.value = true;
|
||||||
const wrapper = mount(WristOverlaySettings);
|
const wrapper = mount(WristOverlaySettings);
|
||||||
|
|
||||||
const firstRadio = wrapper.findAll('[data-testid="radio-group"]')[0];
|
const firstRadio = wrapper.findAll('[data-testid="radio-group"]')[0];
|
||||||
await firstRadio.get('[data-testid="radio-true"]').trigger('click');
|
await firstRadio.get('[data-testid="radio-true"]').trigger('click');
|
||||||
|
|
||||||
expect(mocks.wristStore.setOpenVRAlways).not.toHaveBeenCalled();
|
expect(mocks.wristStore.setOverlaybutton).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user