mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-19 14:53:50 +02:00
refactor: dialogs (#1216)
This commit is contained in:
1120
src/app.js
1120
src/app.js
File diff suppressed because it is too large
Load Diff
56
src/app.pug
56
src/app.pug
@@ -64,7 +64,7 @@ doctype html
|
||||
FriendListTab(v-bind='friendsListTabBind' v-on='friendsListTabEvent')
|
||||
|
||||
//- charts
|
||||
keep-alive
|
||||
KeepAlive
|
||||
ChartsTab(v-if='menuActiveIndex === "charts"' v-bind='chartsTabBind' v-on='chartsTabEvent')
|
||||
|
||||
//- settings
|
||||
@@ -80,30 +80,12 @@ doctype html
|
||||
include ./mixins/dialogs/images.pug
|
||||
+images
|
||||
|
||||
include ./mixins/dialogs/feedFilters.pug
|
||||
+feedFilters
|
||||
|
||||
include ./mixins/dialogs/openSourceSoftwareNotice.pug
|
||||
+openSourceSoftwareNotice
|
||||
|
||||
include ./mixins/dialogs/currentUser.pug
|
||||
+currentUser
|
||||
|
||||
include ./mixins/dialogs/invites.pug
|
||||
+invites
|
||||
|
||||
include ./mixins/dialogs/launch.pug
|
||||
+launch
|
||||
|
||||
include ./mixins/dialogs/screenshotMetadata.pug
|
||||
+screenshotMetadata
|
||||
|
||||
include ./mixins/dialogs/vrcx.pug
|
||||
+vrcx
|
||||
|
||||
include ./mixins/dialogs/settings.pug
|
||||
+settings
|
||||
|
||||
include ./mixins/dialogs/boops.pug
|
||||
+boops
|
||||
|
||||
@@ -140,4 +122,40 @@ doctype html
|
||||
//- avatar
|
||||
AvatarDialog(v-bind='avatarDialogBind' v-on='avatarDialogEvent')
|
||||
|
||||
//- settings
|
||||
FeedFiltersDialog(v-bind='feedFiltersDialogBind' v-on='feedFiltersDialogEvent')
|
||||
|
||||
LaunchOptionsDialog(:is-launch-options-dialog-visible.sync='isLaunchOptionsDialogVisible')
|
||||
|
||||
OpenSourceSoftwareNoticeDialog(:oss-dialog.sync='ossDialog')
|
||||
|
||||
ChangelogDialog(:change-log-dialog.sync='changeLogDialog')
|
||||
|
||||
VRCXUpdateDialog(v-bind='vrcxUpdateDialogBind' v-on='vrcxUpdateDialogEvent')
|
||||
|
||||
ScreenshotMetadataDialog(v-bind='screenshotMetadataDialogBind' v-on='screenshotMetadataDialogEvent')
|
||||
|
||||
DiscordNamesDialog(:discord-names-dialog-visible.sync='discordNamesDialogVisible' :friends='friends')
|
||||
|
||||
EditInviteMessageDialog(:edit-invite-message-dialog.sync='editInviteMessageDialog')
|
||||
|
||||
NoteExportDialog(:is-note-export-dialog-visible.sync='isNoteExportDialogVisible' :friends='friends')
|
||||
|
||||
VRChatConfigDialog(v-bind='vrchatConfigDialogBind' v-on='vrchatConfigDialogEvent')
|
||||
|
||||
YouTubeApiDialog(v-bind='youTubeApiDialogBind' v-on='youTubeApiDialogEvent')
|
||||
|
||||
NotificationPositionDialog(v-bind='notificationPositionDialogBind' v-on='notificationPositionDialogEvent')
|
||||
|
||||
AvatarProviderDialog(v-bind='avatarProviderDialogBind' v-on='avatarProviderDialogEvent')
|
||||
|
||||
RegistryBackupDialog(
|
||||
:isRegistryBackupDialogVisible.sync='isRegistryBackupDialogVisible'
|
||||
:backupVrcRegistry='backupVrcRegistry')
|
||||
|
||||
PrimaryPasswordDialog(:enablePrimaryPasswordDialog.sync='enablePrimaryPasswordDialog' @setPrimaryPassword="setPrimaryPassword")
|
||||
|
||||
//- player list
|
||||
ChatboxBlacklistDialog(:chatboxBlacklistDialog="chatboxBlacklistDialog" :chatboxUserBlacklist="chatboxUserBlacklist" @deleteChatboxUserBlacklist="deleteChatboxUserBlacklist")
|
||||
|
||||
//- el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="templateDialog" :visible.sync="templateDialog.visible" :title="$t('dialog.template_dialog.header')" width="450px")
|
||||
|
||||
@@ -843,10 +843,6 @@ i.x-status-icon.red {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.changelog-dialog img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vrc-instance-queue-message {
|
||||
padding: 3px;
|
||||
top: 0 !important;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import * as workerTimers from 'worker-timers';
|
||||
import configRepository from '../service/config.js';
|
||||
import { baseClass, $app, API } from './baseClass.js';
|
||||
import { worldRequest, groupRequest } from '../api';
|
||||
|
||||
@@ -573,28 +572,6 @@ export default class extends baseClass {
|
||||
}
|
||||
this.sharedFeed.moderationAgainstTable.wrist = wristArr;
|
||||
this.sharedFeed.pendingUpdate = true;
|
||||
},
|
||||
|
||||
saveSharedFeedFilters() {
|
||||
configRepository.setString(
|
||||
'sharedFeedFilters',
|
||||
JSON.stringify(this.sharedFeedFilters)
|
||||
);
|
||||
this.updateSharedFeed(true);
|
||||
},
|
||||
|
||||
async resetNotyFeedFilters() {
|
||||
this.sharedFeedFilters.noty = {
|
||||
...this.sharedFeedFiltersDefaults.noty
|
||||
};
|
||||
this.saveSharedFeedFilters();
|
||||
},
|
||||
|
||||
async resetWristFeedFilters() {
|
||||
this.sharedFeedFilters.wrist = {
|
||||
...this.sharedFeedFiltersDefaults.wrist
|
||||
};
|
||||
this.saveSharedFeedFilters();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import configRepository from '../service/config.js';
|
||||
import { baseClass, $app, API, $t, $utils } from './baseClass.js';
|
||||
import { baseClass, $t, $utils } from './baseClass.js';
|
||||
|
||||
export default class extends baseClass {
|
||||
constructor(_app, _API, _t) {
|
||||
@@ -8,67 +8,9 @@ export default class extends baseClass {
|
||||
|
||||
init() {}
|
||||
|
||||
_data = {
|
||||
registryBackupDialog: {
|
||||
visible: false
|
||||
},
|
||||
|
||||
registryBackupTable: {
|
||||
data: [],
|
||||
tableProps: {
|
||||
stripe: true,
|
||||
size: 'mini',
|
||||
defaultSort: {
|
||||
prop: 'date',
|
||||
order: 'descending'
|
||||
}
|
||||
},
|
||||
layout: 'table'
|
||||
}
|
||||
};
|
||||
_data = {};
|
||||
|
||||
_methods = {
|
||||
showRegistryBackupDialog() {
|
||||
this.$nextTick(() =>
|
||||
$app.adjustDialogZ(this.$refs.registryBackupDialog.$el)
|
||||
);
|
||||
var D = this.registryBackupDialog;
|
||||
D.visible = true;
|
||||
this.updateRegistryBackupDialog();
|
||||
},
|
||||
|
||||
async updateRegistryBackupDialog() {
|
||||
var D = this.registryBackupDialog;
|
||||
this.registryBackupTable.data = [];
|
||||
if (!D.visible) {
|
||||
return;
|
||||
}
|
||||
var backupsJson = await configRepository.getString(
|
||||
'VRCX_VRChatRegistryBackups'
|
||||
);
|
||||
if (!backupsJson) {
|
||||
backupsJson = JSON.stringify([]);
|
||||
}
|
||||
this.registryBackupTable.data = JSON.parse(backupsJson);
|
||||
},
|
||||
|
||||
async promptVrcRegistryBackupName() {
|
||||
var name = await this.$prompt(
|
||||
'Enter a name for the backup',
|
||||
'Backup Name',
|
||||
{
|
||||
confirmButtonText: 'Confirm',
|
||||
cancelButtonText: 'Cancel',
|
||||
inputPattern: /\S+/,
|
||||
inputErrorMessage: 'Name is required',
|
||||
inputValue: 'Backup'
|
||||
}
|
||||
);
|
||||
if (name.action === 'confirm') {
|
||||
this.backupVrcRegistry(name.value);
|
||||
}
|
||||
},
|
||||
|
||||
async backupVrcRegistry(name) {
|
||||
var regJson;
|
||||
if (LINUX) {
|
||||
@@ -94,158 +36,11 @@ export default class extends baseClass {
|
||||
'VRCX_VRChatRegistryBackups',
|
||||
JSON.stringify(backups)
|
||||
);
|
||||
await this.updateRegistryBackupDialog();
|
||||
},
|
||||
|
||||
async deleteVrcRegistryBackup(row) {
|
||||
var backups = this.registryBackupTable.data;
|
||||
$app.removeFromArray(backups, row);
|
||||
await configRepository.setString(
|
||||
'VRCX_VRChatRegistryBackups',
|
||||
JSON.stringify(backups)
|
||||
);
|
||||
await this.updateRegistryBackupDialog();
|
||||
},
|
||||
|
||||
restoreVrcRegistryBackup(row) {
|
||||
this.$confirm('Continue? Restore Backup', 'Confirm', {
|
||||
confirmButtonText: 'Confirm',
|
||||
cancelButtonText: 'Cancel',
|
||||
type: 'warning',
|
||||
callback: (action) => {
|
||||
if (action !== 'confirm') {
|
||||
return;
|
||||
}
|
||||
var data = JSON.stringify(row.data);
|
||||
AppApi.SetVRChatRegistry(data)
|
||||
.then(() => {
|
||||
this.$message({
|
||||
message: 'VRC registry settings restored',
|
||||
type: 'success'
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
this.$message({
|
||||
message: `Failed to restore VRC registry settings, check console for full error: ${e}`,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
saveVrcRegistryBackupToFile(row) {
|
||||
$utils.downloadAndSaveJson(row.name, row.data);
|
||||
},
|
||||
|
||||
async openJsonFileSelectorDialogElectron() {
|
||||
return new Promise((resolve) => {
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.accept = '.json';
|
||||
fileInput.style.display = 'none';
|
||||
document.body.appendChild(fileInput);
|
||||
|
||||
fileInput.onchange = function (event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
fileInput.remove();
|
||||
resolve(reader.result);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
} else {
|
||||
fileInput.remove();
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
|
||||
fileInput.click();
|
||||
});
|
||||
},
|
||||
|
||||
async restoreVrcRegistryFromFile() {
|
||||
if (WINDOWS) {
|
||||
var filePath = await AppApi.OpenFileSelectorDialog(
|
||||
null,
|
||||
'.json',
|
||||
'JSON Files (*.json)|*.json'
|
||||
);
|
||||
if (filePath === '') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var json;
|
||||
if (LINUX) {
|
||||
json = await this.openJsonFileSelectorDialogElectron();
|
||||
} else {
|
||||
json = await AppApi.ReadVrcRegJsonFile(filePath);
|
||||
}
|
||||
|
||||
try {
|
||||
var data = JSON.parse(json);
|
||||
if (!data || typeof data !== 'object') {
|
||||
throw new Error('Invalid JSON');
|
||||
}
|
||||
// quick check to make sure it's a valid registry backup
|
||||
for (var key in data) {
|
||||
var value = data[key];
|
||||
if (
|
||||
typeof value !== 'object' ||
|
||||
typeof value.type !== 'number' ||
|
||||
typeof value.data === 'undefined'
|
||||
) {
|
||||
throw new Error('Invalid JSON');
|
||||
}
|
||||
}
|
||||
AppApi.SetVRChatRegistry(json)
|
||||
.then(() => {
|
||||
this.$message({
|
||||
message: 'VRC registry settings restored',
|
||||
type: 'success'
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
this.$message({
|
||||
message: `Failed to restore VRC registry settings, check console for full error: ${e}`,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
this.$message({
|
||||
message: 'Invalid JSON',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
deleteVrcRegistry() {
|
||||
this.$confirm('Continue? Delete VRC Registry Settings', 'Confirm', {
|
||||
confirmButtonText: 'Confirm',
|
||||
cancelButtonText: 'Cancel',
|
||||
type: 'warning',
|
||||
callback: (action) => {
|
||||
if (action !== 'confirm') {
|
||||
return;
|
||||
}
|
||||
AppApi.DeleteVRChatRegistryFolder().then(() => {
|
||||
this.$message({
|
||||
message: 'VRC registry settings deleted',
|
||||
type: 'success'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
clearVrcRegistryDialog() {
|
||||
this.registryBackupTable.data = [];
|
||||
// await this.updateRegistryBackupDialog();
|
||||
},
|
||||
|
||||
// Because it is a startup func, it is not integrated into RegistryBackupDialog.vue now
|
||||
// func backupVrcRegistry is also split up
|
||||
async checkAutoBackupRestoreVrcRegistry() {
|
||||
if (!this.vrcRegistryAutoBackup) {
|
||||
return;
|
||||
@@ -309,7 +104,7 @@ export default class extends baseClass {
|
||||
backups.forEach((backup) => {
|
||||
if (backup.name === 'Auto Backup') {
|
||||
// remove old auto backup
|
||||
$app.removeFromArray(backups, backup);
|
||||
$utils.removeFromArray(backups, backup);
|
||||
}
|
||||
});
|
||||
await configRepository.setString(
|
||||
|
||||
@@ -44,9 +44,6 @@ export default class extends baseClass {
|
||||
|
||||
_methods = {
|
||||
async showVRCXUpdateDialog() {
|
||||
this.$nextTick(() =>
|
||||
$app.adjustDialogZ(this.$refs.VRCXUpdateDialog.$el)
|
||||
);
|
||||
var D = this.VRCXUpdateDialog;
|
||||
D.visible = true;
|
||||
D.updatePendingIsLatest = false;
|
||||
|
||||
@@ -515,7 +515,6 @@
|
||||
import database from '../../../service/database';
|
||||
import { avatarModerationRequest, avatarRequest, favoriteRequest, miscRequest } from '../../../api';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import $utils from '../../../classes/utils';
|
||||
|
||||
import SetAvatarTagsDialog from './SetAvatarTagsDialog.vue';
|
||||
import SetAvatarStylesDialog from './SetAvatarStylesDialog.vue';
|
||||
@@ -672,7 +671,7 @@
|
||||
showAvatarDialog(D.id);
|
||||
break;
|
||||
case 'Share':
|
||||
$utils.copyToClipboard(D.id);
|
||||
utils.copyToClipboard(D.id);
|
||||
break;
|
||||
case 'Rename':
|
||||
promptRenameAvatar(D);
|
||||
|
||||
162
src/components/dialogs/VRCXUpdateDialog.vue
Normal file
162
src/components/dialogs/VRCXUpdateDialog.vue
Normal file
@@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
ref="VRCXUpdateDialogRef"
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible.sync="VRCXUpdateDialog.visible"
|
||||
:title="t('dialog.vrcx_updater.header')"
|
||||
width="400px"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div v-loading="checkingForVRCXUpdate" style="margin-top: 15px">
|
||||
<template v-if="updateInProgress">
|
||||
<el-progress :percentage="updateProgress" :format="updateProgressText"></el-progress>
|
||||
<br />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div v-if="VRCXUpdateDialog.updatePending" style="margin-bottom: 15px">
|
||||
<span>{{ pendingVRCXInstall }}</span>
|
||||
<br />
|
||||
<span>{{ t('dialog.vrcx_updater.ready_for_update') }}</span>
|
||||
</div>
|
||||
<el-select
|
||||
v-model="currentBranch"
|
||||
style="display: inline-block; width: 150px; margin-right: 15px"
|
||||
@change="loadBranchVersions">
|
||||
<el-option v-for="branch in branches" :key="branch.name" :label="branch.name" :value="branch.name">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-select v-model="VRCXUpdateDialog.release" style="display: inline-block; width: 150px">
|
||||
<el-option
|
||||
v-for="item in VRCXUpdateDialog.releases"
|
||||
:key="item.name"
|
||||
:label="item.tag_name"
|
||||
:value="item.name">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<div
|
||||
v-if="!VRCXUpdateDialog.updatePending && VRCXUpdateDialog.release === appVersion"
|
||||
style="margin-top: 15px">
|
||||
<span>{{ t('dialog.vrcx_updater.latest_version') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button v-if="updateInProgress" type="primary" size="small" @click="cancelUpdate">
|
||||
{{ t('dialog.vrcx_updater.cancel') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="VRCXUpdateDialog.release !== pendingVRCXInstall"
|
||||
:disabled="updateInProgress"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="installVRCXUpdate">
|
||||
{{ t('dialog.vrcx_updater.download') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="!updateInProgress && pendingVRCXInstall"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="restartVRCX(true)">
|
||||
{{ t('dialog.vrcx_updater.install') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, inject, watch, nextTick } from 'vue';
|
||||
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
|
||||
const { t } = useI18n();
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
const adjustDialogZ = inject('adjustDialogZ');
|
||||
|
||||
const props = defineProps({
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
VRCXUpdateDialog: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
appVersion: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
checkingForVRCXUpdate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
updateInProgress: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
updateProgress: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
updateProgressText: {
|
||||
type: Function,
|
||||
default: () => ''
|
||||
},
|
||||
pendingVRCXInstall: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
branch: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
branches: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
});
|
||||
|
||||
const VRCXUpdateDialogRef = ref(null);
|
||||
|
||||
const emit = defineEmits([
|
||||
'loadBranchVersions',
|
||||
'cancelUpdate',
|
||||
'installVRCXUpdate',
|
||||
'restartVRCX',
|
||||
'update:branch'
|
||||
]);
|
||||
|
||||
const currentBranch = computed({
|
||||
get: () => props.branch,
|
||||
set: (value) => {
|
||||
emit('update:branch', value);
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.VRCXUpdateDialog,
|
||||
(newVal) => {
|
||||
if (newVal.visible) {
|
||||
nextTick(() => {
|
||||
adjustDialogZ(VRCXUpdateDialogRef.value.$el);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function loadBranchVersions(event) {
|
||||
emit('loadBranchVersions', event);
|
||||
}
|
||||
|
||||
function cancelUpdate() {
|
||||
emit('cancelUpdate');
|
||||
}
|
||||
|
||||
function installVRCXUpdate() {
|
||||
emit('installVRCXUpdate');
|
||||
}
|
||||
|
||||
function restartVRCX(isUpgrade) {
|
||||
emit('restartVRCX', isUpgrade);
|
||||
}
|
||||
</script>
|
||||
236
src/composables/settings/constants/feedFiltersOptions.js
Normal file
236
src/composables/settings/constants/feedFiltersOptions.js
Normal file
@@ -0,0 +1,236 @@
|
||||
const getOptions = (optionTypes) => {
|
||||
const optionMap = {
|
||||
Off: { label: 'Off', textKey: 'dialog.shared_feed_filters.off' },
|
||||
On: { label: 'On', textKey: 'dialog.shared_feed_filters.on' },
|
||||
VIP: {
|
||||
label: 'VIP',
|
||||
textKey: 'dialog.shared_feed_filters.favorite'
|
||||
},
|
||||
Friends: {
|
||||
label: 'Friends',
|
||||
textKey: 'dialog.shared_feed_filters.friends'
|
||||
},
|
||||
Everyone: {
|
||||
label: 'Everyone',
|
||||
textKey: 'dialog.shared_feed_filters.everyone'
|
||||
}
|
||||
};
|
||||
return optionTypes.map((type) => optionMap[type]);
|
||||
};
|
||||
|
||||
function feedFiltersOptions() {
|
||||
const baseOptions = [
|
||||
{
|
||||
key: 'OnPlayerJoining',
|
||||
name: 'OnPlayerJoining',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'OnPlayerJoined',
|
||||
name: 'OnPlayerJoined',
|
||||
options: getOptions(['Off', 'VIP', 'Friends', 'Everyone'])
|
||||
},
|
||||
{
|
||||
key: 'OnPlayerLeft',
|
||||
name: 'OnPlayerLeft',
|
||||
options: getOptions(['Off', 'VIP', 'Friends', 'Everyone'])
|
||||
},
|
||||
{
|
||||
key: 'Online',
|
||||
name: 'Online',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'Offline',
|
||||
name: 'Offline',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'GPS',
|
||||
name: 'GPS',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'Status',
|
||||
name: 'Status',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'invite',
|
||||
name: 'Invite',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'requestInvite',
|
||||
name: 'Request Invite',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'inviteResponse',
|
||||
name: 'Invite Response',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'requestInviteResponse',
|
||||
name: 'Request Invite Response',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'friendRequest',
|
||||
name: 'Friend Request',
|
||||
options: getOptions(['Off', 'On'])
|
||||
},
|
||||
{
|
||||
key: 'Friend',
|
||||
name: 'New Friend',
|
||||
options: getOptions(['Off', 'On'])
|
||||
},
|
||||
{
|
||||
key: 'Unfriend',
|
||||
name: 'Unfriend',
|
||||
options: getOptions(['Off', 'On'])
|
||||
},
|
||||
{
|
||||
key: 'DisplayName',
|
||||
name: 'Display Name Change',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'TrustLevel',
|
||||
name: 'Trust Level Change',
|
||||
options: getOptions(['Off', 'VIP', 'Friends'])
|
||||
},
|
||||
{
|
||||
key: 'groupChange',
|
||||
name: 'Group Change',
|
||||
options: getOptions(['Off', 'On']),
|
||||
tooltip:
|
||||
"When you've left or been kicked from a group, group name changed, group owner changed, role added/removed"
|
||||
},
|
||||
{
|
||||
key: 'group.announcement',
|
||||
name: 'Group Announcement',
|
||||
options: getOptions(['Off', 'On'])
|
||||
},
|
||||
{
|
||||
key: 'group.informative',
|
||||
name: 'Group Join',
|
||||
options: getOptions(['Off', 'On']),
|
||||
tooltip: 'When your request to join a group has been approved'
|
||||
},
|
||||
{
|
||||
key: 'group.invite',
|
||||
name: 'Group Invite',
|
||||
options: getOptions(['Off', 'On']),
|
||||
tooltip: 'When someone invites you to join a group'
|
||||
},
|
||||
{
|
||||
key: 'group.joinRequest',
|
||||
name: 'Group Join Request',
|
||||
options: getOptions(['Off', 'On']),
|
||||
tooltip:
|
||||
"When someone requests to join a group you're a moderator for"
|
||||
},
|
||||
{
|
||||
key: 'group.transfer',
|
||||
name: 'Group Transfer Request',
|
||||
options: getOptions(['Off', 'On'])
|
||||
},
|
||||
{
|
||||
key: 'group.queueReady',
|
||||
name: 'Instance Queue Ready',
|
||||
options: getOptions(['Off', 'On'])
|
||||
},
|
||||
{
|
||||
key: 'instance.closed',
|
||||
name: 'Instance Closed',
|
||||
options: getOptions(['Off', 'On']),
|
||||
tooltip:
|
||||
"When the instance you're in has been closed preventing anyone from joining"
|
||||
},
|
||||
{
|
||||
key: 'VideoPlay',
|
||||
name: 'Video Play',
|
||||
options: getOptions(['Off', 'On']),
|
||||
tooltip: 'Requires VRCX YouTube API option enabled',
|
||||
tooltipIcon: 'el-icon-warning'
|
||||
},
|
||||
{
|
||||
key: 'Event',
|
||||
name: 'Miscellaneous Events',
|
||||
options: getOptions(['Off', 'On']),
|
||||
tooltip:
|
||||
'Misc event from VRC game log: VRC crash auto rejoin, shader keyword limit, joining instance blocked by master, error loading video, audio device changed, error joining instance, kicked from instance, VRChat failing to start OSC server, etc...'
|
||||
},
|
||||
{
|
||||
key: 'External',
|
||||
name: 'External App',
|
||||
options: getOptions(['Off', 'On'])
|
||||
},
|
||||
{
|
||||
key: 'BlockedOnPlayerJoined',
|
||||
name: 'Blocked Player Joins',
|
||||
options: getOptions(['Off', 'VIP', 'Friends', 'Everyone'])
|
||||
},
|
||||
{
|
||||
key: 'BlockedOnPlayerLeft',
|
||||
name: 'Blocked Player Leaves',
|
||||
options: getOptions(['Off', 'VIP', 'Friends', 'Everyone'])
|
||||
},
|
||||
{
|
||||
key: 'MutedOnPlayerJoined',
|
||||
name: 'Muted Player Joins',
|
||||
options: getOptions(['Off', 'VIP', 'Friends', 'Everyone'])
|
||||
},
|
||||
{
|
||||
key: 'MutedOnPlayerLeft',
|
||||
name: 'Muted Player Leaves',
|
||||
options: getOptions(['Off', 'VIP', 'Friends', 'Everyone'])
|
||||
},
|
||||
{
|
||||
key: 'AvatarChange',
|
||||
name: 'Lobby Avatar Change',
|
||||
options: getOptions(['Off', 'VIP', 'Friends', 'Everyone'])
|
||||
}
|
||||
];
|
||||
|
||||
const photonFeedFiltersOptions = [
|
||||
{
|
||||
key: 'PortalSpawn',
|
||||
name: 'Portal Spawn',
|
||||
options: getOptions(['Off', 'VIP', 'Friends', 'Everyone'])
|
||||
},
|
||||
{
|
||||
key: 'ChatBoxMessage',
|
||||
name: 'Lobby ChatBox Message',
|
||||
options: getOptions(['Off', 'VIP', 'Friends', 'Everyone'])
|
||||
},
|
||||
{ key: 'Blocked', name: 'Blocked', options: getOptions(['Off', 'On']) },
|
||||
{
|
||||
key: 'Unblocked',
|
||||
name: 'Unblocked',
|
||||
options: getOptions(['Off', 'On'])
|
||||
},
|
||||
{ key: 'Muted', name: 'Muted', options: getOptions(['Off', 'On']) },
|
||||
{ key: 'Unmuted', name: 'Unmuted', options: getOptions(['Off', 'On']) }
|
||||
];
|
||||
|
||||
const notyFeedFiltersOptions = baseOptions;
|
||||
|
||||
const wristFeedFiltersOptions = [
|
||||
{
|
||||
key: 'Location',
|
||||
name: 'Self Location',
|
||||
options: getOptions(['Off', 'On'])
|
||||
},
|
||||
...baseOptions
|
||||
];
|
||||
|
||||
return {
|
||||
notyFeedFiltersOptions,
|
||||
wristFeedFiltersOptions,
|
||||
photonFeedFiltersOptions
|
||||
};
|
||||
}
|
||||
|
||||
export { feedFiltersOptions };
|
||||
@@ -1,19 +1,7 @@
|
||||
mixin openSourceSoftwareNotice
|
||||
//- dialog: open source software notice
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
:visible.sync='ossDialog'
|
||||
:title='$t("dialog.open_source.header")'
|
||||
width='650px')
|
||||
div(v-if='ossDialog' style='height: 350px; overflow: hidden scroll; word-break: break-all')
|
||||
div
|
||||
span {{ $t('dialog.open_source.description') }}
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') animate.css
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
The MIT License (MIT)
|
||||
const openSourceSoftwareLicenses = [
|
||||
{
|
||||
name: 'animate.css',
|
||||
licenseText: `The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Daniel Eden
|
||||
|
||||
@@ -33,11 +21,11 @@ mixin openSourceSoftwareNotice
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') CefSharp
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
// Copyright © The CefSharp Authors. All rights reserved.
|
||||
SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'CefSharp',
|
||||
licenseText: `// Copyright © The CefSharp Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
@@ -66,11 +54,11 @@ mixin openSourceSoftwareNotice
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') DiscordRichPresence
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
MIT License
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.`
|
||||
},
|
||||
{
|
||||
name: 'DiscordRichPresence',
|
||||
licenseText: `MIT License
|
||||
|
||||
Copyright (c) 2018 Lachee
|
||||
|
||||
@@ -90,11 +78,11 @@ mixin openSourceSoftwareNotice
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') element
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
The MIT License (MIT)
|
||||
SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'element',
|
||||
licenseText: `The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-present ElemeFE
|
||||
|
||||
@@ -114,11 +102,11 @@ mixin openSourceSoftwareNotice
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') librsync.net
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
The MIT License (MIT)
|
||||
SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'librsync.net',
|
||||
licenseText: `The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Brad Dodson
|
||||
|
||||
@@ -138,11 +126,11 @@ mixin openSourceSoftwareNotice
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') Newtonsoft.Json
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
The MIT License (MIT)
|
||||
SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'Newtonsoft.Json',
|
||||
licenseText: `The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007 James Newton-King
|
||||
|
||||
@@ -150,11 +138,11 @@ mixin openSourceSoftwareNotice
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') normalize
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
The MIT License (MIT)
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'normalize',
|
||||
licenseText: `The MIT License (MIT)
|
||||
|
||||
Copyright © Nicolas Gallagher and Jonathan Neal
|
||||
|
||||
@@ -162,11 +150,11 @@ mixin openSourceSoftwareNotice
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') noty
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
Copyright (c) 2012 Nedim Arabacı
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'noty',
|
||||
licenseText: `Copyright (c) 2012 Nedim Arabacı
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -185,11 +173,11 @@ mixin openSourceSoftwareNotice
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') OpenVR SDK
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
Copyright (c) 2015, Valve Corporation
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'OpenVR SDK',
|
||||
licenseText: `Copyright (c) 2015, Valve Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -215,11 +203,11 @@ mixin openSourceSoftwareNotice
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') Twemoji
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
MIT License
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.`
|
||||
},
|
||||
{
|
||||
name: 'Twemoji',
|
||||
licenseText: `MIT License
|
||||
|
||||
Copyright (c) 2021 Twitter
|
||||
|
||||
@@ -239,11 +227,11 @@ mixin openSourceSoftwareNotice
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') SharpDX
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
|
||||
SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'SharpDX',
|
||||
licenseText: `Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -261,11 +249,11 @@ mixin openSourceSoftwareNotice
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') vue
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
The MIT License (MIT)
|
||||
THE SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'vue',
|
||||
licenseText: `The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-present, Yuxi (Evan) You
|
||||
|
||||
@@ -285,11 +273,11 @@ mixin openSourceSoftwareNotice
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') vue-data-tables
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
The MIT License (MIT)
|
||||
THE SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'vue-data-tables',
|
||||
licenseText: `The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Leon Zhang
|
||||
|
||||
@@ -309,11 +297,11 @@ mixin openSourceSoftwareNotice
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') vue-lazyload
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
The MIT License (MIT)
|
||||
SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'vue-lazyload',
|
||||
licenseText: `The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Awe
|
||||
|
||||
@@ -333,12 +321,11 @@ mixin openSourceSoftwareNotice
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') Encode Sans Font (from Dark Vanilla)
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'Encode Sans Font (from Dark Vanilla)',
|
||||
licenseText: `SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
Copyright (c) 2020 June 20, Impallari Type, Andres Torresi, Jacques Le Bailly
|
||||
(https://fonts.google.com/specimen/Encode+Sans),
|
||||
with Reserved Font Name: Encode Sans.
|
||||
@@ -397,20 +384,20 @@ mixin openSourceSoftwareNotice
|
||||
DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
|
||||
OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
|
||||
DEALINGS IN THE FONT SOFTWARE.
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') Apache ECharts
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
Apache License 2.0
|
||||
DEALINGS IN THE FONT SOFTWARE.`
|
||||
},
|
||||
{
|
||||
name: 'Apache ECharts',
|
||||
licenseText: `Apache License 2.0
|
||||
|
||||
Copyright 2017-2025 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (https://www.apache.org/).
|
||||
div(style='margin-top: 15px')
|
||||
p(style='font-weight: bold') dayjs
|
||||
pre(style='font-size: 12px; white-space: pre-line').
|
||||
MIT License
|
||||
The Apache Software Foundation (https://www.apache.org/).`
|
||||
},
|
||||
{
|
||||
name: 'dayjs',
|
||||
licenseText: `MIT License
|
||||
|
||||
Copyright (c) 2018-present, iamkun
|
||||
|
||||
@@ -430,4 +417,8 @@ mixin openSourceSoftwareNotice
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.`
|
||||
}
|
||||
];
|
||||
|
||||
export { openSourceSoftwareLicenses };
|
||||
36
src/composables/settings/constants/vrchatResolutions.js
Normal file
36
src/composables/settings/constants/vrchatResolutions.js
Normal file
@@ -0,0 +1,36 @@
|
||||
function getVRChatResolution(res) {
|
||||
switch (res) {
|
||||
case '1280x720':
|
||||
return '1280x720 (720p)';
|
||||
case '1920x1080':
|
||||
return '1920x1080 (1080p)';
|
||||
case '2560x1440':
|
||||
return '2560x1440 (2K)';
|
||||
case '3840x2160':
|
||||
return '3840x2160 (4K)';
|
||||
case '7680x4320':
|
||||
return '7680x4320 (8K)';
|
||||
}
|
||||
return `${res} (Custom)`;
|
||||
}
|
||||
|
||||
const VRChatScreenshotResolutions = [
|
||||
{ name: '1280x720 (720p)', width: 1280, height: 720 },
|
||||
{ name: '1920x1080 (1080p Default)', width: '', height: '' },
|
||||
{ name: '2560x1440 (1440p)', width: 2560, height: 1440 },
|
||||
{ name: '3840x2160 (4K)', width: 3840, height: 2160 }
|
||||
];
|
||||
|
||||
const VRChatCameraResolutions = [
|
||||
{ name: '1280x720 (720p)', width: 1280, height: 720 },
|
||||
{ name: '1920x1080 (1080p Default)', width: '', height: '' },
|
||||
{ name: '2560x1440 (1440p)', width: 2560, height: 1440 },
|
||||
{ name: '3840x2160 (4K)', width: 3840, height: 2160 },
|
||||
{ name: '7680x4320 (8K)', width: 7680, height: 4320 }
|
||||
];
|
||||
|
||||
export {
|
||||
getVRChatResolution,
|
||||
VRChatScreenshotResolutions,
|
||||
VRChatCameraResolutions
|
||||
};
|
||||
@@ -1,724 +0,0 @@
|
||||
mixin feedFilters
|
||||
//- dialog: Noty feed filters
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='notyFeedFiltersDialog'
|
||||
:visible.sync='notyFeedFiltersDialog.visible'
|
||||
:title='$t("dialog.shared_feed_filters.notification")'
|
||||
width='550px'
|
||||
top='5vh')
|
||||
.toggle-list(style='height: 75vh; overflow-y: auto')
|
||||
.toggle-item
|
||||
span.toggle-name OnPlayerJoining
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.OnPlayerJoining'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name OnPlayerJoined
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.OnPlayerJoined'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name OnPlayerLeft
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.OnPlayerLeft'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Online
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.Online' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Offline
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.Offline' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name GPS
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.GPS' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Status
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.Status' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Invite
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.invite' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Request Invite
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.requestInvite'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Invite Response
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.inviteResponse'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Request Invite Response
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.requestInviteResponse'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Friend Request
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.friendRequest'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name New Friend
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.Friend' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Unfriend
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.Unfriend' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Display Name Change
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.DisplayName'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Trust Level Change
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.TrustLevel' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
//- .toggle-item
|
||||
//- span.toggle-name Boop
|
||||
//- el-radio-group(v-model="sharedFeedFilters.noty.boop" size="mini" @change="saveSharedFeedFilters")
|
||||
//- el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }}
|
||||
//- el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Change
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='When you\'ve left or been kicked from a group, group name changed, group owner changed, role added/removed')
|
||||
i.el-icon-info
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.groupChange'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Announcement
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty["group.announcement"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Join
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='When your request to join a group has been approved')
|
||||
i.el-icon-info
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty["group.informative"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Invite
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='When someone invites you to join a group')
|
||||
i.el-icon-info
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty["group.invite"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Join Request
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='When someone requests to join a group you\'re a moderator for')
|
||||
i.el-icon-info
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty["group.joinRequest"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Transfer Request
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty["group.transfer"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Instance Queue Ready
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty["group.queueReady"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Instance Closed
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='When the instance you\'re in has been closed preventing anyone from joining')
|
||||
i.el-icon-info
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty["instance.closed"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Video Play
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='Requires VRCX YouTube API option enabled')
|
||||
i.el-icon-warning
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.VideoPlay' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Miscellaneous Events
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='Misc event from VRC game log: VRC crash auto rejoin, shader keyword limit, joining instance blocked by master, error loading video, audio device changed, error joining instance, kicked from instance, VRChat failing to start OSC server, etc...')
|
||||
i.el-icon-info
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.Event' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name External App
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.External' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Blocked Player Joins
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.BlockedOnPlayerJoined'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Blocked Player Leaves
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.BlockedOnPlayerLeft'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Muted Player Joins
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.MutedOnPlayerJoined'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Muted Player Leaves
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.MutedOnPlayerLeft'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Lobby Avatar Change
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.AvatarChange'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
template(v-if='photonLoggingEnabled')
|
||||
br
|
||||
.toggle-item
|
||||
span.toggle-name Photon Event Logging
|
||||
.toggle-item
|
||||
span.toggle-name Portal Spawn
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.PortalSpawn'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Lobby ChatBox Message
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.ChatBoxMessage'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Blocked
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.Blocked'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Unblocked
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.Unblocked'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Muted
|
||||
el-radio-group(v-model='sharedFeedFilters.noty.Muted' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Unmuted
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.noty.Unmuted'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
template(#footer)
|
||||
el-button(size='small' @click='resetNotyFeedFilters') {{ $t('dialog.shared_feed_filters.reset') }}
|
||||
el-button(
|
||||
size='small'
|
||||
type='primary'
|
||||
style='margin-left: 10px'
|
||||
@click='notyFeedFiltersDialog.visible = false') {{ $t('dialog.shared_feed_filters.close') }}
|
||||
|
||||
//- dialog: wrist feed filters
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='wristFeedFiltersDialog'
|
||||
:visible.sync='wristFeedFiltersDialog.visible'
|
||||
:title='$t("dialog.shared_feed_filters.wrist")'
|
||||
width='550px'
|
||||
top='5vh')
|
||||
.toggle-list(style='height: 75vh; overflow-y: auto')
|
||||
.toggle-item
|
||||
span.toggle-name Self Location
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.Location' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name OnPlayerJoining
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.OnPlayerJoining'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name OnPlayerJoined
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.OnPlayerJoined'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name OnPlayerLeft
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.OnPlayerLeft'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Online
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.Online' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Offline
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.Offline' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name GPS
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.GPS' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Status
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.Status' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Invite
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.invite' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Request Invite
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.requestInvite'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Invite Response
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.inviteResponse'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Request Invite Response
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.requestInviteResponse'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Friend Request
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.friendRequest'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name New Friend
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.Friend' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Unfriend
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.Unfriend' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Display Name Change
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.DisplayName'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
.toggle-item
|
||||
span.toggle-name Trust Level Change
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.TrustLevel'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
//- .toggle-item
|
||||
//- span.toggle-name Boop
|
||||
//- el-radio-group(v-model="sharedFeedFilters.wrist.boop" size="mini" @change="saveSharedFeedFilters")
|
||||
//- el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }}
|
||||
//- el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Change
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='When you\'ve left or been kicked from a group, group name changed, group owner changed, role added/removed')
|
||||
i.el-icon-info
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.groupChange'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Announcement
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist["group.announcement"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Join
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='When your request to join a group has been approved')
|
||||
i.el-icon-info
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist["group.informative"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Invite
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='When someone invites you to join a group')
|
||||
i.el-icon-info
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist["group.invite"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Join Request
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='When someone requests to join a group you\'re a moderator for')
|
||||
i.el-icon-info
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist["group.joinRequest"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Group Transfer Request
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist["group.transfer"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Instance Queue Ready
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist["group.queueReady"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Instance Closed
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='When the instance you\'re in has been closed preventing anyone from joining')
|
||||
i.el-icon-info
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist["instance.closed"]'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Video Play
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='Requires VRCX YouTube API option enabled')
|
||||
i.el-icon-warning
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.VideoPlay' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Miscellaneous Events
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
style='margin-left: 5px'
|
||||
content='Misc event from VRC game log: VRC crash auto rejoin, shader keyword limit, joining instance blocked by master, error loading video, audio device changed, error joining instance, kicked from instance, VRChat failing to start OSC server, etc...')
|
||||
i.el-icon-info
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.Event' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name External App
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.External' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Blocked Player Joins
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.BlockedOnPlayerJoined'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Blocked Player Leaves
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.BlockedOnPlayerLeft'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Muted Player Joins
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.MutedOnPlayerJoined'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Muted Player Leaves
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.MutedOnPlayerLeft'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Lobby Avatar Change
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.AvatarChange'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
template(v-if='photonLoggingEnabled')
|
||||
br
|
||||
.toggle-item
|
||||
span.toggle-name Photon Event Logging
|
||||
.toggle-item
|
||||
span.toggle-name Portal Spawn
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.PortalSpawn'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Lobby ChatBox Message
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.ChatBoxMessage'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='VIP') {{ $t('dialog.shared_feed_filters.favorite') }}
|
||||
el-radio-button(label='Friends') {{ $t('dialog.shared_feed_filters.friends') }}
|
||||
el-radio-button(label='Everyone') {{ $t('dialog.shared_feed_filters.everyone') }}
|
||||
.toggle-item
|
||||
span.toggle-name Blocked
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.Blocked'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Unblocked
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.Unblocked'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Muted
|
||||
el-radio-group(v-model='sharedFeedFilters.wrist.Muted' size='mini' @change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
.toggle-item
|
||||
span.toggle-name Unmuted
|
||||
el-radio-group(
|
||||
v-model='sharedFeedFilters.wrist.Unmuted'
|
||||
size='mini'
|
||||
@change='saveSharedFeedFilters')
|
||||
el-radio-button(label='Off') {{ $t('dialog.shared_feed_filters.off') }}
|
||||
el-radio-button(label='On') {{ $t('dialog.shared_feed_filters.on') }}
|
||||
template(#footer)
|
||||
el-button(size='small' @click='resetWristFeedFilters') {{ $t('dialog.shared_feed_filters.reset') }}
|
||||
el-button(size='small' type='primary' @click='wristFeedFiltersDialog.visible = false') {{ $t('dialog.shared_feed_filters.close') }}
|
||||
@@ -110,30 +110,6 @@ mixin invites
|
||||
:disabled='inviteDialog.loading || !inviteDialog.userIds.length'
|
||||
@click='sendInvite()') {{ $t('dialog.invite.invite') }}
|
||||
|
||||
//- dialog: Edit Invite Message
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='editInviteMessageDialog'
|
||||
:visible.sync='editInviteMessageDialog.visible'
|
||||
:title='$t("dialog.edit_invite_message.header")'
|
||||
width='400px')
|
||||
div(style='font-size: 12px')
|
||||
span {{ $t('dialog.edit_invite_message.description') }}
|
||||
el-input(
|
||||
type='textarea'
|
||||
v-model='editInviteMessageDialog.newMessage'
|
||||
size='mini'
|
||||
maxlength='64'
|
||||
show-word-limit
|
||||
:autosize='{ minRows: 2, maxRows: 5 }'
|
||||
placeholder=''
|
||||
style='margin-top: 10px')
|
||||
template(#footer)
|
||||
el-button(type='small' @click='cancelEditInviteMessage') {{ $t('dialog.edit_invite_message.cancel') }}
|
||||
el-button(type='primary' size='small' @click='saveEditInviteMessage') {{ $t('dialog.edit_invite_message.save') }}
|
||||
|
||||
//- dialog: Edit And Send Invite Response Message
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
mixin launch
|
||||
//- dialog: launch options
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='launchOptionsDialog'
|
||||
:visible.sync='launchOptionsDialog.visible'
|
||||
:title='$t("dialog.launch_options.header")'
|
||||
width='600px')
|
||||
div(style='font-size: 12px')
|
||||
| {{ $t('dialog.launch_options.description') }} #[br]
|
||||
| {{ $t('dialog.launch_options.example') }} #[el-tag(size='mini') --fps=144]
|
||||
el-input(
|
||||
type='textarea'
|
||||
v-model='launchOptionsDialog.launchArguments'
|
||||
size='mini'
|
||||
show-word-limit
|
||||
:autosize='{ minRows: 2, maxRows: 5 }'
|
||||
placeholder=''
|
||||
style='margin-top: 10px')
|
||||
div(style='font-size: 12px; margin-top: 10px')
|
||||
| {{ $t('dialog.launch_options.path_override') }}
|
||||
el-input(
|
||||
type='textarea'
|
||||
v-model='launchOptionsDialog.vrcLaunchPathOverride'
|
||||
placeholder='C:\\Program Files (x86)\\Steam\\steamapps\\common\\VRChat'
|
||||
:rows='1'
|
||||
style='display: block; margin-top: 10px')
|
||||
template(#footer)
|
||||
div(style='display: flex')
|
||||
el-button(size='small' @click='openExternalLink("https://docs.vrchat.com/docs/launch-options")') {{ $t('dialog.launch_options.vrchat_docs') }}
|
||||
el-button(
|
||||
size='small'
|
||||
@click='openExternalLink("https://docs.unity3d.com/Manual/CommandLineArguments.html")') {{ $t('dialog.launch_options.unity_manual') }}
|
||||
el-button(
|
||||
type='primary'
|
||||
size='small'
|
||||
:disabled='launchOptionsDialog.loading'
|
||||
@click='updateLaunchOptions'
|
||||
style='margin-left: auto') {{ $t('dialog.launch_options.save') }}
|
||||
@@ -1,128 +0,0 @@
|
||||
mixin screenshotMetadata
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='screenshotMetadataDialog'
|
||||
:visible.sync='screenshotMetadataDialog.visible'
|
||||
:title='$t("dialog.screenshot_metadata.header")'
|
||||
width='1050px'
|
||||
top='10vh')
|
||||
div(
|
||||
v-if='screenshotMetadataDialog.visible'
|
||||
v-loading='screenshotMetadataDialog.loading'
|
||||
@dragover.prevent
|
||||
@dragenter.prevent
|
||||
@drop='handleDrop'
|
||||
style='-webkit-app-region: drag')
|
||||
span(style='margin-left: 5px; color: #909399; font-family: monospace') {{ $t('dialog.screenshot_metadata.drag') }}
|
||||
br
|
||||
br
|
||||
el-button(size='small' icon='el-icon-folder-opened' @click='getAndDisplayScreenshotFromFile()') {{ $t('dialog.screenshot_metadata.browse') }}
|
||||
el-button(size='small' icon='el-icon-picture-outline' @click='getAndDisplayLastScreenshot()') {{ $t('dialog.screenshot_metadata.last_screenshot') }}
|
||||
el-button(
|
||||
size='small'
|
||||
icon='el-icon-copy-document'
|
||||
@click='copyImageToClipboard(screenshotMetadataDialog.metadata.filePath)') {{ $t('dialog.screenshot_metadata.copy_image') }}
|
||||
el-button(
|
||||
size='small'
|
||||
icon='el-icon-folder'
|
||||
@click='openImageFolder(screenshotMetadataDialog.metadata.filePath)') {{ $t('dialog.screenshot_metadata.open_folder') }}
|
||||
el-button(
|
||||
v-if='API.currentUser.$isVRCPlus && screenshotMetadataDialog.metadata.filePath'
|
||||
size='small'
|
||||
icon='el-icon-upload2'
|
||||
@click='uploadScreenshotToGallery') {{ $t('dialog.screenshot_metadata.upload') }}
|
||||
br
|
||||
br
|
||||
//- Search bar input
|
||||
el-input(
|
||||
v-model='screenshotMetadataDialog.search'
|
||||
size='small'
|
||||
placeholder='Search'
|
||||
clearable
|
||||
style='width: 200px'
|
||||
@input='screenshotMetadataSearch')
|
||||
//- Search index/total label
|
||||
template(v-if='screenshotMetadataDialog.searchIndex != null')
|
||||
span(style='white-space: pre-wrap; font-size: 12px; margin-left: 10px') {{ screenshotMetadataDialog.searchIndex + 1 + '/' + screenshotMetadataDialog.searchResults.length }}
|
||||
//- Search type dropdown
|
||||
el-select(
|
||||
v-model='screenshotMetadataDialog.searchType'
|
||||
size='small'
|
||||
placeholder='Search Type'
|
||||
style='width: 150px; margin-left: 10px'
|
||||
@change='screenshotMetadataSearch')
|
||||
el-option(v-for='type in screenshotMetadataDialog.searchTypes' :key='type' :label='type' :value='type')
|
||||
br
|
||||
br
|
||||
span(v-text='screenshotMetadataDialog.metadata.fileName')
|
||||
br
|
||||
template(v-if='screenshotMetadataDialog.metadata.note')
|
||||
span(v-text='screenshotMetadataDialog.metadata.note')
|
||||
br
|
||||
span(v-if='screenshotMetadataDialog.metadata.dateTime' style='margin-right: 5px') {{ screenshotMetadataDialog.metadata.dateTime | formatDate('long') }}
|
||||
span(
|
||||
v-if='screenshotMetadataDialog.metadata.fileResolution'
|
||||
v-text='screenshotMetadataDialog.metadata.fileResolution'
|
||||
style='margin-right: 5px')
|
||||
el-tag(
|
||||
v-if='screenshotMetadataDialog.metadata.fileSize'
|
||||
type='info'
|
||||
effect='plain'
|
||||
size='mini'
|
||||
v-text='screenshotMetadataDialog.metadata.fileSize')
|
||||
br
|
||||
location(
|
||||
v-if='screenshotMetadataDialog.metadata.world'
|
||||
:location='screenshotMetadataDialog.metadata.world.instanceId'
|
||||
:hint='screenshotMetadataDialog.metadata.world.name')
|
||||
br
|
||||
display-name(
|
||||
v-if='screenshotMetadataDialog.metadata.author'
|
||||
:userid='screenshotMetadataDialog.metadata.author.id'
|
||||
:hint='screenshotMetadataDialog.metadata.author.displayName'
|
||||
style='color: #909399; font-family: monospace')
|
||||
br
|
||||
el-carousel(
|
||||
ref='screenshotMetadataCarousel'
|
||||
:interval='0'
|
||||
:initial-index='1'
|
||||
indicator-position='none'
|
||||
arrow='always'
|
||||
height='600px'
|
||||
style='margin-top: 10px'
|
||||
@change='screenshotMetadataCarouselChange')
|
||||
el-carousel-item
|
||||
span(placement='top' width='700px' trigger='click')
|
||||
img.x-link(
|
||||
slot='reference'
|
||||
:src='screenshotMetadataDialog.metadata.previousFilePath'
|
||||
style='width: 100%; height: 100%; object-fit: contain')
|
||||
el-carousel-item
|
||||
span(
|
||||
placement='top'
|
||||
width='700px'
|
||||
trigger='click'
|
||||
@click='showFullscreenImageDialog(screenshotMetadataDialog.metadata.filePath)')
|
||||
img.x-link(
|
||||
slot='reference'
|
||||
:src='screenshotMetadataDialog.metadata.filePath'
|
||||
style='width: 100%; height: 100%; object-fit: contain')
|
||||
el-carousel-item
|
||||
span(placement='top' width='700px' trigger='click')
|
||||
img.x-link(
|
||||
slot='reference'
|
||||
:src='screenshotMetadataDialog.metadata.nextFilePath'
|
||||
style='width: 100%; height: 100%; object-fit: contain')
|
||||
br
|
||||
template(v-if='screenshotMetadataDialog.metadata.error')
|
||||
pre(v-text='screenshotMetadataDialog.metadata.error' style='white-space: pre-wrap; font-size: 12px')
|
||||
br
|
||||
span(v-for='user in screenshotMetadataDialog.metadata.players' style='margin-top: 5px')
|
||||
span.x-link(v-text='user.displayName' @click='lookupUser(user)')
|
||||
span(
|
||||
v-if='user.pos'
|
||||
v-text='"(" + user.pos.x + ", " + user.pos.y + ", " + user.pos.z + ")"'
|
||||
style='margin-left: 5px; color: #909399; font-family: monospace')
|
||||
br
|
||||
@@ -1,442 +0,0 @@
|
||||
mixin settings
|
||||
//- dialog: VRChat Config JSON
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='VRChatConfigDialog'
|
||||
:visible.sync='VRChatConfigDialog.visible'
|
||||
:title='$t("dialog.config_json.header")'
|
||||
width='420px'
|
||||
top='10vh')
|
||||
div(style='font-size: 12px; word-break: keep-all')
|
||||
| {{ $t('dialog.config_json.description1') }} #[br]
|
||||
| {{ $t('dialog.config_json.description2') }}
|
||||
br
|
||||
span(style='margin-right: 5px') {{ $t('dialog.config_json.cache_size') }}
|
||||
span(v-text='VRChatUsedCacheSize')
|
||||
span /
|
||||
span(v-text='VRChatTotalCacheSize')
|
||||
span GB
|
||||
el-tooltip(placement='top' :content='$t("dialog.config_json.refresh")' :disabled='hideTooltips')
|
||||
el-button(
|
||||
type='default'
|
||||
:loading='VRChatCacheSizeLoading'
|
||||
@click='getVRChatCacheSize'
|
||||
size='small'
|
||||
icon='el-icon-refresh'
|
||||
circle
|
||||
style='margin-left: 5px')
|
||||
div(style='margin-top: 10px')
|
||||
span(style='margin-right: 5px') {{ $t('dialog.config_json.delete_all_cache') }}
|
||||
el-button(
|
||||
size='small'
|
||||
style='margin-left: 5px'
|
||||
icon='el-icon-delete'
|
||||
@click='showDeleteAllVRChatCacheConfirm()') {{ $t('dialog.config_json.delete_cache') }}
|
||||
div(style='margin-top: 10px')
|
||||
span(style='margin-right: 5px') {{ $t('dialog.config_json.delete_old_cache') }}
|
||||
el-button(size='small' style='margin-left: 5px' icon='el-icon-folder-delete' @click='sweepVRChatCache()') {{ $t('dialog.config_json.sweep_cache') }}
|
||||
div(style='display: block; margin-top: 10px' v-for='(item, value) in VRChatConfigList' :key='value')
|
||||
span(style='word-break: keep-all') {{ item.name }}:
|
||||
div(style='display: flex')
|
||||
el-button(
|
||||
v-if='item.folderBrowser'
|
||||
size='mini'
|
||||
icon='el-icon-folder-opened'
|
||||
@click='openConfigFolderBrowser(value)')
|
||||
el-input(
|
||||
v-model='VRChatConfigFile[value]'
|
||||
:placeholder='item.default'
|
||||
size='mini'
|
||||
:type='item.type ? item.type : "text"'
|
||||
:min='item.min'
|
||||
:max='item.max'
|
||||
@change='redrawVRChatConfigDialog'
|
||||
style='flex: 1; margin-top: 5px')
|
||||
div(style='display: inline-block; margin-top: 10px')
|
||||
span {{ $t('dialog.config_json.camera_resolution') }}
|
||||
br
|
||||
el-dropdown(
|
||||
@command='(command) => setVRChatCameraResolution(command)'
|
||||
size='small'
|
||||
trigger='click'
|
||||
style='margin-top: 5px')
|
||||
el-button(size='small')
|
||||
span #[span(v-text='getVRChatCameraResolution()')] #[i.el-icon-arrow-down.el-icon--right]
|
||||
el-dropdown-menu(#default='dropdown')
|
||||
el-dropdown-item(
|
||||
v-for='row in VRChatCameraResolutions'
|
||||
:key='row.index'
|
||||
v-text='row.name'
|
||||
:command='row')
|
||||
br
|
||||
div(style='display: inline-block; margin-top: 10px')
|
||||
span {{ $t('dialog.config_json.spout_resolution') }}
|
||||
br
|
||||
el-dropdown(
|
||||
@command='(command) => setVRChatSpoutResolution(command)'
|
||||
size='small'
|
||||
trigger='click'
|
||||
style='margin-top: 5px')
|
||||
el-button(size='small')
|
||||
span #[span(v-text='getVRChatSpoutResolution()')] #[i.el-icon-arrow-down.el-icon--right]
|
||||
el-dropdown-menu(#default='dropdown')
|
||||
el-dropdown-item(
|
||||
v-for='row in VRChatScreenshotResolutions'
|
||||
:key='row.index'
|
||||
v-text='row.name'
|
||||
:command='row')
|
||||
br
|
||||
div(style='display: inline-block; margin-top: 10px')
|
||||
span {{ $t('dialog.config_json.screenshot_resolution') }}
|
||||
br
|
||||
el-dropdown(
|
||||
@command='(command) => setVRChatScreenshotResolution(command)'
|
||||
size='small'
|
||||
trigger='click'
|
||||
style='margin-top: 5px')
|
||||
el-button(size='small')
|
||||
span #[span(v-text='getVRChatScreenshotResolution()')] #[i.el-icon-arrow-down.el-icon--right]
|
||||
el-dropdown-menu(#default='dropdown')
|
||||
el-dropdown-item(
|
||||
v-for='row in VRChatScreenshotResolutions'
|
||||
:key='row.index'
|
||||
v-text='row.name'
|
||||
:command='row')
|
||||
el-checkbox(v-model='VRChatConfigFile.picture_output_split_by_date' style='margin-top: 5px; display: block') {{ $t('dialog.config_json.picture_sort_by_date') }}
|
||||
el-checkbox(v-model='VRChatConfigFile.disableRichPresence' style='margin-top: 5px; display: block') {{ $t('dialog.config_json.disable_discord_presence') }}
|
||||
template(#footer)
|
||||
div(style='display: flex; align-items: center; justify-content: space-between')
|
||||
div
|
||||
el-button(
|
||||
size='small'
|
||||
@click='openExternalLink("https://docs.vrchat.com/docs/configuration-file")') {{ $t('dialog.config_json.vrchat_docs') }}
|
||||
div
|
||||
el-button(size='small' @click='VRChatConfigDialog.visible = false') {{ $t('dialog.config_json.cancel') }}
|
||||
el-button(
|
||||
size='small'
|
||||
type='primary'
|
||||
:disabled='VRChatConfigDialog.loading'
|
||||
@click='saveVRChatConfigFile') {{ $t('dialog.config_json.save') }}
|
||||
|
||||
//- dialog: YouTube Api Dialog
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='youTubeApiDialog'
|
||||
:visible.sync='youTubeApiDialog.visible'
|
||||
:title='$t("dialog.youtube_api.header")'
|
||||
width='400px')
|
||||
div(style='font-size: 12px')
|
||||
| {{ $t('dialog.youtube_api.description') }} #[br]
|
||||
el-input(
|
||||
type='textarea'
|
||||
v-model='youTubeApiKey'
|
||||
:placeholder='$t("dialog.youtube_api.placeholder")'
|
||||
maxlength='39'
|
||||
show-word-limit
|
||||
style='display: block; margin-top: 10px')
|
||||
template(#footer)
|
||||
div(style='display: flex')
|
||||
el-button(
|
||||
size='small'
|
||||
@click='openExternalLink("https://rapidapi.com/blog/how-to-get-youtube-api-key/")') {{ $t('dialog.youtube_api.guide') }}
|
||||
el-button(type='primary' size='small' @click='testYouTubeApiKey' style='margin-left: auto') {{ $t('dialog.youtube_api.save') }}
|
||||
|
||||
//- dialog: Discord username list
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
:visible.sync='discordNamesDialogVisible'
|
||||
:title='$t("dialog.discord_names.header")'
|
||||
width='650px')
|
||||
div(style='font-size: 12px')
|
||||
| {{ $t('dialog.discord_names.description') }}
|
||||
el-input(
|
||||
type='textarea'
|
||||
v-if='discordNamesDialogVisible'
|
||||
v-model='discordNamesContent'
|
||||
size='mini'
|
||||
rows='15'
|
||||
resize='none'
|
||||
readonly
|
||||
style='margin-top: 15px')
|
||||
|
||||
//- dialog: Note export dialog
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='noteExportDialog'
|
||||
:visible.sync='noteExportDialog.visible'
|
||||
:title='$t("dialog.note_export.header")'
|
||||
width='1000px')
|
||||
div(style='font-size: 12px')
|
||||
| {{ $t('dialog.note_export.description1') }} #[br]
|
||||
| {{ $t('dialog.note_export.description2') }} #[br]
|
||||
| {{ $t('dialog.note_export.description3') }} #[br]
|
||||
| {{ $t('dialog.note_export.description4') }} #[br]
|
||||
| {{ $t('dialog.note_export.description5') }} #[br]
|
||||
| {{ $t('dialog.note_export.description6') }} #[br]
|
||||
| {{ $t('dialog.note_export.description7') }} #[br]
|
||||
| {{ $t('dialog.note_export.description8') }} #[br]
|
||||
el-button(
|
||||
size='small'
|
||||
@click='updateNoteExportDialog'
|
||||
:disabled='noteExportDialog.loading'
|
||||
style='margin-top: 10px') {{ $t('dialog.note_export.refresh') }}
|
||||
el-button(size='small' @click='exportNoteExport' :disabled='noteExportDialog.loading' style='margin-top: 10px') {{ $t('dialog.note_export.export') }}
|
||||
el-button(v-if='noteExportDialog.loading' size='small' @click='cancelNoteExport' style='margin-top: 10px') {{ $t('dialog.note_export.cancel') }}
|
||||
span(v-if='noteExportDialog.loading' style='margin: 10px') #[i.el-icon-loading(style='margin-right: 5px')] {{ $t('dialog.note_export.progress') }} {{ noteExportDialog.progress }}/{{ noteExportDialog.progressTotal }}
|
||||
template(v-if='noteExportDialog.errors')
|
||||
el-button(size='small' @click='noteExportDialog.errors = ""') {{ $t('dialog.note_export.clear_errors') }}
|
||||
h2(style='font-weight: bold; margin: 0') {{ $t('dialog.note_export.errors') }}
|
||||
pre(v-text='noteExportDialog.errors' style='white-space: pre-wrap; font-size: 12px')
|
||||
data-tables(
|
||||
v-if='noteExportDialog.visible'
|
||||
v-bind='noteExportTable'
|
||||
v-loading='noteExportDialog.loading'
|
||||
style='margin-top: 10px')
|
||||
el-table-column(:label='$t("table.import.image")' width='70' prop='currentAvatarThumbnailImageUrl')
|
||||
template(#default='scope')
|
||||
el-popover(placement='right' height='500px' trigger='hover')
|
||||
img.friends-list-avatar(slot='reference' v-lazy='userImage(scope.row.ref)')
|
||||
img.friends-list-avatar(
|
||||
v-lazy='userImageFull(scope.row.ref)'
|
||||
style='height: 500px; cursor: pointer'
|
||||
@click='showFullscreenImageDialog(userImageFull(scope.row.ref))')
|
||||
el-table-column(:label='$t("table.import.name")' width='170' prop='name')
|
||||
template(#default='scope')
|
||||
span.x-link(v-text='scope.row.name' @click='showUserDialog(scope.row.id)')
|
||||
el-table-column(:label='$t("table.import.note")' prop='memo')
|
||||
template(#default='scope')
|
||||
el-input(
|
||||
v-model='scope.row.memo'
|
||||
type='textarea'
|
||||
maxlength='256'
|
||||
show-word-limit
|
||||
:rows='2'
|
||||
:autosize='{ minRows: 1, maxRows: 10 }'
|
||||
size='mini'
|
||||
resize='none')
|
||||
el-table-column(:label='$t("table.import.skip_export")' width='90' align='right')
|
||||
template(#default='scope')
|
||||
el-button(
|
||||
type='text'
|
||||
icon='el-icon-close'
|
||||
size='mini'
|
||||
@click='removeFromNoteExportTable(scope.row)')
|
||||
|
||||
//- dialog: chatbox blacklist
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='chatboxBlacklistDialog'
|
||||
:visible.sync='chatboxBlacklistDialog.visible'
|
||||
:title='$t("dialog.chatbox_blacklist.header")'
|
||||
width='600px')
|
||||
div(v-loading='chatboxBlacklistDialog.loading' v-if='chatboxBlacklistDialog.visible')
|
||||
h2 {{ $t('dialog.chatbox_blacklist.keyword_blacklist') }}
|
||||
el-input(
|
||||
v-for='(item, index) in chatboxBlacklist'
|
||||
:key='index'
|
||||
:value='item'
|
||||
v-model='chatboxBlacklist[index]'
|
||||
size='small'
|
||||
style='margin-top: 5px'
|
||||
@change='saveChatboxBlacklist')
|
||||
el-button(
|
||||
slot='append'
|
||||
icon='el-icon-delete'
|
||||
@click='chatboxBlacklist.splice(index, 1); saveChatboxBlacklist()')
|
||||
el-button(@click='chatboxBlacklist.push("")' size='mini' style='margin-top: 5px') {{ $t('dialog.chatbox_blacklist.add_item') }}
|
||||
br
|
||||
h2 {{ $t('dialog.chatbox_blacklist.user_blacklist') }}
|
||||
el-tag(
|
||||
v-for='user in chatboxUserBlacklist'
|
||||
type='info'
|
||||
disable-transitions='true'
|
||||
:key='user[0]'
|
||||
style='margin-right: 5px; margin-top: 5px'
|
||||
closable
|
||||
@close='deleteChatboxUserBlacklist(user[0])')
|
||||
span {{ user[1] }}
|
||||
|
||||
//- dialog: Notification position
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='notificationPositionDialog'
|
||||
:visible.sync='notificationPositionDialog.visible'
|
||||
:title='$t("dialog.notification_position.header")'
|
||||
width='400px')
|
||||
div(style='font-size: 12px')
|
||||
| {{ $t('dialog.notification_position.description') }}
|
||||
svg.notification-position(
|
||||
version='1.1'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
xmlns:xlink='http://www.w3.org/1999/xlink'
|
||||
x='0px'
|
||||
y='0px'
|
||||
viewBox='0 0 300 200'
|
||||
style='margin-top: 15px'
|
||||
xml:space='preserve')
|
||||
path(
|
||||
style='fill: black'
|
||||
d='M291.89,5A3.11,3.11,0,0,1,295,8.11V160.64a3.11,3.11,0,0,1-3.11,3.11H8.11A3.11,3.11,0,0,1,5,160.64V8.11A3.11,3.11,0,0,1,8.11,5H291.89m0-5H8.11A8.11,8.11,0,0,0,0,8.11V160.64a8.11,8.11,0,0,0,8.11,8.11H291.89a8.11,8.11,0,0,0,8.11-8.11V8.11A8.11,8.11,0,0,0,291.89,0Z')
|
||||
rect(style='fill: #c4c4c4' x='5' y='5' width='290' height='158.75' rx='2.5')
|
||||
el-radio-group(v-model='notificationPosition' size='mini' @change='changeNotificationPosition')
|
||||
el-radio(
|
||||
label='topLeft'
|
||||
v-model='notificationPosition'
|
||||
style='margin: 0; position: absolute; left: 35px; top: 120px')
|
||||
el-radio(
|
||||
label='top'
|
||||
v-model='notificationPosition'
|
||||
style='margin: 0; position: absolute; left: 195px; top: 120px')
|
||||
el-radio(
|
||||
label='topRight'
|
||||
v-model='notificationPosition'
|
||||
style='margin: 0; position: absolute; right: 25px; top: 120px')
|
||||
el-radio(
|
||||
label='centerLeft'
|
||||
v-model='notificationPosition'
|
||||
style='margin: 0; position: absolute; left: 35px; top: 200px')
|
||||
el-radio(
|
||||
label='center'
|
||||
v-model='notificationPosition'
|
||||
style='margin: 0; position: absolute; left: 195px; top: 200px')
|
||||
el-radio(
|
||||
label='centerRight'
|
||||
v-model='notificationPosition'
|
||||
style='margin: 0; position: absolute; right: 25px; top: 200px')
|
||||
el-radio(
|
||||
label='bottomLeft'
|
||||
v-model='notificationPosition'
|
||||
style='margin: 0; position: absolute; left: 35px; top: 280px')
|
||||
el-radio(
|
||||
label='bottom'
|
||||
v-model='notificationPosition'
|
||||
style='margin: 0; position: absolute; left: 195px; top: 280px')
|
||||
el-radio(
|
||||
label='bottomRight'
|
||||
v-model='notificationPosition'
|
||||
style='margin: 0; position: absolute; right: 25px; top: 280px')
|
||||
template(#footer)
|
||||
div(style='display: flex')
|
||||
el-button(
|
||||
type='primary'
|
||||
size='small'
|
||||
style='margin-left: auto'
|
||||
@click='notificationPositionDialog.visible = false') {{ $t('dialog.notification_position.ok') }}
|
||||
|
||||
//- dialog: avatar database provider
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='avatarProviderDialog'
|
||||
:visible.sync='avatarProviderDialog.visible'
|
||||
:title='$t("dialog.avatar_database_provider.header")'
|
||||
width='600px')
|
||||
div
|
||||
el-input(
|
||||
v-for='(provider, index) in avatarRemoteDatabaseProviderList'
|
||||
:key='index'
|
||||
:value='provider'
|
||||
v-model='avatarRemoteDatabaseProviderList[index]'
|
||||
@change='saveAvatarProviderList'
|
||||
size='small'
|
||||
style='margin-top: 5px')
|
||||
el-button(slot='append' icon='el-icon-delete' @click='removeAvatarProvider(provider)')
|
||||
el-button(@click='avatarRemoteDatabaseProviderList.push("")' size='mini' style='margin-top: 5px') {{ $t('dialog.avatar_database_provider.add_provider') }}
|
||||
|
||||
//- dialog: Registry Auto Backup
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@closed='clearVrcRegistryDialog'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='registryBackupDialog'
|
||||
:visible.sync='registryBackupDialog.visible'
|
||||
:title='$t("dialog.registry_backup.header")'
|
||||
width='600px')
|
||||
div(v-if='registryBackupDialog.visible' style='margin-top: 10px')
|
||||
div(style='display: flex; align-items: center; justify-content: space-between; font-size: 12px')
|
||||
span.name(style='margin-right: 24px') {{ $t('dialog.registry_backup.auto_backup') }}
|
||||
el-switch(v-model='vrcRegistryAutoBackup' @change='saveVrcRegistryAutoBackup')
|
||||
data-tables(v-bind='registryBackupTable' style='margin-top: 10px')
|
||||
el-table-column(:label='$t("dialog.registry_backup.name")' prop='name')
|
||||
el-table-column(:label='$t("dialog.registry_backup.date")' prop='date')
|
||||
template(#default='scope')
|
||||
span {{ scope.row.date | formatDate('long') }}
|
||||
el-table-column(:label='$t("dialog.registry_backup.action")' width='90' align='right')
|
||||
template(#default='scope')
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
:content='$t("dialog.registry_backup.restore")'
|
||||
:disabled='hideTooltips')
|
||||
el-button(
|
||||
type='text'
|
||||
icon='el-icon-upload2'
|
||||
size='mini'
|
||||
@click='restoreVrcRegistryBackup(scope.row)')
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
:content='$t("dialog.registry_backup.save_to_file")'
|
||||
:disabled='hideTooltips')
|
||||
el-button(
|
||||
type='text'
|
||||
icon='el-icon-download'
|
||||
size='mini'
|
||||
@click='saveVrcRegistryBackupToFile(scope.row)')
|
||||
el-tooltip(
|
||||
placement='top'
|
||||
:content='$t("dialog.registry_backup.delete")'
|
||||
:disabled='hideTooltips')
|
||||
el-button(
|
||||
type='text'
|
||||
icon='el-icon-delete'
|
||||
size='mini'
|
||||
@click='deleteVrcRegistryBackup(scope.row)')
|
||||
div(style='display: flex; align-items: center; justify-content: space-between; margin-top: 10px')
|
||||
el-button(type='danger' @click='deleteVrcRegistry' size='small') {{ $t('dialog.registry_backup.reset') }}
|
||||
div
|
||||
el-button(@click='promptVrcRegistryBackupName' size='small') {{ $t('dialog.registry_backup.backup') }}
|
||||
el-button(@click='restoreVrcRegistryFromFile' size='small') {{ $t('dialog.registry_backup.restore_from_file') }}
|
||||
|
||||
//- dialog: Enable primary password
|
||||
el-dialog.x-dialog(
|
||||
:visible.sync='enablePrimaryPasswordDialog.visible'
|
||||
:before-close='enablePrimaryPasswordDialog.beforeClose'
|
||||
ref='primaryPasswordDialog'
|
||||
:close-on-click-modal='false'
|
||||
:title='$t("dialog.primary_password.header")'
|
||||
width='400px')
|
||||
el-input(
|
||||
v-model='enablePrimaryPasswordDialog.password'
|
||||
:placeholder='$t("dialog.primary_password.password_placeholder")'
|
||||
type='password'
|
||||
size='mini'
|
||||
maxlength='32'
|
||||
show-password
|
||||
autofocus)
|
||||
el-input(
|
||||
v-model='enablePrimaryPasswordDialog.rePassword'
|
||||
:placeholder='$t("dialog.primary_password.re_input_placeholder")'
|
||||
type='password'
|
||||
style='margin-top: 5px'
|
||||
size='mini'
|
||||
maxlength='32'
|
||||
show-password)
|
||||
template(#footer)
|
||||
el-button(
|
||||
type='primary'
|
||||
size='small'
|
||||
@click='setPrimaryPassword'
|
||||
:disabled='enablePrimaryPasswordDialog.password.length === 0 || enablePrimaryPasswordDialog.password !== enablePrimaryPasswordDialog.rePassword') {{ $t('dialog.primary_password.ok') }}
|
||||
@@ -1,69 +0,0 @@
|
||||
mixin vrcx
|
||||
//- dialog: update VRCX
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='VRCXUpdateDialog'
|
||||
:visible.sync='VRCXUpdateDialog.visible'
|
||||
:title='$t("dialog.vrcx_updater.header")'
|
||||
width='400px')
|
||||
div(v-loading='checkingForVRCXUpdate' style='margin-top: 15px')
|
||||
template(v-if='updateInProgress')
|
||||
el-progress(:percentage='updateProgress' :format='updateProgressText')
|
||||
br
|
||||
template(v-else)
|
||||
div(v-if='VRCXUpdateDialog.updatePending' style='margin-bottom: 15px')
|
||||
span(v-text='pendingVRCXInstall')
|
||||
br
|
||||
span {{ $t('dialog.vrcx_updater.ready_for_update') }}
|
||||
el-select(
|
||||
v-model='branch'
|
||||
@change='loadBranchVersions'
|
||||
style='display: inline-block; width: 150px; margin-right: 15px')
|
||||
el-option(v-for='branch in branches' :key='branch.name' :label='branch.name' :value='branch.name')
|
||||
el-select(v-model='VRCXUpdateDialog.release' style='display: inline-block; width: 150px')
|
||||
el-option(
|
||||
v-for='item in VRCXUpdateDialog.releases'
|
||||
:key='item.name'
|
||||
:label='item.tag_name'
|
||||
:value='item.name')
|
||||
div(
|
||||
v-if='!VRCXUpdateDialog.updatePending && VRCXUpdateDialog.release === appVersion'
|
||||
style='margin-top: 15px')
|
||||
span {{ $t('dialog.vrcx_updater.latest_version') }}
|
||||
template(#footer)
|
||||
el-button(v-if='updateInProgress' type='primary' size='small' @click='cancelUpdate') {{ $t('dialog.vrcx_updater.cancel') }}
|
||||
el-button(
|
||||
v-if='VRCXUpdateDialog.release !== pendingVRCXInstall'
|
||||
:disabled='updateInProgress'
|
||||
type='primary'
|
||||
size='small'
|
||||
@click='installVRCXUpdate') {{ $t('dialog.vrcx_updater.download') }}
|
||||
el-button(
|
||||
v-if='!updateInProgress && pendingVRCXInstall'
|
||||
type='primary'
|
||||
size='small'
|
||||
@click='restartVRCX(true)') {{ $t('dialog.vrcx_updater.install') }}
|
||||
|
||||
//- dialog: change log
|
||||
el-dialog.x-dialog(
|
||||
:before-close='beforeDialogClose'
|
||||
@mousedown.native='dialogMouseDown'
|
||||
@mouseup.native='dialogMouseUp'
|
||||
ref='changeLogDialog'
|
||||
:visible.sync='changeLogDialog.visible'
|
||||
:title='$t("dialog.change_log.header")'
|
||||
width='800px'
|
||||
top='5vh')
|
||||
.changelog-dialog(v-if='changeLogDialog.visible')
|
||||
h2(v-text='changeLogDialog.buildName')
|
||||
span {{ $t('dialog.change_log.description') }} #[a.x-link(@click='openExternalLink("https://www.patreon.com/Natsumi_VRCX")') Patreon], #[a.x-link(@click='openExternalLink("https://ko-fi.com/natsumi_sama")') Ko-fi].
|
||||
vue-markdown(
|
||||
:source='changeLogDialog.changeLog'
|
||||
:linkify='false'
|
||||
style='height: 62vh; overflow-y: auto; margin-top: 10px')
|
||||
template(#footer)
|
||||
el-button(type='small' @click='openExternalLink("https://github.com/vrcx-team/VRCX/releases")') {{ $t('dialog.change_log.github') }}
|
||||
el-button(type='small' @click='openExternalLink("https://patreon.com/Natsumi_VRCX")') {{ $t('dialog.change_log.donate') }}
|
||||
el-button(type='small' @click='changeLogDialog.visible = false') {{ $t('dialog.change_log.close') }}
|
||||
@@ -49,11 +49,6 @@ mixin profileTab
|
||||
icon='el-icon-user'
|
||||
@click='showExportAvatarsListDialog()'
|
||||
style='margin-left: 0; margin-right: 5px; margin-top: 10px') {{ $t('view.profile.profile.export_own_avatars') }}
|
||||
el-button(
|
||||
size='small'
|
||||
icon='el-icon-document-copy'
|
||||
@click='showNoteExportDialog()'
|
||||
style='margin-left: 0; margin-right: 5px; margin-top: 10px') {{ $t('view.profile.profile.export_notes') }}
|
||||
|
||||
.options-container
|
||||
span.header {{ $t('view.profile.game_info.header') }}
|
||||
|
||||
98
src/views/PlayerList/dialogs/ChatboxBlacklistDialog.vue
Normal file
98
src/views/PlayerList/dialogs/ChatboxBlacklistDialog.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible.sync="chatboxBlacklistDialog.visible"
|
||||
:title="t('dialog.chatbox_blacklist.header')"
|
||||
width="600px"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div v-if="chatboxBlacklistDialog.visible" v-loading="chatboxBlacklistDialog.loading">
|
||||
<h2>{{ t('dialog.chatbox_blacklist.keyword_blacklist') }}</h2>
|
||||
<el-input
|
||||
v-for="(item, index) in chatboxBlacklist"
|
||||
:key="index"
|
||||
v-model="chatboxBlacklist[index]"
|
||||
size="small"
|
||||
style="margin-top: 5px"
|
||||
@change="saveChatboxBlacklist">
|
||||
<template #append>
|
||||
<el-button
|
||||
icon="el-icon-delete"
|
||||
@click="
|
||||
chatboxBlacklist.splice(index, 1);
|
||||
saveChatboxBlacklist();
|
||||
">
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button size="mini" style="margin-top: 5px" @click="chatboxBlacklist.push('')">
|
||||
{{ t('dialog.chatbox_blacklist.add_item') }}
|
||||
</el-button>
|
||||
<br />
|
||||
<h2>{{ t('dialog.chatbox_blacklist.user_blacklist') }}</h2>
|
||||
<el-tag
|
||||
v-for="user in chatboxUserBlacklist"
|
||||
:key="user[0]"
|
||||
type="info"
|
||||
disable-transitions
|
||||
style="margin-right: 5px; margin-top: 5px"
|
||||
closable
|
||||
@close="deleteChatboxUserBlacklist(user[0])">
|
||||
<span>{{ user[1] }}</span>
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// TODO: untested
|
||||
import { inject, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import configRepository from '../../../service/config';
|
||||
const { t } = useI18n();
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
|
||||
defineProps({
|
||||
chatboxBlacklistDialog: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
chatboxUserBlacklist: {
|
||||
type: Map,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const chatboxBlacklist = ref([
|
||||
'NP: ',
|
||||
'Now Playing',
|
||||
'Now playing',
|
||||
"▶️ '",
|
||||
'( ▶️ ',
|
||||
"' - '",
|
||||
"' by '",
|
||||
'[Spotify] '
|
||||
]);
|
||||
|
||||
const emit = defineEmits(['deleteChatboxUserBlacklist']);
|
||||
|
||||
initChatboxBlacklist();
|
||||
|
||||
async function initChatboxBlacklist() {
|
||||
if (await configRepository.getString('VRCX_chatboxBlacklist')) {
|
||||
chatboxBlacklist.value = JSON.parse(await configRepository.getString('VRCX_chatboxBlacklist'));
|
||||
}
|
||||
}
|
||||
|
||||
async function saveChatboxBlacklist() {
|
||||
await configRepository.setString('VRCX_chatboxBlacklist', JSON.stringify(chatboxBlacklist.value));
|
||||
}
|
||||
|
||||
function deleteChatboxUserBlacklist(userId) {
|
||||
emit('deleteChatboxUserBlacklist', userId);
|
||||
}
|
||||
</script>
|
||||
105
src/views/Profile/dialogs/DiscordNamesDialog.vue
Normal file
105
src/views/Profile/dialogs/DiscordNamesDialog.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible="discordNamesDialogVisible"
|
||||
:title="t('dialog.discord_names.header')"
|
||||
width="650px"
|
||||
@close="closeDialog"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div style="font-size: 12px">
|
||||
{{ t('dialog.discord_names.description') }}
|
||||
</div>
|
||||
<el-input
|
||||
v-model="discordNamesContent"
|
||||
type="textarea"
|
||||
size="mini"
|
||||
rows="15"
|
||||
resize="none"
|
||||
readonly
|
||||
style="margin-top: 15px" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, inject } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
|
||||
const API = inject('API');
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
discordNamesDialogVisible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
friends: {
|
||||
type: Map,
|
||||
default: () => new Map()
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.discordNamesDialogVisible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
showDiscordNamesContent();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits(['update:discordNamesDialogVisible']);
|
||||
|
||||
const discordNamesContent = ref('');
|
||||
|
||||
function showDiscordNamesContent() {
|
||||
const { friends } = API.currentUser;
|
||||
if (Array.isArray(friends) === false) {
|
||||
return;
|
||||
}
|
||||
const lines = ['DisplayName,DiscordName'];
|
||||
const _ = function (str) {
|
||||
if (/[\x00-\x1f,"]/.test(str) === true) {
|
||||
return `"${str.replace(/"/g, '""')}"`;
|
||||
}
|
||||
return str;
|
||||
};
|
||||
for (const userId of friends) {
|
||||
const { ref } = props.friends.get(userId);
|
||||
let discord = '';
|
||||
if (typeof ref === 'undefined') {
|
||||
continue;
|
||||
}
|
||||
const name = ref.displayName;
|
||||
if (ref.statusDescription) {
|
||||
const statusRegex = /(?:discord|dc|dis)(?: |=|:|˸|;)(.*)/gi.exec(ref.statusDescription);
|
||||
if (statusRegex) {
|
||||
discord = statusRegex[1];
|
||||
}
|
||||
}
|
||||
if (!discord && ref.bio) {
|
||||
const bioRegex = /(?:discord|dc|dis)(?: |=|:|˸|;)(.*)/gi.exec(ref.bio);
|
||||
if (bioRegex) {
|
||||
discord = bioRegex[1];
|
||||
}
|
||||
}
|
||||
if (!discord) {
|
||||
continue;
|
||||
}
|
||||
discord = discord.trim();
|
||||
lines.push(`${_(name)},${_(discord)}`);
|
||||
}
|
||||
discordNamesContent.value = lines.join('\n');
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:discordNamesDialogVisible', false);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
102
src/views/Profile/dialogs/EditInviteMessageDialog.vue
Normal file
102
src/views/Profile/dialogs/EditInviteMessageDialog.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible="editInviteMessageDialog.visible"
|
||||
:title="t('dialog.edit_invite_message.header')"
|
||||
width="400px"
|
||||
@close="closeDialog"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div style="font-size: 12px">
|
||||
<span>{{ t('dialog.edit_invite_message.description') }}</span>
|
||||
<el-input
|
||||
v-model="message"
|
||||
type="textarea"
|
||||
size="mini"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
:autosize="{ minRows: 2, maxRows: 5 }"
|
||||
placeholder=""
|
||||
style="margin-top: 10px"></el-input>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button type="small" @click="closeDialog">{{ $t('dialog.edit_invite_message.cancel') }}</el-button>
|
||||
<el-button type="primary" size="small" @click="saveEditInviteMessage">{{
|
||||
$t('dialog.edit_invite_message.save')
|
||||
}}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, inject, getCurrentInstance } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import { inviteMessagesRequest } from '../../../api';
|
||||
|
||||
const { t } = useI18n();
|
||||
const instance = getCurrentInstance();
|
||||
const $message = instance.proxy.$message;
|
||||
const API = inject('API');
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
|
||||
const props = defineProps({
|
||||
editInviteMessageDialog: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
visible: false,
|
||||
newMessage: ''
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
const message = ref('');
|
||||
|
||||
watch(
|
||||
() => props.editInviteMessageDialog,
|
||||
(newVal) => {
|
||||
if (newVal && newVal.visible) {
|
||||
message.value = newVal.newMessage;
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const emit = defineEmits(['update:editInviteMessageDialog']);
|
||||
|
||||
function saveEditInviteMessage() {
|
||||
const D = props.editInviteMessageDialog;
|
||||
D.visible = false;
|
||||
if (D.inviteMessage.message !== message.value) {
|
||||
const slot = D.inviteMessage.slot;
|
||||
const messageType = D.messageType;
|
||||
const params = {
|
||||
message: message.value
|
||||
};
|
||||
inviteMessagesRequest
|
||||
.editInviteMessage(params, messageType, slot)
|
||||
.catch((err) => {
|
||||
throw err;
|
||||
})
|
||||
.then((args) => {
|
||||
API.$emit(`INVITE:${messageType.toUpperCase()}`, args);
|
||||
if (args.json[slot].message === D.inviteMessage.message) {
|
||||
$message({
|
||||
message: "VRChat API didn't update message, try again",
|
||||
type: 'error'
|
||||
});
|
||||
throw new Error("VRChat API didn't update message, try again");
|
||||
} else {
|
||||
$message.success('Invite message updated');
|
||||
}
|
||||
return args;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:editInviteMessageDialog', { ...props.editInviteMessageDialog, visible: false });
|
||||
}
|
||||
</script>
|
||||
68
src/views/Settings/dialogs/AvatarProviderDialog.vue
Normal file
68
src/views/Settings/dialogs/AvatarProviderDialog.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:visible="isAvatarProviderDialogVisible"
|
||||
:title="t('dialog.avatar_database_provider.header')"
|
||||
width="600px"
|
||||
:before-close="beforeDialogClose"
|
||||
@close="closeDialog"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div>
|
||||
<el-input
|
||||
v-for="(provider, index) in avatarRemoteDatabaseProviderList"
|
||||
:key="index"
|
||||
v-model="avatarRemoteDatabaseProviderList[index]"
|
||||
:value="provider"
|
||||
size="small"
|
||||
style="margin-top: 5px"
|
||||
@change="saveAvatarProviderList">
|
||||
<el-button slot="append" icon="el-icon-delete" @click="removeAvatarProvider(provider)"></el-button>
|
||||
</el-input>
|
||||
|
||||
<el-button size="mini" style="margin-top: 5px" @click="avatarRemoteDatabaseProviderList.push('')">
|
||||
{{ t('dialog.avatar_database_provider.add_provider') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
const { t } = useI18n();
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
|
||||
defineProps({
|
||||
avatarRemoteDatabaseProviderList: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
isAvatarProviderDialogVisible: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits([
|
||||
'update:isAvatarProviderDialogVisible',
|
||||
'update:avatarRemoteDatabaseProviderList',
|
||||
'saveAvatarProviderList',
|
||||
'removeAvatarProvider'
|
||||
]);
|
||||
|
||||
function saveAvatarProviderList() {
|
||||
emit('saveAvatarProviderList');
|
||||
}
|
||||
|
||||
function removeAvatarProvider(provider) {
|
||||
emit('removeAvatarProvider', provider);
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:isAvatarProviderDialogVisible', false);
|
||||
}
|
||||
</script>
|
||||
65
src/views/Settings/dialogs/ChangelogDialog.vue
Normal file
65
src/views/Settings/dialogs/ChangelogDialog.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible="changeLogDialog.visible"
|
||||
:title="t('dialog.change_log.header')"
|
||||
width="800px"
|
||||
top="5vh"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp"
|
||||
@close="closeDialog">
|
||||
<div v-if="changeLogDialog.visible" class="changelog-dialog">
|
||||
<h2 v-text="changeLogDialog.buildName"></h2>
|
||||
<span>
|
||||
{{ t('dialog.change_log.description') }}
|
||||
<a class="x-link" @click="openExternalLink('https://www.patreon.com/Natsumi_VRCX')">Patreon</a>,
|
||||
<a class="x-link" @click="openExternalLink('https://ko-fi.com/natsumi_sama')">Ko-fi</a>.
|
||||
</span>
|
||||
<vue-markdown
|
||||
:source="changeLogDialog.changeLog"
|
||||
:linkify="false"
|
||||
style="height: 62vh; overflow-y: auto; margin-top: 10px"></vue-markdown>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button type="small" @click="openExternalLink('https://github.com/vrcx-team/VRCX/releases')">
|
||||
{{ t('dialog.change_log.github') }}
|
||||
</el-button>
|
||||
<el-button type="small" @click="openExternalLink('https://patreon.com/Natsumi_VRCX')">
|
||||
{{ t('dialog.change_log.donate') }}
|
||||
</el-button>
|
||||
<el-button type="small" @click="closeDialog">
|
||||
{{ t('dialog.change_log.close') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
|
||||
const { t } = useI18n();
|
||||
const openExternalLink = inject('openExternalLink');
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
|
||||
const props = defineProps({
|
||||
changeLogDialog: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
const emit = defineEmits(['update:changeLogDialog']);
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:changeLogDialog', { ...props.changeLogDialog, visible: false });
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.changelog-dialog img {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
150
src/views/Settings/dialogs/FeedFiltersDialog.vue
Normal file
150
src/views/Settings/dialogs/FeedFiltersDialog.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:before-close="beforeDialogClose"
|
||||
:visible="!!feedFiltersDialogMode"
|
||||
:title="dialogTitle"
|
||||
width="550px"
|
||||
top="5vh"
|
||||
destroy-on-close
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp"
|
||||
@close="handleDialogClose">
|
||||
<div class="toggle-list" style="height: 75vh; overflow-y: auto">
|
||||
<div v-for="setting in currentOptions" :key="setting.key" class="toggle-item">
|
||||
<span class="toggle-name"
|
||||
>{{ setting.name
|
||||
}}<el-tooltip
|
||||
v-if="setting.tooltip"
|
||||
placement="top"
|
||||
style="margin-left: 5px"
|
||||
:content="setting.tooltip">
|
||||
<i :class="setting.tooltipIcon || 'el-icon-info'"></i> </el-tooltip
|
||||
></span>
|
||||
|
||||
<el-radio-group
|
||||
v-model="currentSharedFeedFilters[setting.key]"
|
||||
size="mini"
|
||||
@change="saveSharedFeedFilters">
|
||||
<el-radio-button v-for="option in setting.options" :key="option.label" :label="option.label">
|
||||
{{ t(option.textKey) }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<template v-if="props.photonLoggingEnabled">
|
||||
<br />
|
||||
<div class="toggle-item">
|
||||
<span class="toggle-name">Photon Event Logging</span>
|
||||
</div>
|
||||
<div v-for="setting in photonFeedFiltersOptions" :key="setting.key" class="toggle-item">
|
||||
<span class="toggle-name">{{ setting.name }}</span>
|
||||
<el-radio-group
|
||||
v-model="currentSharedFeedFilters[setting.key]"
|
||||
size="mini"
|
||||
@change="saveSharedFeedFilters">
|
||||
<el-radio-button v-for="option in setting.options" :key="option.label" :label="option.label">
|
||||
{{ t(option.textKey) }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button size="small" @click="currentResetFunction">{{
|
||||
t('dialog.shared_feed_filters.reset')
|
||||
}}</el-button>
|
||||
<el-button size="small" type="primary" style="margin-left: 10px" @click="handleDialogClose">{{
|
||||
t('dialog.shared_feed_filters.close')
|
||||
}}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, inject } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import configRepository from '../../../service/config';
|
||||
import { feedFiltersOptions } from '../../../composables/settings/constants/feedFiltersOptions';
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const { notyFeedFiltersOptions, wristFeedFiltersOptions, photonFeedFiltersOptions } = feedFiltersOptions();
|
||||
|
||||
const props = defineProps({
|
||||
feedFiltersDialogMode: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: ''
|
||||
},
|
||||
photonLoggingEnabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
sharedFeedFilters: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
noty: {},
|
||||
wrist: {}
|
||||
})
|
||||
},
|
||||
sharedFeedFiltersDefaults: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
noty: {},
|
||||
wrist: {}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
const currentOptions = computed(() => {
|
||||
return props.feedFiltersDialogMode === 'noty' ? notyFeedFiltersOptions : wristFeedFiltersOptions;
|
||||
});
|
||||
|
||||
const currentSharedFeedFilters = computed(() => {
|
||||
return props.feedFiltersDialogMode === 'noty'
|
||||
? props.sharedFeedFilters['noty']
|
||||
: props.sharedFeedFilters['wrist'];
|
||||
});
|
||||
|
||||
const dialogTitle = computed(() => {
|
||||
const key =
|
||||
props.feedFiltersDialogMode === 'noty'
|
||||
? 'dialog.shared_feed_filters.notification'
|
||||
: 'dialog.shared_feed_filters.wrist';
|
||||
return t(key);
|
||||
});
|
||||
|
||||
const currentResetFunction = computed(() => {
|
||||
return props.feedFiltersDialogMode === 'noty' ? resetNotyFeedFilters : resetWristFeedFilters;
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:feedFiltersDialogMode', 'updateSharedFeed']);
|
||||
|
||||
function saveSharedFeedFilters() {
|
||||
configRepository.setString('sharedFeedFilters', JSON.stringify(props.sharedFeedFilters));
|
||||
emit('updateSharedFeed', true);
|
||||
}
|
||||
|
||||
function resetNotyFeedFilters() {
|
||||
props.sharedFeedFilters.noty = {
|
||||
...props.sharedFeedFiltersDefaults.noty
|
||||
};
|
||||
saveSharedFeedFilters();
|
||||
}
|
||||
|
||||
async function resetWristFeedFilters() {
|
||||
props.sharedFeedFilters.wrist = {
|
||||
...props.sharedFeedFiltersDefaults.wrist
|
||||
};
|
||||
saveSharedFeedFilters();
|
||||
}
|
||||
|
||||
function handleDialogClose() {
|
||||
emit('update:feedFiltersDialogMode', '');
|
||||
}
|
||||
</script>
|
||||
129
src/views/Settings/dialogs/LaunchOptionsDialog.vue
Normal file
129
src/views/Settings/dialogs/LaunchOptionsDialog.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible="isLaunchOptionsDialogVisible"
|
||||
:title="t('dialog.launch_options.header')"
|
||||
width="600px"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp"
|
||||
@close="closeDialog">
|
||||
<div style="font-size: 12px">
|
||||
{{ t('dialog.launch_options.description') }} <br />
|
||||
{{ t('dialog.launch_options.example') }} <el-tag size="mini">--fps=144</el-tag>
|
||||
</div>
|
||||
|
||||
<el-input
|
||||
v-model="launchOptionsDialog.launchArguments"
|
||||
type="textarea"
|
||||
size="mini"
|
||||
show-word-limit
|
||||
:autosize="{ minRows: 2, maxRows: 5 }"
|
||||
placeholder=""
|
||||
style="margin-top: 10px">
|
||||
</el-input>
|
||||
|
||||
<div style="font-size: 12px; margin-top: 10px">
|
||||
{{ t('dialog.launch_options.path_override') }}
|
||||
</div>
|
||||
|
||||
<el-input
|
||||
v-model="launchOptionsDialog.vrcLaunchPathOverride"
|
||||
type="textarea"
|
||||
placeholder="C:\\Program Files (x86)\\Steam\\steamapps\\common\\VRChat"
|
||||
:rows="1"
|
||||
style="display: block; margin-top: 10px">
|
||||
</el-input>
|
||||
|
||||
<template #footer>
|
||||
<div style="display: flex">
|
||||
<el-button size="small" @click="openExternalLink('https://docs.vrchat.com/docs/launch-options')">
|
||||
{{ t('dialog.launch_options.vrchat_docs') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
@click="openExternalLink('https://docs.unity3d.com/Manual/CommandLineArguments.html')">
|
||||
{{ t('dialog.launch_options.unity_manual') }}
|
||||
</el-button>
|
||||
<el-button type="primary" size="small" style="margin-left: auto" @click="updateLaunchOptions">
|
||||
{{ t('dialog.launch_options.save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, inject, getCurrentInstance } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import configRepository from '../../../service/config';
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
const openExternalLink = inject('openExternalLink');
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
const $message = instance.proxy.$message;
|
||||
|
||||
defineProps({
|
||||
isLaunchOptionsDialogVisible: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:isLaunchOptionsDialogVisible']);
|
||||
|
||||
const launchOptionsDialog = ref({
|
||||
launchArguments: '',
|
||||
vrcLaunchPathOverride: ''
|
||||
});
|
||||
|
||||
function init() {
|
||||
configRepository
|
||||
.getString('launchArguments')
|
||||
.then((launchArguments) => (launchOptionsDialog.value.launchArguments = launchArguments));
|
||||
|
||||
configRepository.getString('vrcLaunchPathOverride').then((vrcLaunchPathOverride) => {
|
||||
if (vrcLaunchPathOverride === null || vrcLaunchPathOverride === 'null') {
|
||||
launchOptionsDialog.value.vrcLaunchPathOverride = '';
|
||||
configRepository.setString('vrcLaunchPathOverride', '');
|
||||
} else {
|
||||
launchOptionsDialog.value.vrcLaunchPathOverride = vrcLaunchPathOverride;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// created
|
||||
init();
|
||||
|
||||
function updateLaunchOptions() {
|
||||
const D = launchOptionsDialog.value;
|
||||
D.launchArguments = String(D.launchArguments).replace(/\s+/g, ' ').trim();
|
||||
configRepository.setString('launchArguments', D.launchArguments);
|
||||
if (
|
||||
D.vrcLaunchPathOverride &&
|
||||
D.vrcLaunchPathOverride.endsWith('.exe') &&
|
||||
!D.vrcLaunchPathOverride.endsWith('launch.exe')
|
||||
) {
|
||||
$message({
|
||||
message: 'Invalid path, you must enter VRChat folder or launch.exe',
|
||||
type: 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
configRepository.setString('vrcLaunchPathOverride', D.vrcLaunchPathOverride);
|
||||
$message({
|
||||
message: 'Updated launch options',
|
||||
type: 'success'
|
||||
});
|
||||
closeDialog();
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:isLaunchOptionsDialogVisible');
|
||||
}
|
||||
</script>
|
||||
210
src/views/Settings/dialogs/NoteExportDialog.vue
Normal file
210
src/views/Settings/dialogs/NoteExportDialog.vue
Normal file
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible="isNoteExportDialogVisible"
|
||||
:title="t('dialog.note_export.header')"
|
||||
width="1000px"
|
||||
@close="closeDialog"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div style="font-size: 12px">
|
||||
{{ t('dialog.note_export.description1') }} <br />
|
||||
{{ t('dialog.note_export.description2') }} <br />
|
||||
{{ t('dialog.note_export.description3') }} <br />
|
||||
{{ t('dialog.note_export.description4') }} <br />
|
||||
{{ t('dialog.note_export.description5') }} <br />
|
||||
{{ t('dialog.note_export.description6') }} <br />
|
||||
{{ t('dialog.note_export.description7') }} <br />
|
||||
{{ t('dialog.note_export.description8') }} <br />
|
||||
</div>
|
||||
|
||||
<el-button size="small" :disabled="loading" style="margin-top: 10px" @click="updateNoteExportDialog">
|
||||
{{ t('dialog.note_export.refresh') }}
|
||||
</el-button>
|
||||
<el-button size="small" :disabled="loading" style="margin-top: 10px" @click="exportNoteExport">
|
||||
{{ t('dialog.note_export.export') }}
|
||||
</el-button>
|
||||
<el-button v-if="loading" size="small" style="margin-top: 10px" @click="cancelNoteExport">
|
||||
{{ t('dialog.note_export.cancel') }}
|
||||
</el-button>
|
||||
<span v-if="loading" style="margin: 10px">
|
||||
<i class="el-icon-loading" style="margin-right: 5px"></i>
|
||||
{{ t('dialog.note_export.progress') }} {{ progress }}/{{ progressTotal }}
|
||||
</span>
|
||||
|
||||
<template v-if="errors">
|
||||
<el-button size="small" @click="errors = ''">
|
||||
{{ t('dialog.note_export.clear_errors') }}
|
||||
</el-button>
|
||||
<h2 style="font-weight: bold; margin: 0">
|
||||
{{ t('dialog.note_export.errors') }}
|
||||
</h2>
|
||||
<pre style="white-space: pre-wrap; font-size: 12px" v-text="errors"></pre>
|
||||
</template>
|
||||
|
||||
<data-tables v-loading="loading" v-bind="noteExportTable" style="margin-top: 10px">
|
||||
<el-table-column :label="t('table.import.image')" width="70" prop="currentAvatarThumbnailImageUrl">
|
||||
<template slot-scope="scope">
|
||||
<el-popover placement="right" height="500px" trigger="hover">
|
||||
<img slot="reference" v-lazy="userImage(scope.row.ref)" class="friends-list-avatar" />
|
||||
<img
|
||||
v-lazy="userImageFull(scope.row.ref)"
|
||||
class="friends-list-avatar"
|
||||
style="height: 500px; cursor: pointer"
|
||||
@click="showFullscreenImageDialog(userImageFull(scope.row.ref))" />
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('table.import.name')" width="170" prop="name">
|
||||
<template slot-scope="scope">
|
||||
<span class="x-link" @click="showUserDialog(scope.row.id)" v-text="scope.row.name"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('table.import.note')" prop="memo">
|
||||
<template slot-scope="scope">
|
||||
<el-input
|
||||
v-model="scope.row.memo"
|
||||
type="textarea"
|
||||
maxlength="256"
|
||||
show-word-limit
|
||||
:rows="2"
|
||||
:autosize="{ minRows: 1, maxRows: 10 }"
|
||||
size="mini"
|
||||
resize="none"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('table.import.skip_export')" width="90" align="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-close"
|
||||
size="mini"
|
||||
@click="removeFromNoteExportTable(scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</data-tables>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, inject } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import utils from '../../../classes/utils';
|
||||
import * as workerTimers from 'worker-timers';
|
||||
import { miscRequest } from '../../../api';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
const userImage = inject('userImage');
|
||||
const userImageFull = inject('userImageFull');
|
||||
const showUserDialog = inject('showUserDialog');
|
||||
const showFullscreenImageDialog = inject('showFullscreenImageDialog');
|
||||
|
||||
const props = defineProps({
|
||||
isNoteExportDialogVisible: {
|
||||
type: Boolean
|
||||
},
|
||||
friends: {
|
||||
type: Map,
|
||||
default: () => new Map()
|
||||
}
|
||||
});
|
||||
|
||||
const noteExportTable = ref({
|
||||
data: [],
|
||||
tableProps: {
|
||||
stripe: true,
|
||||
size: 'mini'
|
||||
},
|
||||
layout: 'table'
|
||||
});
|
||||
|
||||
const progress = ref(0);
|
||||
const progressTotal = ref(0);
|
||||
const loading = ref(false);
|
||||
const errors = ref('');
|
||||
|
||||
watch(
|
||||
() => props.isNoteExportDialogVisible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
initData();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function initData() {
|
||||
noteExportTable.value.data = [];
|
||||
progress.value = 0;
|
||||
progressTotal.value = 0;
|
||||
loading.value = false;
|
||||
errors.value = '';
|
||||
}
|
||||
|
||||
const emit = defineEmits(['update:isNoteExportDialogVisible']);
|
||||
|
||||
function updateNoteExportDialog() {
|
||||
const data = [];
|
||||
props.friends.forEach((ctx) => {
|
||||
const newMemo = ctx.memo.replace(/[\r\n]/g, ' ');
|
||||
if (ctx.memo && ctx.ref && ctx.ref.note !== newMemo.slice(0, 256)) {
|
||||
data.push({
|
||||
id: ctx.id,
|
||||
name: ctx.name,
|
||||
memo: newMemo,
|
||||
ref: ctx.ref
|
||||
});
|
||||
}
|
||||
});
|
||||
noteExportTable.value.data = data;
|
||||
}
|
||||
|
||||
async function exportNoteExport() {
|
||||
let ctx;
|
||||
|
||||
loading.value = true;
|
||||
const data = [...noteExportTable.value.data].reverse();
|
||||
progressTotal.value = data.length;
|
||||
try {
|
||||
for (let i = data.length - 1; i >= 0; i--) {
|
||||
if (props.isNoteExportDialogVisible && loading.value) {
|
||||
ctx = data[i];
|
||||
await miscRequest.saveNote({
|
||||
targetUserId: ctx.id,
|
||||
note: ctx.memo.slice(0, 256)
|
||||
});
|
||||
utils.removeFromArray(noteExportTable.value.data, ctx);
|
||||
progress.value++;
|
||||
await new Promise((resolve) => {
|
||||
workerTimers.setTimeout(resolve, 5000);
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
errors.value = `Name: ${ctx?.name}\n${err}\n\n`;
|
||||
} finally {
|
||||
progress.value = 0;
|
||||
progressTotal.value = 0;
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function cancelNoteExport() {
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
function removeFromNoteExportTable(ref) {
|
||||
utils.removeFromArray(noteExportTable.value.data, ref);
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:isNoteExportDialogVisible', false);
|
||||
}
|
||||
</script>
|
||||
80
src/views/Settings/dialogs/NotificationPositionDialog.vue
Normal file
80
src/views/Settings/dialogs/NotificationPositionDialog.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:visible="isNotificationPositionDialogVisible"
|
||||
:title="t('dialog.notification_position.header')"
|
||||
width="400px"
|
||||
:before-close="beforeDialogClose"
|
||||
@close="closeDialog"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div style="font-size: 12px">
|
||||
{{ t('dialog.notification_position.description') }}
|
||||
</div>
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 300 200"
|
||||
style="margin-top: 15px"
|
||||
xml:space="preserve"
|
||||
class="notification-position">
|
||||
<path
|
||||
style="fill: black"
|
||||
d="M291.89,5A3.11,3.11,0,0,1,295,8.11V160.64a3.11,3.11,0,0,1-3.11,3.11H8.11A3.11,3.11,0,0,1,5,160.64V8.11A3.11,3.11,0,0,1,8.11,5H291.89m0-5H8.11A8.11,8.11,0,0,0,0,8.11V160.64a8.11,8.11,0,0,0,8.11,8.11H291.89a8.11,8.11,0,0,0,8.11-8.11V8.11A8.11,8.11,0,0,0,291.89,0Z" />
|
||||
<rect style="fill: #c4c4c4" x="5" y="5" width="290" height="158.75" rx="2.5" />
|
||||
</svg>
|
||||
<el-radio-group :value="notificationPosition" size="mini" @input="changeNotificationPosition">
|
||||
<el-radio label="topLeft" style="margin: 0; position: absolute; left: 35px; top: 120px"></el-radio>
|
||||
<el-radio label="top" style="margin: 0; position: absolute; left: 195px; top: 120px"></el-radio>
|
||||
<el-radio label="topRight" style="margin: 0; position: absolute; right: 25px; top: 120px"></el-radio>
|
||||
<el-radio label="centerLeft" style="margin: 0; position: absolute; left: 35px; top: 200px"></el-radio>
|
||||
<el-radio label="center" style="margin: 0; position: absolute; left: 195px; top: 200px"></el-radio>
|
||||
<el-radio label="centerRight" style="margin: 0; position: absolute; right: 25px; top: 200px"></el-radio>
|
||||
<el-radio label="bottomLeft" style="margin: 0; position: absolute; left: 35px; top: 280px"></el-radio>
|
||||
<el-radio label="bottom" style="margin: 0; position: absolute; left: 195px; top: 280px"></el-radio>
|
||||
<el-radio label="bottomRight" style="margin: 0; position: absolute; right: 25px; top: 280px"></el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
<template #footer>
|
||||
<div style="display: flex">
|
||||
<el-button type="primary" size="small" style="margin-left: auto" @click="closeDialog">
|
||||
{{ t('dialog.notification_position.ok') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
const { t } = useI18n();
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
|
||||
defineProps({
|
||||
isNotificationPositionDialogVisible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
notificationPosition: {
|
||||
type: String,
|
||||
default: 'topRight'
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:isNotificationPositionDialogVisible', 'changeNotificationPosition']);
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:isNotificationPositionDialogVisible', false);
|
||||
}
|
||||
|
||||
function changeNotificationPosition(value) {
|
||||
emit('changeNotificationPosition', value);
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible="ossDialog"
|
||||
:title="t('dialog.open_source.header')"
|
||||
width="650px"
|
||||
@close="closeDialog"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div v-once style="height: 350px; overflow: hidden scroll; word-break: break-all">
|
||||
<div>
|
||||
<span>{{ t('dialog.open_source.description') }} }}</span>
|
||||
</div>
|
||||
|
||||
<div v-for="lib in openSourceSoftwareLicenses" :key="lib.name" style="margin-top: 15px">
|
||||
<p style="font-weight: bold">{{ lib.name }}</p>
|
||||
<pre style="font-size: 12px; white-space: pre-line">{{ lib.licenseText }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import { openSourceSoftwareLicenses } from '../../../composables/settings/constants/openSourceSoftwareLicenses';
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
defineProps({
|
||||
ossDialog: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:ossDialog']);
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:ossDialog', false);
|
||||
}
|
||||
</script>
|
||||
59
src/views/Settings/dialogs/PrimaryPasswordDialog.vue
Normal file
59
src/views/Settings/dialogs/PrimaryPasswordDialog.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:visible.sync="enablePrimaryPasswordDialog.visible"
|
||||
:before-close="enablePrimaryPasswordDialog.beforeClose"
|
||||
:close-on-click-modal="false"
|
||||
:title="t('dialog.primary_password.header')"
|
||||
width="400px">
|
||||
<el-input
|
||||
v-model="enablePrimaryPasswordDialog.password"
|
||||
:placeholder="t('dialog.primary_password.password_placeholder')"
|
||||
type="password"
|
||||
size="mini"
|
||||
maxlength="32"
|
||||
show-password
|
||||
autofocus>
|
||||
</el-input>
|
||||
<el-input
|
||||
v-model="enablePrimaryPasswordDialog.rePassword"
|
||||
:placeholder="t('dialog.primary_password.re_input_placeholder')"
|
||||
type="password"
|
||||
style="margin-top: 5px"
|
||||
size="mini"
|
||||
maxlength="32"
|
||||
show-password>
|
||||
</el-input>
|
||||
<template #footer>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="
|
||||
enablePrimaryPasswordDialog.password.length === 0 ||
|
||||
enablePrimaryPasswordDialog.password !== enablePrimaryPasswordDialog.rePassword
|
||||
"
|
||||
@click="setPrimaryPassword">
|
||||
{{ t('dialog.primary_password.ok') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
enablePrimaryPasswordDialog: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['setPrimaryPassword']);
|
||||
|
||||
function setPrimaryPassword() {
|
||||
emit('setPrimaryPassword', props.enablePrimaryPasswordDialog.password);
|
||||
props.enablePrimaryPasswordDialog.visible = false;
|
||||
}
|
||||
</script>
|
||||
305
src/views/Settings/dialogs/RegistryBackupDialog.vue
Normal file
305
src/views/Settings/dialogs/RegistryBackupDialog.vue
Normal file
@@ -0,0 +1,305 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible="isRegistryBackupDialogVisible"
|
||||
:title="t('dialog.registry_backup.header')"
|
||||
width="600px"
|
||||
@close="closeDialog"
|
||||
@closed="clearVrcRegistryDialog"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div style="margin-top: 10px">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; font-size: 12px">
|
||||
<span class="name" style="margin-right: 24px">{{ t('dialog.registry_backup.auto_backup') }}</span>
|
||||
<el-switch v-model="vrcRegistryAutoBackup" @change="saveVrcRegistryAutoBackup"></el-switch>
|
||||
</div>
|
||||
<data-tables v-bind="registryBackupTable" style="margin-top: 10px">
|
||||
<el-table-column :label="t('dialog.registry_backup.name')" prop="name"></el-table-column>
|
||||
<el-table-column :label="t('dialog.registry_backup.date')" prop="date">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.date | formatDate('long') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('dialog.registry_backup.action')" width="90" align="right">
|
||||
<template #default="scope">
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
:content="t('dialog.registry_backup.restore')"
|
||||
:disabled="hideTooltips">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-upload2"
|
||||
size="mini"
|
||||
@click="restoreVrcRegistryBackup(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
:content="t('dialog.registry_backup.save_to_file')"
|
||||
:disabled="hideTooltips">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="saveVrcRegistryBackupToFile(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
:content="t('dialog.registry_backup.delete')"
|
||||
:disabled="hideTooltips">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
@click="deleteVrcRegistryBackup(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</data-tables>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 10px">
|
||||
<el-button type="danger" size="small" @click="deleteVrcRegistry">{{
|
||||
t('dialog.registry_backup.reset')
|
||||
}}</el-button>
|
||||
<div>
|
||||
<el-button size="small" @click="promptVrcRegistryBackupName">{{
|
||||
t('dialog.registry_backup.backup')
|
||||
}}</el-button>
|
||||
<el-button size="small" @click="restoreVrcRegistryFromFile">{{
|
||||
t('dialog.registry_backup.restore_from_file')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getCurrentInstance, inject, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import configRepository from '../../../service/config';
|
||||
import utils from '../../../classes/utils';
|
||||
const { t } = useI18n();
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
const { $confirm, $message, $prompt } = instance.proxy;
|
||||
|
||||
const props = defineProps({
|
||||
isRegistryBackupDialogVisible: {
|
||||
type: Boolean
|
||||
},
|
||||
hideTooltips: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
backupVrcRegistry: {
|
||||
type: Function
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:isRegistryBackupDialogVisible']);
|
||||
|
||||
const registryBackupTable = ref({
|
||||
data: [],
|
||||
tableProps: {
|
||||
stripe: true,
|
||||
size: 'mini',
|
||||
defaultSort: {
|
||||
prop: 'date',
|
||||
order: 'descending'
|
||||
}
|
||||
},
|
||||
layout: 'table'
|
||||
});
|
||||
|
||||
const vrcRegistryAutoBackup = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.isRegistryBackupDialogVisible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
updateRegistryBackupDialog();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
setVrcRegistryAutoBackup();
|
||||
|
||||
function setVrcRegistryAutoBackup() {
|
||||
configRepository.getBool('VRCX_vrcRegistryAutoBackup', true).then((value) => {
|
||||
vrcRegistryAutoBackup.value = value;
|
||||
});
|
||||
}
|
||||
|
||||
async function updateRegistryBackupDialog() {
|
||||
let backupsJson = await configRepository.getString('VRCX_VRChatRegistryBackups');
|
||||
registryBackupTable.value.data = JSON.parse(backupsJson || '[]');
|
||||
}
|
||||
|
||||
async function saveVrcRegistryAutoBackup() {
|
||||
await configRepository.setBool('VRCX_vrcRegistryAutoBackup', vrcRegistryAutoBackup.value);
|
||||
}
|
||||
|
||||
function restoreVrcRegistryBackup(row) {
|
||||
$confirm('Continue? Restore Backup', 'Confirm', {
|
||||
confirmButtonText: 'Confirm',
|
||||
cancelButtonText: 'Cancel',
|
||||
type: 'warning',
|
||||
callback: (action) => {
|
||||
if (action !== 'confirm') {
|
||||
return;
|
||||
}
|
||||
const data = JSON.stringify(row.data);
|
||||
AppApi.SetVRChatRegistry(data)
|
||||
.then(() => {
|
||||
$message({
|
||||
message: 'VRC registry settings restored',
|
||||
type: 'success'
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
$message({
|
||||
message: `Failed to restore VRC registry settings, check console for full error: ${e}`,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function saveVrcRegistryBackupToFile(row) {
|
||||
utils.downloadAndSaveJson(row.name, row.data);
|
||||
}
|
||||
|
||||
async function deleteVrcRegistryBackup(row) {
|
||||
const backups = registryBackupTable.value.data;
|
||||
utils.removeFromArray(backups, row);
|
||||
await configRepository.setString('VRCX_VRChatRegistryBackups', JSON.stringify(backups));
|
||||
await updateRegistryBackupDialog();
|
||||
}
|
||||
|
||||
function deleteVrcRegistry() {
|
||||
$confirm('Continue? Delete VRC Registry Settings', 'Confirm', {
|
||||
confirmButtonText: 'Confirm',
|
||||
cancelButtonText: 'Cancel',
|
||||
type: 'warning',
|
||||
callback: (action) => {
|
||||
if (action !== 'confirm') {
|
||||
return;
|
||||
}
|
||||
AppApi.DeleteVRChatRegistryFolder().then(() => {
|
||||
$message({
|
||||
message: 'VRC registry settings deleted',
|
||||
type: 'success'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function handleBackupVrcRegistry(name) {
|
||||
await props.backupVrcRegistry(name);
|
||||
await updateRegistryBackupDialog();
|
||||
}
|
||||
|
||||
async function promptVrcRegistryBackupName() {
|
||||
const name = await $prompt('Enter a name for the backup', 'Backup Name', {
|
||||
confirmButtonText: 'Confirm',
|
||||
cancelButtonText: 'Cancel',
|
||||
inputPattern: /\S+/,
|
||||
inputErrorMessage: 'Name is required',
|
||||
inputValue: 'Backup'
|
||||
});
|
||||
if (name.action === 'confirm') {
|
||||
await handleBackupVrcRegistry(name.value);
|
||||
}
|
||||
}
|
||||
|
||||
async function openJsonFileSelectorDialogElectron() {
|
||||
return new Promise((resolve) => {
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.accept = '.json';
|
||||
fileInput.style.display = 'none';
|
||||
document.body.appendChild(fileInput);
|
||||
|
||||
fileInput.onchange = function (event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
fileInput.remove();
|
||||
resolve(reader.result);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
} else {
|
||||
fileInput.remove();
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
|
||||
fileInput.click();
|
||||
});
|
||||
}
|
||||
|
||||
async function restoreVrcRegistryFromFile() {
|
||||
const filePath = await AppApi.OpenFileSelectorDialog(null, '.json', 'JSON Files (*.json)|*.json');
|
||||
if (WINDOWS) {
|
||||
if (filePath === '') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let json;
|
||||
if (LINUX) {
|
||||
json = await openJsonFileSelectorDialogElectron();
|
||||
} else {
|
||||
json = await AppApi.ReadVrcRegJsonFile(filePath);
|
||||
}
|
||||
|
||||
try {
|
||||
const data = JSON.parse(json);
|
||||
if (!data || typeof data !== 'object') {
|
||||
throw new Error('Invalid JSON');
|
||||
}
|
||||
// quick check to make sure it's a valid registry backup
|
||||
for (const key in data) {
|
||||
const value = data[key];
|
||||
if (typeof value !== 'object' || typeof value.type !== 'number' || typeof value.data === 'undefined') {
|
||||
throw new Error('Invalid JSON');
|
||||
}
|
||||
}
|
||||
AppApi.SetVRChatRegistry(json)
|
||||
.then(() => {
|
||||
$message({
|
||||
message: 'VRC registry settings restored',
|
||||
type: 'success'
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
$message({
|
||||
message: `Failed to restore VRC registry settings, check console for full error: ${e}`,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
$message({
|
||||
message: 'Invalid JSON',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function clearVrcRegistryDialog() {
|
||||
registryBackupTable.value.data = [];
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:isRegistryBackupDialogVisible', false);
|
||||
}
|
||||
</script>
|
||||
517
src/views/Settings/dialogs/ScreenshotMetadataDialog.vue
Normal file
517
src/views/Settings/dialogs/ScreenshotMetadataDialog.vue
Normal file
@@ -0,0 +1,517 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible.sync="screenshotMetadataDialog.visible"
|
||||
:title="t('dialog.screenshot_metadata.header')"
|
||||
width="1050px"
|
||||
top="10vh"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div
|
||||
v-if="screenshotMetadataDialog.visible"
|
||||
v-loading="screenshotMetadataDialog.loading"
|
||||
style="-webkit-app-region: drag"
|
||||
@dragover.prevent
|
||||
@dragenter.prevent
|
||||
@drop="handleDrop">
|
||||
<span style="margin-left: 5px; color: #909399; font-family: monospace">{{
|
||||
t('dialog.screenshot_metadata.drag')
|
||||
}}</span>
|
||||
<br />
|
||||
<br />
|
||||
<el-button size="small" icon="el-icon-folder-opened" @click="getAndDisplayScreenshotFromFile">{{
|
||||
t('dialog.screenshot_metadata.browse')
|
||||
}}</el-button>
|
||||
<el-button size="small" icon="el-icon-picture-outline" @click="getAndDisplayLastScreenshot">{{
|
||||
t('dialog.screenshot_metadata.last_screenshot')
|
||||
}}</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
icon="el-icon-copy-document"
|
||||
@click="copyImageToClipboard(screenshotMetadataDialog.metadata.filePath)"
|
||||
>{{ t('dialog.screenshot_metadata.copy_image') }}</el-button
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
icon="el-icon-folder"
|
||||
@click="openImageFolder(screenshotMetadataDialog.metadata.filePath)"
|
||||
>{{ t('dialog.screenshot_metadata.open_folder') }}</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="API.currentUser.$isVRCPlus && screenshotMetadataDialog.metadata.filePath"
|
||||
size="small"
|
||||
icon="el-icon-upload2"
|
||||
@click="uploadScreenshotToGallery"
|
||||
>{{ t('dialog.screenshot_metadata.upload') }}</el-button
|
||||
>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<!-- Search bar input -->
|
||||
<el-input
|
||||
v-model="screenshotMetadataDialog.search"
|
||||
size="small"
|
||||
placeholder="Search"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@input="screenshotMetadataSearch" />
|
||||
<!-- Search type dropdown -->
|
||||
<el-select
|
||||
v-model="screenshotMetadataDialog.searchType"
|
||||
size="small"
|
||||
placeholder="Search Type"
|
||||
style="width: 150px; margin-left: 10px"
|
||||
@change="screenshotMetadataSearch">
|
||||
<el-option
|
||||
v-for="type in screenshotMetadataDialog.searchTypes"
|
||||
:key="type"
|
||||
:label="type"
|
||||
:value="type" />
|
||||
</el-select>
|
||||
<!-- Search index/total label -->
|
||||
<template v-if="screenshotMetadataDialog.searchIndex !== null">
|
||||
<span style="white-space: pre-wrap; font-size: 12px; margin-left: 10px">{{
|
||||
screenshotMetadataDialog.searchIndex + 1 + '/' + screenshotMetadataDialog.searchResults.length
|
||||
}}</span>
|
||||
</template>
|
||||
<br />
|
||||
<br />
|
||||
<span v-text="screenshotMetadataDialog.metadata.fileName"></span>
|
||||
<br />
|
||||
<template v-if="screenshotMetadataDialog.metadata.note">
|
||||
<span v-text="screenshotMetadataDialog.metadata.note"></span>
|
||||
<br />
|
||||
</template>
|
||||
<span v-if="screenshotMetadataDialog.metadata.dateTime" style="margin-right: 5px">{{
|
||||
screenshotMetadataDialog.metadata.dateTime | formatDate('long')
|
||||
}}</span>
|
||||
<span
|
||||
v-if="screenshotMetadataDialog.metadata.fileResolution"
|
||||
style="margin-right: 5px"
|
||||
v-text="screenshotMetadataDialog.metadata.fileResolution"></span>
|
||||
<el-tag v-if="screenshotMetadataDialog.metadata.fileSize" type="info" effect="plain" size="mini">{{
|
||||
screenshotMetadataDialog.metadata.fileSize
|
||||
}}</el-tag>
|
||||
<br />
|
||||
<location
|
||||
v-if="screenshotMetadataDialog.metadata.world"
|
||||
:location="screenshotMetadataDialog.metadata.world.instanceId"
|
||||
:hint="screenshotMetadataDialog.metadata.world.name" />
|
||||
<br />
|
||||
<display-name
|
||||
v-if="screenshotMetadataDialog.metadata.author"
|
||||
:userid="screenshotMetadataDialog.metadata.author.id"
|
||||
:hint="screenshotMetadataDialog.metadata.author.displayName"
|
||||
style="color: #909399; font-family: monospace" />
|
||||
<br />
|
||||
<el-carousel
|
||||
ref="screenshotMetadataCarouselRef"
|
||||
:interval="0"
|
||||
:initial-index="1"
|
||||
indicator-position="none"
|
||||
arrow="always"
|
||||
height="600px"
|
||||
style="margin-top: 10px"
|
||||
@change="screenshotMetadataCarouselChange">
|
||||
<el-carousel-item>
|
||||
<span placement="top" width="700px" trigger="click">
|
||||
<img
|
||||
slot="reference"
|
||||
class="x-link"
|
||||
:src="screenshotMetadataDialog.metadata.previousFilePath"
|
||||
style="width: 100%; height: 100%; object-fit: contain" />
|
||||
</span>
|
||||
</el-carousel-item>
|
||||
<el-carousel-item>
|
||||
<span
|
||||
placement="top"
|
||||
width="700px"
|
||||
trigger="click"
|
||||
@click="showFullscreenImageDialog(screenshotMetadataDialog.metadata.filePath)">
|
||||
<img
|
||||
slot="reference"
|
||||
class="x-link"
|
||||
:src="screenshotMetadataDialog.metadata.filePath"
|
||||
style="width: 100%; height: 100%; object-fit: contain" />
|
||||
</span>
|
||||
</el-carousel-item>
|
||||
<el-carousel-item>
|
||||
<span placement="top" width="700px" trigger="click">
|
||||
<img
|
||||
slot="reference"
|
||||
class="x-link"
|
||||
:src="screenshotMetadataDialog.metadata.nextFilePath"
|
||||
style="width: 100%; height: 100%; object-fit: contain" />
|
||||
</span>
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
<br />
|
||||
<template v-if="screenshotMetadataDialog.metadata.error">
|
||||
<pre
|
||||
style="white-space: pre-wrap; font-size: 12px"
|
||||
v-text="screenshotMetadataDialog.metadata.error"></pre>
|
||||
<br />
|
||||
</template>
|
||||
<span v-for="user in screenshotMetadataDialog.metadata.players" :key="user.id" style="margin-top: 5px">
|
||||
<span class="x-link" @click="lookupUser(user)" v-text="user.displayName"></span>
|
||||
<span
|
||||
v-if="user.pos"
|
||||
style="margin-left: 5px; color: #909399; font-family: monospace"
|
||||
v-text="'(' + user.pos.x + ', ' + user.pos.y + ', ' + user.pos.z + ')'"></span>
|
||||
<br />
|
||||
<br />
|
||||
</span>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, inject, computed, getCurrentInstance, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import { vrcPlusImageRequest } from '../../../api';
|
||||
import Location from '../../../components/Location.vue';
|
||||
|
||||
const API = inject('API');
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
const showFullscreenImageDialog = inject('showFullscreenImageDialog');
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
const $message = instance.proxy.$message;
|
||||
|
||||
const props = defineProps({
|
||||
screenshotMetadataDialog: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
currentlyDroppingFile: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
fullscreenImageDialog: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['lookupUser']);
|
||||
|
||||
watch(
|
||||
() => props.screenshotMetadataDialog.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
if (!props.screenshotMetadataDialog.metadata.filePath) {
|
||||
getAndDisplayLastScreenshot();
|
||||
}
|
||||
window.addEventListener('keyup', handleComponentKeyup);
|
||||
} else {
|
||||
window.removeEventListener('keyup', handleComponentKeyup);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const screenshotMetadataSearchInputs = ref(0);
|
||||
const screenshotMetadataCarouselRef = ref(null);
|
||||
|
||||
const handleComponentKeyup = (event) => {
|
||||
const carouselNavigation = { ArrowLeft: 0, ArrowRight: 2 }[event.key];
|
||||
if (typeof carouselNavigation !== 'undefined' && props.screenshotMetadataDialog?.visible) {
|
||||
screenshotMetadataCarouselChange(carouselNavigation);
|
||||
}
|
||||
};
|
||||
|
||||
function handleDrop(event) {
|
||||
if (props.currentlyDroppingFile === null) {
|
||||
return;
|
||||
}
|
||||
console.log('Dropped file into viewer: ', props.currentlyDroppingFile);
|
||||
|
||||
screenshotMetadataResetSearch();
|
||||
getAndDisplayScreenshot(props.currentlyDroppingFile);
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
async function getAndDisplayScreenshotFromFile() {
|
||||
let filePath = '';
|
||||
// eslint-disable-next-line no-undef
|
||||
if (LINUX) {
|
||||
filePath = await window.electron.openFileDialog(); // PNG filter is applied in main.js
|
||||
} else {
|
||||
filePath = await AppApi.OpenFileSelectorDialog(
|
||||
await AppApi.GetVRChatPhotosLocation(),
|
||||
'.png',
|
||||
'PNG Files (*.png)|*.png'
|
||||
);
|
||||
}
|
||||
|
||||
if (filePath === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
screenshotMetadataResetSearch();
|
||||
getAndDisplayScreenshot(filePath);
|
||||
}
|
||||
|
||||
function getAndDisplayLastScreenshot() {
|
||||
screenshotMetadataResetSearch();
|
||||
AppApi.GetLastScreenshot().then((path) => {
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
getAndDisplayScreenshot(path);
|
||||
});
|
||||
}
|
||||
|
||||
function copyImageToClipboard(path) {
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
AppApi.CopyImageToClipboard(path).then(() => {
|
||||
$message({
|
||||
message: 'Image copied to clipboard',
|
||||
type: 'success'
|
||||
});
|
||||
});
|
||||
}
|
||||
function openImageFolder(path) {
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
AppApi.OpenFolderAndSelectItem(path).then(() => {
|
||||
$message({
|
||||
message: 'Opened image folder',
|
||||
type: 'success'
|
||||
});
|
||||
});
|
||||
}
|
||||
function uploadScreenshotToGallery() {
|
||||
const D = props.screenshotMetadataDialog;
|
||||
if (D.metadata.fileSizeBytes > 10000000) {
|
||||
$message({
|
||||
message: t('message.file.too_large'),
|
||||
type: 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
D.isUploading = true;
|
||||
AppApi.GetFileBase64(D.metadata.filePath)
|
||||
.then((base64Body) => {
|
||||
vrcPlusImageRequest
|
||||
.uploadGalleryImage(base64Body)
|
||||
.then((args) => {
|
||||
$message({
|
||||
message: t('message.gallery.uploaded'),
|
||||
type: 'success'
|
||||
});
|
||||
return args;
|
||||
})
|
||||
.finally(() => {
|
||||
D.isUploading = false;
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
$message({
|
||||
message: t('message.gallery.failed'),
|
||||
type: 'error'
|
||||
});
|
||||
console.error(err);
|
||||
D.isUploading = false;
|
||||
});
|
||||
}
|
||||
function screenshotMetadataSearch() {
|
||||
const D = props.screenshotMetadataDialog;
|
||||
|
||||
// Don't search if user is still typing
|
||||
screenshotMetadataSearchInputs.value++;
|
||||
let current = screenshotMetadataSearchInputs.value;
|
||||
setTimeout(() => {
|
||||
if (current !== screenshotMetadataSearchInputs.value) {
|
||||
return;
|
||||
}
|
||||
screenshotMetadataSearchInputs.value = 0;
|
||||
|
||||
if (D.search === '') {
|
||||
screenshotMetadataResetSearch();
|
||||
if (D.metadata.filePath !== null) {
|
||||
// Re-retrieve the current screenshot metadata and get previous/next files for regular carousel directory navigation
|
||||
getAndDisplayScreenshot(D.metadata.filePath, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const searchType = D.searchTypes.indexOf(D.searchType); // Matches the search type enum in .NET
|
||||
D.loading = true;
|
||||
AppApi.FindScreenshotsBySearch(D.search, searchType)
|
||||
.then((json) => {
|
||||
const results = JSON.parse(json);
|
||||
|
||||
if (results.length === 0) {
|
||||
D.metadata = {};
|
||||
D.metadata.error = 'No results found';
|
||||
|
||||
D.searchIndex = null;
|
||||
D.searchResults = null;
|
||||
return;
|
||||
}
|
||||
|
||||
D.searchIndex = 0;
|
||||
D.searchResults = results;
|
||||
|
||||
// console.log("Search results", results)
|
||||
getAndDisplayScreenshot(results[0], false);
|
||||
})
|
||||
.finally(() => {
|
||||
D.loading = false;
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function screenshotMetadataCarouselChange(index) {
|
||||
const D = props.screenshotMetadataDialog;
|
||||
const searchIndex = D.searchIndex;
|
||||
|
||||
if (searchIndex !== null) {
|
||||
screenshotMetadataCarouselChangeSearch(index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (index === 0) {
|
||||
if (D.metadata.previousFilePath) {
|
||||
getAndDisplayScreenshot(D.metadata.previousFilePath);
|
||||
} else {
|
||||
getAndDisplayScreenshot(D.metadata.filePath);
|
||||
}
|
||||
}
|
||||
if (index === 2) {
|
||||
if (D.metadata.nextFilePath) {
|
||||
getAndDisplayScreenshot(D.metadata.nextFilePath);
|
||||
} else {
|
||||
getAndDisplayScreenshot(D.metadata.filePath);
|
||||
}
|
||||
}
|
||||
if (typeof screenshotMetadataCarouselRef.value !== 'undefined') {
|
||||
screenshotMetadataCarouselRef.value.setActiveItem(1);
|
||||
}
|
||||
|
||||
if (props.fullscreenImageDialog.visible) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
function lookupUser(user) {
|
||||
emit('lookupUser', user);
|
||||
}
|
||||
|
||||
function screenshotMetadataResetSearch() {
|
||||
const D = props.screenshotMetadataDialog;
|
||||
|
||||
D.search = '';
|
||||
D.searchIndex = null;
|
||||
D.searchResults = null;
|
||||
}
|
||||
|
||||
function screenshotMetadataCarouselChangeSearch(index) {
|
||||
const D = props.screenshotMetadataDialog;
|
||||
let searchIndex = D.searchIndex;
|
||||
const filesArr = D.searchResults;
|
||||
|
||||
if (searchIndex === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (index === 0) {
|
||||
if (searchIndex > 0) {
|
||||
getAndDisplayScreenshot(filesArr[searchIndex - 1], false);
|
||||
searchIndex--;
|
||||
} else {
|
||||
getAndDisplayScreenshot(filesArr[filesArr.length - 1], false);
|
||||
searchIndex = filesArr.length - 1;
|
||||
}
|
||||
} else if (index === 2) {
|
||||
if (searchIndex < filesArr.length - 1) {
|
||||
getAndDisplayScreenshot(filesArr[searchIndex + 1], false);
|
||||
searchIndex++;
|
||||
} else {
|
||||
getAndDisplayScreenshot(filesArr[0], false);
|
||||
searchIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof screenshotMetadataCarouselRef.value !== 'undefined') {
|
||||
screenshotMetadataCarouselRef.value.setActiveItem(1);
|
||||
}
|
||||
|
||||
D.searchIndex = searchIndex;
|
||||
}
|
||||
|
||||
function getAndDisplayScreenshot(path, needsCarouselFiles = true) {
|
||||
AppApi.GetScreenshotMetadata(path).then((metadata) => displayScreenshotMetadata(metadata, needsCarouselFiles));
|
||||
}
|
||||
|
||||
/**
|
||||
* Function receives an unmodified json string grabbed from the screenshot file
|
||||
* Error checking and and verification of data is done in .NET already; In the case that the data/file is invalid, a JSON object with the token "error" will be returned containing a description of the problem.
|
||||
* Example: {"error":"Invalid file selected. Please select a valid VRChat screenshot."}
|
||||
* See docs/screenshotMetadata.json for schema
|
||||
* @param {string} metadata - JSON string grabbed from PNG file
|
||||
* @param {string} needsCarouselFiles - Whether or not to get the last/next files for the carousel
|
||||
* @returns {void}
|
||||
*/
|
||||
async function displayScreenshotMetadata(json, needsCarouselFiles = true) {
|
||||
let time;
|
||||
let date;
|
||||
const D = props.screenshotMetadataDialog;
|
||||
const metadata = JSON.parse(json);
|
||||
if (!metadata?.sourceFile) {
|
||||
D.metadata = {};
|
||||
D.metadata.error = 'Invalid file selected. Please select a valid VRChat screenshot.';
|
||||
return;
|
||||
}
|
||||
|
||||
// Get extra data for display dialog like resolution, file size, etc
|
||||
D.loading = true;
|
||||
const extraData = await AppApi.GetExtraScreenshotData(metadata.sourceFile, needsCarouselFiles);
|
||||
D.loading = false;
|
||||
const extraDataObj = JSON.parse(extraData);
|
||||
Object.assign(metadata, extraDataObj);
|
||||
|
||||
// console.log("Displaying screenshot metadata", json, "extra data", extraDataObj, "path", json.filePath)
|
||||
|
||||
D.metadata = metadata;
|
||||
|
||||
const regex = metadata.fileName.match(
|
||||
/VRChat_((\d{3,})x(\d{3,})_(\d{4})-(\d{2})-(\d{2})_(\d{2})-(\d{2})-(\d{2})\.(\d{1,})|(\d{4})-(\d{2})-(\d{2})_(\d{2})-(\d{2})-(\d{2})\.(\d{3})_(\d{3,})x(\d{3,}))/
|
||||
);
|
||||
if (regex) {
|
||||
if (typeof regex[2] !== 'undefined' && regex[4].length === 4) {
|
||||
// old format
|
||||
// VRChat_3840x2160_2022-02-02_03-21-39.771
|
||||
date = `${regex[4]}-${regex[5]}-${regex[6]}`;
|
||||
time = `${regex[7]}:${regex[8]}:${regex[9]}`;
|
||||
D.metadata.dateTime = Date.parse(`${date} ${time}`);
|
||||
// D.metadata.resolution = `${regex[2]}x${regex[3]}`;
|
||||
} else if (typeof regex[11] !== 'undefined' && regex[11].length === 4) {
|
||||
// new format
|
||||
// VRChat_2023-02-16_10-39-25.274_3840x2160
|
||||
date = `${regex[11]}-${regex[12]}-${regex[13]}`;
|
||||
time = `${regex[14]}:${regex[15]}:${regex[16]}`;
|
||||
D.metadata.dateTime = Date.parse(`${date} ${time}`);
|
||||
// D.metadata.resolution = `${regex[18]}x${regex[19]}`;
|
||||
}
|
||||
}
|
||||
if (metadata.timestamp) {
|
||||
D.metadata.dateTime = Date.parse(metadata.timestamp);
|
||||
}
|
||||
if (!D.metadata.dateTime) {
|
||||
D.metadata.dateTime = Date.parse(metadata.creationDate);
|
||||
}
|
||||
|
||||
if (props.fullscreenImageDialog?.visible) {
|
||||
showFullscreenImageDialog(D.metadata.filePath);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
418
src/views/Settings/dialogs/VRChatConfigDialog.vue
Normal file
418
src/views/Settings/dialogs/VRChatConfigDialog.vue
Normal file
@@ -0,0 +1,418 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible="isVRChatConfigDialogVisible"
|
||||
:title="t('dialog.config_json.header')"
|
||||
width="420px"
|
||||
top="10vh"
|
||||
@close="closeDialog"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div v-loading="loading">
|
||||
<div style="font-size: 12px; word-break: keep-all">
|
||||
{{ t('dialog.config_json.description1') }} <br />
|
||||
{{ t('dialog.config_json.description2') }}
|
||||
</div>
|
||||
<br />
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.cache_size') }}</span>
|
||||
<span v-text="VRChatUsedCacheSize"></span>
|
||||
<span>/</span>
|
||||
<span v-text="totalCacheSize"></span>
|
||||
<span>GB</span>
|
||||
<el-tooltip placement="top" :content="t('dialog.config_json.refresh')" :disabled="hideTooltips">
|
||||
<el-button
|
||||
type="default"
|
||||
:loading="VRChatCacheSizeLoading"
|
||||
size="small"
|
||||
icon="el-icon-refresh"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
@click="getVRChatCacheSize"></el-button>
|
||||
</el-tooltip>
|
||||
|
||||
<div style="margin-top: 10px">
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_all_cache') }}</span>
|
||||
<el-button
|
||||
size="small"
|
||||
style="margin-left: 5px"
|
||||
icon="el-icon-delete"
|
||||
@click="showDeleteAllVRChatCacheConfirm"
|
||||
>{{ t('dialog.config_json.delete_cache') }}</el-button
|
||||
>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px">
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_old_cache') }}</span>
|
||||
<el-button
|
||||
size="small"
|
||||
style="margin-left: 5px"
|
||||
icon="el-icon-folder-delete"
|
||||
@click="sweepVRChatCache"
|
||||
>{{ t('dialog.config_json.sweep_cache') }}</el-button
|
||||
>
|
||||
</div>
|
||||
|
||||
<div v-for="(item, value) in VRChatConfigList" :key="value" style="display: block; margin-top: 10px">
|
||||
<span style="word-break: keep-all">{{ item.name }}:</span>
|
||||
<div style="display: flex">
|
||||
<el-input
|
||||
v-model="VRChatConfigFile[value]"
|
||||
:placeholder="item.default"
|
||||
size="mini"
|
||||
:type="item.type ? item.type : 'text'"
|
||||
:min="item.min"
|
||||
:max="item.max"
|
||||
style="flex: 1; margin-top: 5px"
|
||||
><el-button
|
||||
v-if="item.folderBrowser"
|
||||
slot="append"
|
||||
size="mini"
|
||||
icon="el-icon-folder-opened"
|
||||
@click="openConfigFolderBrowser(value)"></el-button
|
||||
></el-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: inline-block; margin-top: 10px">
|
||||
<span>{{ t('dialog.config_json.camera_resolution') }}</span>
|
||||
<br />
|
||||
<el-dropdown
|
||||
size="small"
|
||||
trigger="click"
|
||||
style="margin-top: 5px"
|
||||
@command="(command) => setVRChatCameraResolution(command)">
|
||||
<el-button size="small">
|
||||
<span>
|
||||
<span v-text="getVRChatCameraResolution()"></span>
|
||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="row in VRChatCameraResolutions" :key="row.index" :command="row">{{
|
||||
row.name
|
||||
}}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div style="display: inline-block; margin-top: 10px">
|
||||
<span>{{ t('dialog.config_json.spout_resolution') }}</span>
|
||||
<br />
|
||||
<el-dropdown
|
||||
size="small"
|
||||
trigger="click"
|
||||
style="margin-top: 5px"
|
||||
@command="(command) => setVRChatSpoutResolution(command)">
|
||||
<el-button size="small">
|
||||
<span>
|
||||
<span v-text="getVRChatSpoutResolution()"></span>
|
||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="row in VRChatScreenshotResolutions"
|
||||
:key="row.index"
|
||||
:command="row"
|
||||
>{{ row.name }}</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div style="display: inline-block; margin-top: 10px">
|
||||
<span>{{ t('dialog.config_json.screenshot_resolution') }}</span>
|
||||
<br />
|
||||
<el-dropdown
|
||||
size="small"
|
||||
trigger="click"
|
||||
style="margin-top: 5px"
|
||||
@command="(command) => setVRChatScreenshotResolution(command)">
|
||||
<el-button size="small">
|
||||
<span>
|
||||
<span v-text="getVRChatScreenshotResolution()"></span>
|
||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="row in VRChatScreenshotResolutions"
|
||||
:key="row.index"
|
||||
:command="row"
|
||||
>{{ row.name }}</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<el-checkbox
|
||||
v-model="VRChatConfigFile.picture_output_split_by_date"
|
||||
style="margin-top: 5px; display: block">
|
||||
{{ t('dialog.config_json.picture_sort_by_date') }}
|
||||
</el-checkbox>
|
||||
<el-checkbox v-model="VRChatConfigFile.disableRichPresence" style="margin-top: 5px; display: block">
|
||||
{{ t('dialog.config_json.disable_discord_presence') }}
|
||||
</el-checkbox>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||
<div>
|
||||
<el-button
|
||||
size="small"
|
||||
@click="openExternalLink('https://docs.vrchat.com/docs/configuration-file')"
|
||||
>{{ t('dialog.config_json.vrchat_docs') }}</el-button
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<el-button size="small" @click="closeDialog">{{ t('dialog.config_json.cancel') }}</el-button>
|
||||
<el-button size="small" type="primary" :disabled="loading" @click="saveVRChatConfigFile">{{
|
||||
t('dialog.config_json.save')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, inject, getCurrentInstance, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import {
|
||||
getVRChatResolution,
|
||||
VRChatScreenshotResolutions,
|
||||
VRChatCameraResolutions
|
||||
} from '../../../composables/settings/constants/vrchatResolutions';
|
||||
const { t } = useI18n();
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
const $confirm = instance.proxy.$confirm;
|
||||
const $message = instance.proxy.$message;
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
const openExternalLink = inject('openExternalLink');
|
||||
|
||||
const props = defineProps({
|
||||
isVRChatConfigDialogVisible: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
VRChatUsedCacheSize: {
|
||||
type: [String, Number],
|
||||
required: true
|
||||
},
|
||||
VRChatTotalCacheSize: {
|
||||
type: [String, Number],
|
||||
required: true
|
||||
},
|
||||
VRChatCacheSizeLoading: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
folderSelectorDialog: {
|
||||
type: Function,
|
||||
required: true
|
||||
},
|
||||
hideTooltips: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:isVRChatConfigDialogVisible', 'getVRChatCacheSize', 'sweepVRChatCache']);
|
||||
|
||||
const VRChatConfigFile = ref({});
|
||||
// it's a object
|
||||
const VRChatConfigList = ref({
|
||||
cache_size: {
|
||||
name: t('dialog.config_json.max_cache_size'),
|
||||
default: '30',
|
||||
type: 'number',
|
||||
min: 30
|
||||
},
|
||||
cache_expiry_delay: {
|
||||
name: t('dialog.config_json.cache_expiry_delay'),
|
||||
default: '30',
|
||||
type: 'number',
|
||||
min: 30
|
||||
},
|
||||
cache_directory: {
|
||||
name: t('dialog.config_json.cache_directory'),
|
||||
default: '%AppData%\\..\\LocalLow\\VRChat\\VRChat',
|
||||
folderBrowser: true
|
||||
},
|
||||
picture_output_folder: {
|
||||
name: t('dialog.config_json.picture_directory'),
|
||||
// my pictures folder
|
||||
default: `%UserProfile%\\Pictures\\VRChat`,
|
||||
folderBrowser: true
|
||||
},
|
||||
// dynamic_bone_max_affected_transform_count: {
|
||||
// name: 'Dynamic Bones Limit Max Transforms (0 disable all transforms)',
|
||||
// default: '32',
|
||||
// type: 'number',
|
||||
// min: 0
|
||||
// },
|
||||
// dynamic_bone_max_collider_check_count: {
|
||||
// name: 'Dynamic Bones Limit Max Collider Collisions (0 disable all colliders)',
|
||||
// default: '8',
|
||||
// type: 'number',
|
||||
// min: 0
|
||||
// },
|
||||
fpv_steadycam_fov: {
|
||||
name: t('dialog.config_json.fpv_steadycam_fov'),
|
||||
default: '50',
|
||||
type: 'number',
|
||||
min: 30,
|
||||
max: 110
|
||||
}
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.isVRChatConfigDialogVisible,
|
||||
async (newValue) => {
|
||||
if (newValue) {
|
||||
loading.value = true;
|
||||
await readVRChatConfigFile();
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const totalCacheSize = computed(() => {
|
||||
return VRChatConfigFile.value.cache_size || props.VRChatTotalCacheSize;
|
||||
});
|
||||
|
||||
function getVRChatCacheSize() {
|
||||
emit('getVRChatCacheSize');
|
||||
}
|
||||
|
||||
function showDeleteAllVRChatCacheConfirm() {
|
||||
$confirm(`Continue? Delete all VRChat cache`, 'Confirm', {
|
||||
confirmButtonText: 'Confirm',
|
||||
cancelButtonText: 'Cancel',
|
||||
type: 'info',
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
deleteAllVRChatCache();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function deleteAllVRChatCache() {
|
||||
await AssetBundleManager.DeleteAllCache();
|
||||
getVRChatCacheSize();
|
||||
}
|
||||
|
||||
function sweepVRChatCache() {
|
||||
emit('sweepVRChatCache');
|
||||
}
|
||||
|
||||
async function openConfigFolderBrowser(value) {
|
||||
const oldPath = VRChatConfigFile.value[value];
|
||||
const newPath = await props.folderSelectorDialog(oldPath);
|
||||
if (newPath) {
|
||||
VRChatConfigFile.value[value] = newPath;
|
||||
}
|
||||
}
|
||||
|
||||
function setVRChatSpoutResolution(res) {
|
||||
VRChatConfigFile.value.camera_spout_res_height = res.height;
|
||||
VRChatConfigFile.value.camera_spout_res_width = res.width;
|
||||
}
|
||||
|
||||
function setVRChatCameraResolution(res) {
|
||||
VRChatConfigFile.value.camera_res_height = res.height;
|
||||
VRChatConfigFile.value.camera_res_width = res.width;
|
||||
}
|
||||
|
||||
function setVRChatScreenshotResolution(res) {
|
||||
VRChatConfigFile.value.screenshot_res_height = res.height;
|
||||
VRChatConfigFile.value.screenshot_res_width = res.width;
|
||||
}
|
||||
|
||||
function getVRChatCameraResolution() {
|
||||
if (VRChatConfigFile.value.camera_res_height && VRChatConfigFile.value.camera_res_width) {
|
||||
const res = `${VRChatConfigFile.value.camera_res_width}x${VRChatConfigFile.value.camera_res_height}`;
|
||||
return getVRChatResolution(res);
|
||||
}
|
||||
return '1920x1080 (1080p)';
|
||||
}
|
||||
|
||||
function getVRChatSpoutResolution() {
|
||||
if (VRChatConfigFile.value.camera_spout_res_height && VRChatConfigFile.value.camera_spout_res_width) {
|
||||
const res = `${VRChatConfigFile.value.camera_spout_res_width}x${VRChatConfigFile.value.camera_spout_res_height}`;
|
||||
return getVRChatResolution(res);
|
||||
}
|
||||
return '1920x1080 (1080p)';
|
||||
}
|
||||
|
||||
function getVRChatScreenshotResolution() {
|
||||
if (VRChatConfigFile.value.screenshot_res_height && VRChatConfigFile.value.screenshot_res_width) {
|
||||
const res = `${VRChatConfigFile.value.screenshot_res_width}x${VRChatConfigFile.value.screenshot_res_height}`;
|
||||
return getVRChatResolution(res);
|
||||
}
|
||||
return '1920x1080 (1080p)';
|
||||
}
|
||||
|
||||
function saveVRChatConfigFile() {
|
||||
for (const item in VRChatConfigFile.value) {
|
||||
if (item === 'picture_output_split_by_date') {
|
||||
// this one is default true, it's special
|
||||
if (VRChatConfigFile.value[item]) {
|
||||
delete VRChatConfigFile.value[item];
|
||||
}
|
||||
} else if (VRChatConfigFile.value[item] === '') {
|
||||
delete VRChatConfigFile.value[item];
|
||||
} else if (typeof VRChatConfigFile.value[item] === 'boolean' && VRChatConfigFile.value[item] === false) {
|
||||
delete VRChatConfigFile.value[item];
|
||||
} else if (typeof VRChatConfigFile.value[item] === 'string' && !isNaN(VRChatConfigFile.value[item])) {
|
||||
VRChatConfigFile.value[item] = parseInt(VRChatConfigFile.value[item], 10);
|
||||
}
|
||||
}
|
||||
WriteVRChatConfigFile();
|
||||
closeDialog();
|
||||
}
|
||||
|
||||
function WriteVRChatConfigFile() {
|
||||
const json = JSON.stringify(VRChatConfigFile.value, null, '\t');
|
||||
AppApi.WriteConfigFile(json);
|
||||
}
|
||||
|
||||
async function readVRChatConfigFile() {
|
||||
const config = await AppApi.ReadConfigFile();
|
||||
if (config) {
|
||||
try {
|
||||
const parsedConfig = JSON.parse(config);
|
||||
if (parsedConfig.picture_output_split_by_date === undefined) {
|
||||
parsedConfig.picture_output_split_by_date = true;
|
||||
}
|
||||
VRChatConfigFile.value = { ...VRChatConfigFile.value, ...parsedConfig };
|
||||
} catch {
|
||||
$message({
|
||||
message: 'Invalid JSON in config.json',
|
||||
type: 'error'
|
||||
});
|
||||
throw new Error('Invalid JSON in config.json');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:isVRChatConfigDialogVisible', false);
|
||||
}
|
||||
</script>
|
||||
103
src/views/Settings/dialogs/YouTubeApiDialog.vue
Normal file
103
src/views/Settings/dialogs/YouTubeApiDialog.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible="isYouTubeApiDialogVisible"
|
||||
:title="t('dialog.youtube_api.header')"
|
||||
width="400px"
|
||||
@close="closeDialog"
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<div style="font-size: 12px">{{ t('dialog.youtube_api.description') }} <br /></div>
|
||||
|
||||
<el-input
|
||||
:value="youTubeApiKey"
|
||||
type="textarea"
|
||||
:placeholder="t('dialog.youtube_api.placeholder')"
|
||||
maxlength="39"
|
||||
show-word-limit
|
||||
style="display: block; margin-top: 10px"
|
||||
@input="updateYouTubeApiKey">
|
||||
</el-input>
|
||||
|
||||
<template #footer>
|
||||
<div style="display: flex">
|
||||
<el-button
|
||||
size="small"
|
||||
@click="openExternalLink('https://rapidapi.com/blog/how-to-get-youtube-api-key/')">
|
||||
{{ t('dialog.youtube_api.guide') }}
|
||||
</el-button>
|
||||
<el-button type="primary" size="small" style="margin-left: auto" @click="testYouTubeApiKey">
|
||||
{{ t('dialog.youtube_api.save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject, getCurrentInstance } from 'vue';
|
||||
import configRepository from '../../../service/config';
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
const { t } = useI18n();
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
const $message = instance.proxy.$message;
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
const openExternalLink = inject('openExternalLink');
|
||||
|
||||
const props = defineProps({
|
||||
isYouTubeApiDialogVisible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
lookupYouTubeVideo: {
|
||||
type: Function,
|
||||
default: () => {}
|
||||
},
|
||||
youTubeApiKey: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:isYouTubeApiDialogVisible', 'update:youTubeApiKey']);
|
||||
|
||||
async function testYouTubeApiKey() {
|
||||
if (!props.youTubeApiKey) {
|
||||
$message({
|
||||
message: 'YouTube API key removed',
|
||||
type: 'success'
|
||||
});
|
||||
await configRepository.setString('VRCX_youtubeAPIKey', '');
|
||||
closeDialog();
|
||||
return;
|
||||
}
|
||||
const data = await props.lookupYouTubeVideo('dQw4w9WgXcQ');
|
||||
if (!data) {
|
||||
updateYouTubeApiKey('');
|
||||
$message({
|
||||
message: 'Invalid YouTube API key',
|
||||
type: 'error'
|
||||
});
|
||||
} else {
|
||||
await configRepository.setString('VRCX_youtubeAPIKey', props.youTubeApiKey);
|
||||
$message({
|
||||
message: 'YouTube API key valid!',
|
||||
type: 'success'
|
||||
});
|
||||
closeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
function updateYouTubeApiKey(value) {
|
||||
emit('update:youTubeApiKey', value);
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
emit('update:isYouTubeApiDialogVisible', false);
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user