mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-18 22:33:50 +02:00
improve settings ui
This commit is contained in:
@@ -15,7 +15,9 @@
|
||||
"delete": "Delete",
|
||||
"remove": "Remove",
|
||||
"reset": "Reset",
|
||||
"view_details": "View Details"
|
||||
"view_details": "View Details",
|
||||
"configure": "Configure",
|
||||
"refresh": "Refresh"
|
||||
},
|
||||
"sort_by": "Sort by:",
|
||||
"time_units": {
|
||||
@@ -920,7 +922,7 @@
|
||||
"vrcx_memos_description": "Shows notes saved locally in VRCX",
|
||||
"recent_action_cooldown": "Recent Action Indicator",
|
||||
"recent_action_cooldown_description": "Show a clock icon on invite/request actions that were recently performed",
|
||||
"recent_action_cooldown_minutes": "Cooldown (minutes)"
|
||||
"recent_action_cooldown_minutes": "Cooldown (Minutes)"
|
||||
},
|
||||
"user_colors": {
|
||||
"header": "User Colors",
|
||||
@@ -974,7 +976,7 @@
|
||||
},
|
||||
"text_to_speech": {
|
||||
"header": "Text-To-Speech",
|
||||
"when_to_play": "Notification TTS. When to Play",
|
||||
"when_to_play": "Notification TTS",
|
||||
"tts_voice": "TTS Voice",
|
||||
"use_memo_nicknames": "Use Memo Nicknames",
|
||||
"play": "Play",
|
||||
|
||||
@@ -410,6 +410,20 @@ export const useNotificationsSettingsStore = defineStore(
|
||||
speechSynthesis.speak(tts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} seconds - timeout in seconds
|
||||
*/
|
||||
function setNotificationTimeout(seconds) {
|
||||
const ms = Math.trunc(Number(seconds) * 1000);
|
||||
if (isNaN(ms) || ms < 0) return;
|
||||
notificationTimeout.value = ms;
|
||||
configRepository.setString(
|
||||
'VRCX_notificationTimeout',
|
||||
ms.toString()
|
||||
);
|
||||
vrStore.updateVRConfigVars();
|
||||
}
|
||||
|
||||
function promptNotificationTimeout() {
|
||||
modalStore
|
||||
.prompt({
|
||||
@@ -474,6 +488,7 @@ export const useNotificationsSettingsStore = defineStore(
|
||||
testNotificationTTS,
|
||||
speak,
|
||||
changeNotificationPosition,
|
||||
setNotificationTimeout,
|
||||
promptNotificationTimeout
|
||||
};
|
||||
}
|
||||
|
||||
@@ -227,7 +227,9 @@
|
||||
<span v-text="sqliteTableSizes.event"></span
|
||||
></span>
|
||||
</div>
|
||||
</SettingsGroup>
|
||||
|
||||
<SettingsGroup :title="t('view.settings.advanced.advanced.database_cleanup.header')">
|
||||
<SettingsItem
|
||||
:label="t('view.settings.advanced.advanced.database_cleanup.auto_cleanup')"
|
||||
:description="t('view.settings.advanced.advanced.database_cleanup.auto_cleanup_description')">
|
||||
@@ -329,45 +331,38 @@
|
||||
</Dialog>
|
||||
|
||||
<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')">
|
||||
<SettingsItem :label="t('view.profile.game_info.online_users')">
|
||||
<div class="flex items-center gap-2">
|
||||
<TooltipWrapper side="top" :content="t('view.profile.refresh_tooltip')">
|
||||
<Button class="rounded-full" size="icon-sm" variant="outline" @click="refreshConfigTreeData()">
|
||||
<RefreshCcw />
|
||||
</Button>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper side="top" :content="t('view.profile.clear_results_tooltip')">
|
||||
<Button class="rounded-full" size="icon-sm" variant="outline" @click="configTreeData = {}">
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</TooltipWrapper>
|
||||
<span v-if="visits !== null" class="text-sm text-muted-foreground">{{
|
||||
t('view.profile.game_info.user_online', { count: visits })
|
||||
}}</span>
|
||||
<Button size="sm" variant="outline" @click="getVisits">{{ t('common.actions.refresh') }}</Button>
|
||||
</div>
|
||||
<vue-json-pretty
|
||||
v-if="Object.keys(configTreeData).length > 0"
|
||||
:data="configTreeData"
|
||||
:deep="2"
|
||||
:theme="isDarkMode ? 'dark' : 'light'"
|
||||
:height="800"
|
||||
:dynamic-height="false"
|
||||
virtual
|
||||
show-icon />
|
||||
</SettingsGroup>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem :label="t('view.profile.config_json')">
|
||||
<div class="flex items-center gap-2">
|
||||
<Button size="sm" variant="outline" @click="refreshConfigTreeData()">{{
|
||||
t('common.actions.refresh')
|
||||
}}</Button>
|
||||
<Button
|
||||
v-if="Object.keys(configTreeData).length > 0"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
@click="configTreeData = {}"
|
||||
>{{ t('common.actions.clear') }}</Button
|
||||
>
|
||||
</div>
|
||||
</SettingsItem>
|
||||
<vue-json-pretty
|
||||
v-if="Object.keys(configTreeData).length > 0"
|
||||
:data="configTreeData"
|
||||
:deep="2"
|
||||
:theme="isDarkMode ? 'dark' : 'light'"
|
||||
:height="800"
|
||||
:dynamic-height="false"
|
||||
virtual
|
||||
show-icon />
|
||||
</SettingsGroup>
|
||||
|
||||
<template v-if="branch === 'Nightly'">
|
||||
@@ -386,7 +381,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { RefreshCcw, Trash2, TriangleAlert } from 'lucide-vue-next';
|
||||
import { Trash2, TriangleAlert } from 'lucide-vue-next';
|
||||
import { computed, reactive, ref } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
@@ -421,7 +416,6 @@
|
||||
import RegistryBackupDialog from '../../../Tools/dialogs/RegistryBackupDialog.vue';
|
||||
import SettingsGroup from '../SettingsGroup.vue';
|
||||
import SettingsItem from '../SettingsItem.vue';
|
||||
import { TooltipWrapper } from '@/components/ui/tooltip';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -486,7 +480,7 @@
|
||||
} = advancedSettingsStore;
|
||||
|
||||
const configTreeData = ref({});
|
||||
const visits = ref(0);
|
||||
const visits = ref(null);
|
||||
const selectedPurgePeriod = ref('180');
|
||||
const isPurgeDialogVisible = ref(false);
|
||||
|
||||
|
||||
@@ -156,97 +156,120 @@
|
||||
|
||||
<SettingsGroup :title="t('view.settings.interface.lists_tables.header')">
|
||||
<SettingsItem :label="t('view.settings.appearance.appearance.sort_favorite_by')">
|
||||
<RadioGroup
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
required
|
||||
variant="outline"
|
||||
size="sm"
|
||||
:model-value="sortFavorites ? 'true' : 'false'"
|
||||
class="gap-2 flex"
|
||||
@update:modelValue="handleSortFavoritesRadio">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroupItem id="sortFavorites-false" value="false" />
|
||||
<label for="sortFavorites-false">
|
||||
{{ t('view.settings.appearance.appearance.sort_favorite_by_name') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroupItem id="sortFavorites-true" value="true" />
|
||||
<label for="sortFavorites-true">
|
||||
{{ t('view.settings.appearance.appearance.sort_favorite_by_date') }}
|
||||
</label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
@update:model-value="handleSortFavoritesRadio">
|
||||
<ToggleGroupItem value="false">{{
|
||||
t('view.settings.appearance.appearance.sort_favorite_by_name')
|
||||
}}</ToggleGroupItem>
|
||||
<ToggleGroupItem value="true">{{
|
||||
t('view.settings.appearance.appearance.sort_favorite_by_date')
|
||||
}}</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem :label="t('view.settings.appearance.appearance.sort_instance_users_by')">
|
||||
<RadioGroup
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
required
|
||||
variant="outline"
|
||||
size="sm"
|
||||
:model-value="instanceUsersSortAlphabetical ? 'true' : 'false'"
|
||||
class="gap-2 flex"
|
||||
@update:modelValue="handleInstanceUsersSortAlphabeticalRadio">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroupItem id="instanceUsersSortAlphabetical-false" value="false" />
|
||||
<label for="instanceUsersSortAlphabetical-false">
|
||||
{{ t('view.settings.appearance.appearance.sort_instance_users_by_time') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroupItem id="instanceUsersSortAlphabetical-true" value="true" />
|
||||
<label for="instanceUsersSortAlphabetical-true">
|
||||
{{ t('view.settings.appearance.appearance.sort_instance_users_by_alphabet') }}
|
||||
</label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
@update:model-value="handleInstanceUsersSortAlphabeticalRadio">
|
||||
<ToggleGroupItem value="false">{{
|
||||
t('view.settings.appearance.appearance.sort_instance_users_by_time')
|
||||
}}</ToggleGroupItem>
|
||||
<ToggleGroupItem value="true">{{
|
||||
t('view.settings.appearance.appearance.sort_instance_users_by_alphabet')
|
||||
}}</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem :label="t('view.settings.appearance.appearance.table_page_sizes')">
|
||||
<Popover v-model:open="tablePageSizesOpen">
|
||||
<ListboxRoot v-model="tablePageSizesModel" highlight-on-hover multiple>
|
||||
<PopoverAnchor class="inline-flex w-75">
|
||||
<TagsInput v-slot="{ modelValue: tags }" v-model="tablePageSizesModel" class="w-full">
|
||||
<TagsInputItem v-for="item in tags" :key="item.toString()" :value="item.toString()">
|
||||
<TagsInputItemText />
|
||||
<TagsInputItemDelete />
|
||||
</TagsInputItem>
|
||||
<Button size="sm" variant="outline" @click="tablePageSizesDialogOpen = true">{{
|
||||
t('common.actions.configure')
|
||||
}}</Button>
|
||||
|
||||
<ListboxFilter v-model="tablePageSizesSearchTerm" as-child>
|
||||
<TagsInputInput
|
||||
:placeholder="t('view.settings.appearance.appearance.table_page_sizes')"
|
||||
@keydown.enter.prevent="addTablePageSizeFromInput"
|
||||
@keydown.down="tablePageSizesOpen = true" />
|
||||
</ListboxFilter>
|
||||
<Dialog v-model:open="tablePageSizesDialogOpen">
|
||||
<DialogContent class="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('view.settings.appearance.appearance.table_page_sizes') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<PopoverTrigger as-child>
|
||||
<Button size="icon-sm" variant="ghost" class="order-last self-start ml-auto">
|
||||
<ChevronDown class="size-3.5" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
</TagsInput>
|
||||
</PopoverAnchor>
|
||||
<Popover v-model:open="tablePageSizesOpen">
|
||||
<ListboxRoot v-model="tablePageSizesModel" highlight-on-hover multiple>
|
||||
<PopoverAnchor class="inline-flex w-full">
|
||||
<TagsInput
|
||||
v-slot="{ modelValue: tags }"
|
||||
v-model="tablePageSizesModel"
|
||||
class="w-full">
|
||||
<TagsInputItem
|
||||
v-for="item in tags"
|
||||
:key="item.toString()"
|
||||
:value="item.toString()">
|
||||
<TagsInputItemText />
|
||||
<TagsInputItemDelete />
|
||||
</TagsInputItem>
|
||||
|
||||
<PopoverContent class="p-1" @open-auto-focus.prevent>
|
||||
<ListboxContent
|
||||
class="max-h-75 scroll-py-1 overflow-x-hidden overflow-y-auto empty:after:content-['No_options'] empty:p-1 empty:after:block"
|
||||
tabindex="0">
|
||||
<ListboxItem
|
||||
v-for="size in filteredTablePageSizeOptions"
|
||||
:key="size"
|
||||
class="data-highlighted:bg-accent data-highlighted:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
||||
:value="size"
|
||||
@select="tablePageSizesSearchTerm = ''">
|
||||
<span>{{ size }}</span>
|
||||
<ListboxFilter v-model="tablePageSizesSearchTerm" as-child>
|
||||
<TagsInputInput
|
||||
:placeholder="t('view.settings.appearance.appearance.table_page_sizes')"
|
||||
@keydown.down="tablePageSizesOpen = true" />
|
||||
</ListboxFilter>
|
||||
|
||||
<ListboxItemIndicator class="ml-auto inline-flex items-center justify-center">
|
||||
<CheckIcon />
|
||||
</ListboxItemIndicator>
|
||||
</ListboxItem>
|
||||
</ListboxContent>
|
||||
</PopoverContent>
|
||||
</ListboxRoot>
|
||||
</Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
class="order-last ml-auto self-start">
|
||||
<ChevronDown class="size-3.5" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
</TagsInput>
|
||||
</PopoverAnchor>
|
||||
|
||||
<PopoverContent
|
||||
class="w-[var(--reka-popover-trigger-width)] p-1"
|
||||
@open-auto-focus.prevent>
|
||||
<ListboxContent
|
||||
class="max-h-75 scroll-py-1 overflow-x-hidden overflow-y-auto empty:after:block empty:after:content-['No_options'] empty:p-1"
|
||||
tabindex="0">
|
||||
<ListboxItem
|
||||
v-for="size in filteredTablePageSizeOptions"
|
||||
:key="size"
|
||||
class="data-highlighted:bg-accent data-highlighted:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
||||
:value="size"
|
||||
@select="tablePageSizesSearchTerm = ''">
|
||||
<span>{{ size }}</span>
|
||||
|
||||
<ListboxItemIndicator
|
||||
class="ml-auto inline-flex items-center justify-center">
|
||||
<CheckIcon />
|
||||
</ListboxItemIndicator>
|
||||
</ListboxItem>
|
||||
</ListboxContent>
|
||||
</PopoverContent>
|
||||
</ListboxRoot>
|
||||
</Popover>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="tablePageSizesDialogOpen = false">{{
|
||||
t('dialog.alertdialog.ok')
|
||||
}}</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="t('view.settings.appearance.appearance.table_entries_settings')"
|
||||
:description="t('view.settings.appearance.appearance.table_entries_settings_description')">
|
||||
<Button size="sm" variant="outline" @click="showTableLimitsDialog">{{
|
||||
t('view.settings.appearance.appearance.table_entries_settings')
|
||||
t('common.actions.configure')
|
||||
}}</Button>
|
||||
</SettingsItem>
|
||||
</SettingsGroup>
|
||||
@@ -254,23 +277,20 @@
|
||||
|
||||
<SettingsGroup :title="t('view.settings.appearance.timedate.header')">
|
||||
<SettingsItem :label="t('view.settings.appearance.timedate.time_format')">
|
||||
<RadioGroup
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
required
|
||||
variant="outline"
|
||||
size="sm"
|
||||
:model-value="dtHour12 ? 'true' : 'false'"
|
||||
class="gap-2 flex"
|
||||
@update:modelValue="handleDtHour12Radio">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroupItem id="dtHour12-true" value="true" />
|
||||
<label for="dtHour12-true">
|
||||
{{ t('view.settings.appearance.timedate.time_format_12') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroupItem id="dtHour12-false" value="false" />
|
||||
<label for="dtHour12-false">
|
||||
{{ t('view.settings.appearance.timedate.time_format_24') }}
|
||||
</label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
@update:model-value="handleDtHour12Radio">
|
||||
<ToggleGroupItem value="true">{{
|
||||
t('view.settings.appearance.timedate.time_format_12')
|
||||
}}</ToggleGroupItem>
|
||||
<ToggleGroupItem value="false">{{
|
||||
t('view.settings.appearance.timedate.time_format_24')
|
||||
}}</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem :label="t('view.settings.appearance.timedate.force_iso_date_format')">
|
||||
@@ -366,11 +386,13 @@
|
||||
} from '@/components/ui/dialog';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||
import { CheckIcon, ChevronDown } from 'lucide-vue-next';
|
||||
import { useAppearanceSettingsStore, useFavoriteStore, useVrStore } from '@/stores';
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||
import { useAppearanceSettingsStore, useVrStore } from '@/stores';
|
||||
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||
import { getLanguageName, languageCodes } from '@/localization';
|
||||
import { APP_CJK_FONT_PACKS, APP_FONT_CONFIG, APP_FONT_DEFAULT_KEY, APP_FONT_FAMILIES } from '@/shared/constants';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -626,6 +648,7 @@
|
||||
|
||||
const TABLE_PAGE_SIZE_SUGGESTIONS = Object.freeze([5, 10, 15, 20, 25, 30, 50, 75, 100, 150, 200, 250, 500, 1000]);
|
||||
|
||||
const tablePageSizesDialogOpen = ref(false);
|
||||
const tablePageSizesOpen = ref(false);
|
||||
const tablePageSizesSearchTerm = ref('');
|
||||
|
||||
@@ -650,22 +673,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function addTablePageSizeFromInput() {
|
||||
const raw = String(tablePageSizesSearchTerm.value ?? '').trim();
|
||||
if (!raw) {
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(tablePageSizesModel.value)) {
|
||||
tablePageSizesModel.value = [raw];
|
||||
} else if (!tablePageSizesModel.value.includes(raw)) {
|
||||
tablePageSizesModel.value = [...tablePageSizesModel.value, raw];
|
||||
}
|
||||
tablePageSizesSearchTerm.value = '';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
<span class="block truncate font-medium text-sm leading-[18px]">{{
|
||||
t('view.settings.general.general.latest_app_version')
|
||||
}}</span>
|
||||
<span v-if="latestAppVersion" class="block truncate text-xs text-muted-foreground" v-text="latestAppVersion"></span>
|
||||
<span
|
||||
v-if="latestAppVersion"
|
||||
class="block truncate text-xs text-muted-foreground"
|
||||
v-text="latestAppVersion"></span>
|
||||
<span v-else class="block truncate text-xs text-muted-foreground">{{
|
||||
t('view.settings.general.general.latest_app_version_refresh')
|
||||
}}</span>
|
||||
@@ -53,23 +56,22 @@
|
||||
|
||||
<template v-if="!noUpdater">
|
||||
<SettingsItem :label="t('view.settings.general.vrcx_updater.update_action')">
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
required
|
||||
variant="outline"
|
||||
size="sm"
|
||||
:model-value="autoUpdateVRCX"
|
||||
@update:model-value="setAutoUpdateVRCX">
|
||||
<ToggleGroupItem value="Off">{{
|
||||
t('view.settings.general.vrcx_updater.auto_update_off')
|
||||
}}</ToggleGroupItem>
|
||||
<ToggleGroupItem value="Notify">{{
|
||||
t('view.settings.general.vrcx_updater.auto_update_notify')
|
||||
}}</ToggleGroupItem>
|
||||
<ToggleGroupItem value="Auto Download">{{
|
||||
t('view.settings.general.vrcx_updater.auto_update_download')
|
||||
}}</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
<Select :model-value="autoUpdateVRCX" @update:model-value="setAutoUpdateVRCX">
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="Off">{{
|
||||
t('view.settings.general.vrcx_updater.auto_update_off')
|
||||
}}</SelectItem>
|
||||
<SelectItem value="Notify">{{
|
||||
t('view.settings.general.vrcx_updater.auto_update_notify')
|
||||
}}</SelectItem>
|
||||
<SelectItem value="Auto Download">{{
|
||||
t('view.settings.general.vrcx_updater.auto_update_download')
|
||||
}}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</SettingsItem>
|
||||
</template>
|
||||
<div v-else class="text-sm text-muted-foreground">
|
||||
@@ -82,9 +84,7 @@
|
||||
<Switch :model-value="isStartAtWindowsStartup" @update:modelValue="setIsStartAtWindowsStartup" />
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
v-if="!isLinux"
|
||||
:label="t('view.settings.general.application.minimized')">
|
||||
<SettingsItem v-if="!isLinux" :label="t('view.settings.general.application.minimized')">
|
||||
<Switch :model-value="isStartAsMinimizedState" @update:modelValue="setIsStartAsMinimizedState" />
|
||||
</SettingsItem>
|
||||
<SettingsItem
|
||||
@@ -132,7 +132,7 @@
|
||||
</SettingsGroup>
|
||||
|
||||
<SettingsGroup :title="t('view.settings.general.legal_notice.header')">
|
||||
<div class="flex flex-col gap-2 text-sm text-muted-foreground">
|
||||
<div class="flex flex-col gap-2 text-sm text-muted-foreground mb-2">
|
||||
<p class="m-0">
|
||||
© 2019-2026
|
||||
<a class="cursor-pointer" @click="openExternalLink('https://github.com/pypy-vrc')">pypy</a> &
|
||||
@@ -163,7 +163,7 @@
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { useGeneralSettingsStore, useVRCXUpdaterStore } from '@/stores';
|
||||
import { links } from '@/shared/constants';
|
||||
import { openExternalLink } from '@/shared/utils';
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
<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')">
|
||||
<SettingsItem :label="t('view.settings.notifications.notifications.steamvr_notifications.steamvr_overlay')">
|
||||
<Switch
|
||||
:model-value="openVR"
|
||||
@update:modelValue="
|
||||
@@ -12,22 +11,19 @@
|
||||
" />
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.start_overlay_with')">
|
||||
<RadioGroup
|
||||
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.start_overlay_with')">
|
||||
<Select
|
||||
: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>
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="false">{{ 'VRChat' }}</SelectItem>
|
||||
<SelectItem value="true">{{ 'SteamVR' }}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</SettingsItem>
|
||||
|
||||
<template v-if="!isLinux">
|
||||
@@ -45,9 +41,7 @@
|
||||
</template>
|
||||
<template v-else>
|
||||
<SettingsItem
|
||||
:label="
|
||||
t('view.settings.notifications.notifications.steamvr_notifications.wayvr_notifications')
|
||||
">
|
||||
:label="t('view.settings.notifications.notifications.steamvr_notifications.wayvr_notifications')">
|
||||
<Switch
|
||||
:model-value="xsNotifications"
|
||||
@update:modelValue="
|
||||
@@ -90,8 +84,7 @@
|
||||
|
||||
<!-- VR Notifications -->
|
||||
<SettingsGroup :title="t('view.settings.vr.vr_notifications.header')">
|
||||
<SettingsItem
|
||||
:label="t('view.settings.notifications.notifications.desktop_notifications.when_to_display')">
|
||||
<SettingsItem :label="t('view.settings.notifications.notifications.desktop_notifications.when_to_display')">
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
required
|
||||
@@ -124,9 +117,7 @@
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="
|
||||
t('view.settings.notifications.notifications.steamvr_notifications.overlay_notifications')
|
||||
">
|
||||
:label="t('view.settings.notifications.notifications.steamvr_notifications.overlay_notifications')">
|
||||
<Switch
|
||||
:model-value="overlayNotifications"
|
||||
:disabled="!openVR"
|
||||
@@ -137,9 +128,7 @@
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="
|
||||
t('view.settings.notifications.notifications.steamvr_notifications.notification_position')
|
||||
">
|
||||
:label="t('view.settings.notifications.notifications.steamvr_notifications.notification_position')">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
@@ -152,31 +141,31 @@
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="
|
||||
t('view.settings.notifications.notifications.steamvr_notifications.notification_opacity')
|
||||
">
|
||||
: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"
|
||||
:label="t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout')">
|
||||
<NumberField
|
||||
:model-value="notificationTimeoutSeconds"
|
||||
:min="0"
|
||||
:step="1"
|
||||
:format-options="{ maximumFractionDigits: 0 }"
|
||||
:disabled="(!overlayNotifications || !openVR) && !xsNotifications"
|
||||
@click="promptNotificationTimeout"
|
||||
>{{
|
||||
t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout')
|
||||
}}</Button
|
||||
>
|
||||
class="w-32"
|
||||
@update:modelValue="setNotificationTimeout">
|
||||
<NumberFieldContent>
|
||||
<NumberFieldDecrement />
|
||||
<NumberFieldInput />
|
||||
<NumberFieldIncrement />
|
||||
</NumberFieldContent>
|
||||
</NumberField>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="t('view.settings.notifications.notifications.steamvr_notifications.user_images')">
|
||||
<SettingsItem :label="t('view.settings.notifications.notifications.steamvr_notifications.user_images')">
|
||||
<Switch
|
||||
:model-value="imageNotifications"
|
||||
@update:modelValue="
|
||||
@@ -191,7 +180,8 @@
|
||||
|
||||
<!-- VR Extras -->
|
||||
<SettingsGroup :title="t('view.settings.vr.vr_extras.header')">
|
||||
<SettingsItem :label="t('view.settings.advanced.advanced.video_progress_pie.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"
|
||||
@@ -214,10 +204,17 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import {
|
||||
NumberField,
|
||||
NumberFieldContent,
|
||||
NumberFieldDecrement,
|
||||
NumberFieldIncrement,
|
||||
NumberFieldInput
|
||||
} from '@/components/ui/number-field';
|
||||
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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
@@ -250,7 +247,8 @@
|
||||
xsNotifications,
|
||||
ovrtHudNotifications,
|
||||
ovrtWristNotifications,
|
||||
imageNotifications
|
||||
imageNotifications,
|
||||
notificationTimeout
|
||||
} = storeToRefs(notificationsSettingsStore);
|
||||
|
||||
const { notificationOpacity } = storeToRefs(advancedSettingsStore);
|
||||
@@ -258,10 +256,7 @@
|
||||
const { openVRAlways } = storeToRefs(wristOverlaySettingsStore);
|
||||
const { setOpenVRAlways } = wristOverlaySettingsStore;
|
||||
|
||||
const {
|
||||
progressPie,
|
||||
progressPieFilter
|
||||
} = storeToRefs(advancedSettingsStore);
|
||||
const { progressPie, progressPieFilter } = storeToRefs(advancedSettingsStore);
|
||||
|
||||
const {
|
||||
setOverlayToast,
|
||||
@@ -271,9 +266,11 @@
|
||||
setOvrtHudNotifications,
|
||||
setOvrtWristNotifications,
|
||||
setImageNotifications,
|
||||
promptNotificationTimeout
|
||||
setNotificationTimeout
|
||||
} = notificationsSettingsStore;
|
||||
|
||||
const notificationTimeoutSeconds = computed(() => notificationTimeout.value / 1000);
|
||||
|
||||
const { setNotificationOpacity } = advancedSettingsStore;
|
||||
|
||||
const isNotificationPositionDialogVisible = ref(false);
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
" />
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_private_worlds')">
|
||||
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_private_worlds')">
|
||||
<Switch
|
||||
:model-value="hidePrivateFromFeed"
|
||||
@update:modelValue="
|
||||
@@ -38,52 +37,49 @@
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button')">
|
||||
<RadioGroup
|
||||
<Select
|
||||
:model-value="overlaybutton ? 'true' : 'false'"
|
||||
:disabled="!openVR || !overlayWrist"
|
||||
class="gap-2 flex"
|
||||
@update:modelValue="handleOverlayButtonRadio">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroupItem id="overlaybutton-false" value="false" />
|
||||
<label for="overlaybutton-false">{{
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="false">{{
|
||||
t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button_grip')
|
||||
}}</label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroupItem id="overlaybutton-true" value="true" />
|
||||
<label for="overlaybutton-true">{{
|
||||
}}</SelectItem>
|
||||
<SelectItem value="true">{{
|
||||
t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button_menu')
|
||||
}}</label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
}}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on')">
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
required
|
||||
variant="outline"
|
||||
size="sm"
|
||||
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on')">
|
||||
<Select
|
||||
:model-value="overlayHand"
|
||||
@update:model-value="
|
||||
setOverlayHand($event);
|
||||
saveOpenVROption();
|
||||
">
|
||||
<ToggleGroupItem value="1">{{
|
||||
t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_left')
|
||||
}}</ToggleGroupItem>
|
||||
<ToggleGroupItem value="2">{{
|
||||
t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_right')
|
||||
}}</ToggleGroupItem>
|
||||
<ToggleGroupItem value="0">{{
|
||||
t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_both')
|
||||
}}</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="1">{{
|
||||
t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_left')
|
||||
}}</SelectItem>
|
||||
<SelectItem value="2">{{
|
||||
t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_right')
|
||||
}}</SelectItem>
|
||||
<SelectItem value="0">{{
|
||||
t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_both')
|
||||
}}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.grey_background')">
|
||||
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.grey_background')">
|
||||
<Switch
|
||||
:model-value="vrBackgroundEnabled"
|
||||
:disabled="!openVR || !overlayWrist"
|
||||
@@ -93,8 +89,7 @@
|
||||
" />
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.minimal_feed_icons')">
|
||||
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.minimal_feed_icons')">
|
||||
<Switch
|
||||
:model-value="minimalFeed"
|
||||
:disabled="!openVR || !overlayWrist"
|
||||
@@ -124,8 +119,7 @@
|
||||
" />
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem
|
||||
:label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_game_uptime')">
|
||||
<SettingsItem :label="t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_game_uptime')">
|
||||
<Switch
|
||||
:model-value="!hideUptimeFromFeed"
|
||||
:disabled="!openVR || !overlayWrist"
|
||||
@@ -151,8 +145,7 @@
|
||||
<script setup>
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@@ -169,7 +162,6 @@
|
||||
|
||||
const { openVR } = storeToRefs(notificationsSettingsStore);
|
||||
|
||||
|
||||
const {
|
||||
overlayWrist,
|
||||
hidePrivateFromFeed,
|
||||
|
||||
Reference in New Issue
Block a user