mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-02 04:56:06 +02:00
refactor: Avatar dialog (#1208)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="aside" class="x-aside-container" v-show="isSideBarTabShow">
|
||||
<div v-show="isSideBarTabShow" id="aside" class="x-aside-container">
|
||||
<div style="display: flex; align-items: baseline">
|
||||
<el-select
|
||||
value=""
|
||||
@@ -32,7 +32,7 @@
|
||||
:traveling="item.ref.travelingToLocation"
|
||||
:link="false"></location>
|
||||
</div>
|
||||
<img class="avatar" v-lazy="userImage(item.ref)" />
|
||||
<img v-lazy="userImage(item.ref)" class="avatar" />
|
||||
</template>
|
||||
<span v-else>
|
||||
{{ $t('side_panel.search_result_more') }}
|
||||
@@ -69,21 +69,21 @@
|
||||
</span>
|
||||
</template>
|
||||
<el-backtop target=".zero-margin-tabs .el-tabs__content" :bottom="20" :right="20"></el-backtop>
|
||||
<friends-sidebar
|
||||
@confirm-delete-friend="$emit('confirm-delete-friend', $event)"
|
||||
<FriendsSidebar
|
||||
:hide-nicknames="hideNicknames"
|
||||
:is-game-running="isGameRunning"
|
||||
:is-sidebar-divide-by-friend-group="isSidebarDivideByFriendGroup"
|
||||
:is-sidebar-group-by-instance="isSidebarGroupByInstance"
|
||||
:game-log-disabled="gameLogDisabled"
|
||||
:last-location="lastLocation"
|
||||
:last-location-destination="lastLocationDestination"
|
||||
:hide-nicknames="hideNicknames"
|
||||
:active-friends="activeFriends"
|
||||
:offline-friends="offlineFriends"
|
||||
:online-friends="onlineFriends"
|
||||
:vip-friends="vipFriends"
|
||||
:is-hide-friends-in-same-instance="isHideFriendsInSameInstance"
|
||||
:grouped-by-group-key-favorite-friends="groupedByGroupKeyFavoriteFriends"></friends-sidebar>
|
||||
:grouped-by-group-key-favorite-friends="groupedByGroupKeyFavoriteFriends"
|
||||
@confirm-delete-friend="$emit('confirm-delete-friend', $event)" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane lazy>
|
||||
<template slot="label">
|
||||
@@ -92,11 +92,11 @@
|
||||
({{ groupInstances.length }})
|
||||
</span>
|
||||
</template>
|
||||
<groups-sidebar
|
||||
<GroupsSidebar
|
||||
:group-instances="groupInstances"
|
||||
:group-order="inGameGroupOrder"
|
||||
:is-age-gated-instances-visible="isAgeGatedInstancesVisible"
|
||||
@show-group-dialog="$emit('show-group-dialog', $event)"></groups-sidebar>
|
||||
@show-group-dialog="$emit('show-group-dialog', $event)" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,289 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
ref="setAvatarTagsDialog"
|
||||
class="x-dialog"
|
||||
:before-close="beforeDialogClose"
|
||||
:visible.sync="setAvatarTagsDialog.visible"
|
||||
:title="t('dialog.set_avatar_tags.header')"
|
||||
width="770px"
|
||||
append-to-body
|
||||
@mousedown.native="dialogMouseDown"
|
||||
@mouseup.native="dialogMouseUp">
|
||||
<template v-if="setAvatarTagsDialog.visible">
|
||||
<el-checkbox v-model="setAvatarTagsDialog.contentHorror" @change="updateSelectedAvatarTags">{{
|
||||
t('dialog.set_avatar_tags.content_horror')
|
||||
}}</el-checkbox>
|
||||
<br />
|
||||
<el-checkbox v-model="setAvatarTagsDialog.contentGore" @change="updateSelectedAvatarTags">{{
|
||||
t('dialog.set_avatar_tags.content_gore')
|
||||
}}</el-checkbox>
|
||||
<br />
|
||||
<el-checkbox v-model="setAvatarTagsDialog.contentViolence" @change="updateSelectedAvatarTags">{{
|
||||
t('dialog.set_avatar_tags.content_violence')
|
||||
}}</el-checkbox>
|
||||
<br />
|
||||
<el-checkbox v-model="setAvatarTagsDialog.contentAdult" @change="updateSelectedAvatarTags">{{
|
||||
t('dialog.set_avatar_tags.content_adult')
|
||||
}}</el-checkbox>
|
||||
<br />
|
||||
<el-checkbox v-model="setAvatarTagsDialog.contentSex" @change="updateSelectedAvatarTags">{{
|
||||
t('dialog.set_avatar_tags.content_sex')
|
||||
}}</el-checkbox>
|
||||
<br />
|
||||
<el-input
|
||||
v-model="setAvatarTagsDialog.selectedTagsCsv"
|
||||
size="mini"
|
||||
:autosize="{ minRows: 2, maxRows: 5 }"
|
||||
:placeholder="t('dialog.set_avatar_tags.custom_tags_placeholder')"
|
||||
style="margin-top: 10px"
|
||||
@input="updateInputAvatarTags"></el-input>
|
||||
<template v-if="setAvatarTagsDialog.ownAvatars.length === setAvatarTagsDialog.selectedCount">
|
||||
<el-button size="small" @click="setAvatarTagsSelectToggle">{{
|
||||
t('dialog.set_avatar_tags.select_none')
|
||||
}}</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button size="small" @click="setAvatarTagsSelectToggle">{{
|
||||
t('dialog.set_avatar_tags.select_all')
|
||||
}}</el-button>
|
||||
</template>
|
||||
<span style="margin-left: 5px"
|
||||
>{{ setAvatarTagsDialog.selectedCount }} / {{ setAvatarTagsDialog.ownAvatars.length }}</span
|
||||
>
|
||||
<span v-if="setAvatarTagsDialog.loading" style="margin-left: 5px">
|
||||
<i class="el-icon-loading"></i>
|
||||
</span>
|
||||
<br />
|
||||
<div class="x-friend-list" style="margin-top: 10px; min-height: 60px; max-height: 280px">
|
||||
<div
|
||||
v-for="avatar in setAvatarTagsDialog.ownAvatars"
|
||||
:key="avatar.id"
|
||||
class="x-friend-item x-friend-item-border"
|
||||
style="width: 350px"
|
||||
@click="showAvatarDialog(avatar.id)">
|
||||
<div class="avatar">
|
||||
<img v-if="avatar.thumbnailImageUrl" v-lazy="avatar.thumbnailImageUrl" />
|
||||
</div>
|
||||
<div class="detail">
|
||||
<span class="name" v-text="avatar.name"></span>
|
||||
<span
|
||||
v-if="avatar.releaseStatus === 'public'"
|
||||
class="extra"
|
||||
style="color: #67c23a"
|
||||
v-text="avatar.releaseStatus"></span>
|
||||
<span
|
||||
v-else-if="avatar.releaseStatus === 'private'"
|
||||
class="extra"
|
||||
style="color: #f56c6c"
|
||||
v-text="avatar.releaseStatus"></span>
|
||||
<span v-else class="extra" v-text="avatar.releaseStatus"></span>
|
||||
<span class="extra" v-text="avatar.$tagString"></span>
|
||||
</div>
|
||||
<el-button type="text" size="mini" style="margin-left: 5px" @click.stop>
|
||||
<el-checkbox v-model="avatar.$selected" @change="updateAvatarTagsSelection"></el-checkbox>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button size="small" @click="setAvatarTagsDialog.visible = false">{{
|
||||
t('dialog.set_avatar_tags.cancel')
|
||||
}}</el-button>
|
||||
<el-button type="primary" size="small" @click="saveSetAvatarTagsDialog">{{
|
||||
t('dialog.set_avatar_tags.save')
|
||||
}}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject, watch, getCurrentInstance } from 'vue';
|
||||
|
||||
import { useI18n } from 'vue-i18n-bridge';
|
||||
import { avatarRequest } from '../../../classes/request';
|
||||
|
||||
const beforeDialogClose = inject('beforeDialogClose');
|
||||
const dialogMouseDown = inject('dialogMouseDown');
|
||||
const dialogMouseUp = inject('dialogMouseUp');
|
||||
const showAvatarDialog = inject('showAvatarDialog');
|
||||
|
||||
const { t } = useI18n();
|
||||
const instance = getCurrentInstance();
|
||||
const $message = instance.proxy.$message;
|
||||
|
||||
const props = defineProps({
|
||||
setAvatarTagsDialog: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.setAvatarTagsDialog.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
updateAvatarTagsSelection();
|
||||
updateSelectedAvatarTags();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function updateSelectedAvatarTags() {
|
||||
const D = props.setAvatarTagsDialog;
|
||||
if (D.contentHorror) {
|
||||
if (!D.selectedTags.includes('content_horror')) {
|
||||
D.selectedTags.push('content_horror');
|
||||
}
|
||||
} else if (D.selectedTags.includes('content_horror')) {
|
||||
D.selectedTags.splice(D.selectedTags.indexOf('content_horror'), 1);
|
||||
}
|
||||
if (D.contentGore) {
|
||||
if (!D.selectedTags.includes('content_gore')) {
|
||||
D.selectedTags.push('content_gore');
|
||||
}
|
||||
} else if (D.selectedTags.includes('content_gore')) {
|
||||
D.selectedTags.splice(D.selectedTags.indexOf('content_gore'), 1);
|
||||
}
|
||||
if (D.contentViolence) {
|
||||
if (!D.selectedTags.includes('content_violence')) {
|
||||
D.selectedTags.push('content_violence');
|
||||
}
|
||||
} else if (D.selectedTags.includes('content_violence')) {
|
||||
D.selectedTags.splice(D.selectedTags.indexOf('content_violence'), 1);
|
||||
}
|
||||
if (D.contentAdult) {
|
||||
if (!D.selectedTags.includes('content_adult')) {
|
||||
D.selectedTags.push('content_adult');
|
||||
}
|
||||
} else if (D.selectedTags.includes('content_adult')) {
|
||||
D.selectedTags.splice(D.selectedTags.indexOf('content_adult'), 1);
|
||||
}
|
||||
if (D.contentSex) {
|
||||
if (!D.selectedTags.includes('content_sex')) {
|
||||
D.selectedTags.push('content_sex');
|
||||
}
|
||||
} else if (D.selectedTags.includes('content_sex')) {
|
||||
D.selectedTags.splice(D.selectedTags.indexOf('content_sex'), 1);
|
||||
}
|
||||
|
||||
D.selectedTagsCsv = D.selectedTags.join(',').replace(/content_/g, '');
|
||||
}
|
||||
|
||||
function updateAvatarTagsSelection() {
|
||||
const D = props.setAvatarTagsDialog;
|
||||
D.selectedCount = 0;
|
||||
for (const ref of D.ownAvatars) {
|
||||
if (ref.$selected) {
|
||||
D.selectedCount++;
|
||||
}
|
||||
ref.$tagString = '';
|
||||
const conentTags = [];
|
||||
ref.tags.forEach((tag) => {
|
||||
if (tag.startsWith('content_')) {
|
||||
conentTags.push(tag.substring(8));
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < conentTags.length; ++i) {
|
||||
const tag = conentTags[i];
|
||||
if (i < conentTags.length - 1) {
|
||||
ref.$tagString += `${tag}, `;
|
||||
} else {
|
||||
ref.$tagString += tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
// props.setAvatarTagsDialog.forceUpdate++;
|
||||
}
|
||||
|
||||
function setAvatarTagsSelectToggle() {
|
||||
const D = props.setAvatarTagsDialog;
|
||||
const allSelected = D.ownAvatars.length === D.selectedCount;
|
||||
for (const ref of D.ownAvatars) {
|
||||
ref.$selected = !allSelected;
|
||||
}
|
||||
updateAvatarTagsSelection();
|
||||
}
|
||||
|
||||
async function saveSetAvatarTagsDialog() {
|
||||
const D = props.setAvatarTagsDialog;
|
||||
if (D.loading) {
|
||||
return;
|
||||
}
|
||||
D.loading = true;
|
||||
try {
|
||||
for (let i = D.ownAvatars.length - 1; i >= 0; --i) {
|
||||
const ref = D.ownAvatars[i];
|
||||
if (!D.visible) {
|
||||
break;
|
||||
}
|
||||
if (!ref.$selected) {
|
||||
continue;
|
||||
}
|
||||
const tags = [...D.selectedTags];
|
||||
for (const tag of ref.tags) {
|
||||
if (!tag.startsWith('content_')) {
|
||||
tags.push(tag);
|
||||
}
|
||||
}
|
||||
await avatarRequest.saveAvatar({
|
||||
id: ref.id,
|
||||
tags
|
||||
});
|
||||
D.selectedCount--;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
$message({
|
||||
message: 'Error saving avatar tags',
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
D.loading = false;
|
||||
D.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
function updateInputAvatarTags() {
|
||||
const D = props.setAvatarTagsDialog;
|
||||
D.contentHorror = false;
|
||||
D.contentGore = false;
|
||||
D.contentViolence = false;
|
||||
D.contentAdult = false;
|
||||
D.contentSex = false;
|
||||
const tags = D.selectedTagsCsv.split(',');
|
||||
D.selectedTags = [];
|
||||
for (const tag of tags) {
|
||||
switch (tag) {
|
||||
case 'horror':
|
||||
D.contentHorror = true;
|
||||
break;
|
||||
case 'gore':
|
||||
D.contentGore = true;
|
||||
break;
|
||||
case 'violence':
|
||||
D.contentViolence = true;
|
||||
break;
|
||||
case 'adult':
|
||||
D.contentAdult = true;
|
||||
break;
|
||||
case 'sex':
|
||||
D.contentSex = true;
|
||||
break;
|
||||
}
|
||||
if (!D.selectedTags.includes(`content_${tag}`)) {
|
||||
D.selectedTags.push(`content_${tag}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// useless
|
||||
// $app.data.avatarContentTags = [
|
||||
// 'content_horror',
|
||||
// 'content_gore',
|
||||
// 'content_violence',
|
||||
// 'content_adult',
|
||||
// 'content_sex'
|
||||
// ];
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1242,7 +1242,6 @@
|
||||
'get-group-dialog-group-members',
|
||||
'refresh-instance-player-count',
|
||||
'update-group-post-search',
|
||||
'download-and-save-json',
|
||||
'set-group-member-sort-order',
|
||||
'clear-image-gallery-select'
|
||||
]);
|
||||
@@ -1780,8 +1779,8 @@
|
||||
function updateGroupPostSearch() {
|
||||
emit('update-group-post-search');
|
||||
}
|
||||
function downloadAndSaveJson(filename, data) {
|
||||
emit('download-and-save-json', filename, data);
|
||||
function downloadAndSaveJson(fileName, data) {
|
||||
utils.downloadAndSaveJson(fileName, data);
|
||||
}
|
||||
function clearImageGallerySelect() {
|
||||
emit('clear-image-gallery-select');
|
||||
|
||||
@@ -1681,7 +1681,11 @@
|
||||
}
|
||||
|
||||
function getAuditLogTypeName(auditLogType) {
|
||||
return utils.getAuditLogTypeName(auditLogType);
|
||||
if (!auditLogType) return '';
|
||||
return auditLogType
|
||||
.replace('group.', '')
|
||||
.replace(/\./g, ' ')
|
||||
.replace(/\b\w/g, (l) => l.toUpperCase());
|
||||
}
|
||||
|
||||
function hasGroupPermission(ref, permission) {
|
||||
|
||||
@@ -739,17 +739,17 @@
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
<!-- Nested Hmm-->
|
||||
<world-allowed-domains-dialog :world-allowed-domains-dialog.sync="worldAllowedDomainsDialog" />
|
||||
<set-world-tags-dialog
|
||||
<!-- Nested -->
|
||||
<WorldAllowedDomainsDialog :world-allowed-domains-dialog.sync="worldAllowedDomainsDialog" />
|
||||
<SetWorldTagsDialog
|
||||
:is-set-world-tags-dialog-visible.sync="isSetWorldTagsDialogVisible"
|
||||
:old-tags="worldDialog.ref?.tags"
|
||||
:world-id="worldDialog.id"
|
||||
:is-world-dialog-visible="worldDialog.visible" />
|
||||
<previous-instances-world-dialog
|
||||
<PreviousInstancesWorldDialog
|
||||
:previous-instances-world-dialog.sync="previousInstancesWorldDialog"
|
||||
:shift-held="shiftHeld" />
|
||||
<new-instance-dialog
|
||||
<NewInstanceDialog
|
||||
:new-instance-dialog-location-tag="newInstanceDialogLocationTag"
|
||||
:create-new-instance="createNewInstance"
|
||||
:instance-content-settings="instanceContentSettings"
|
||||
@@ -1082,8 +1082,8 @@
|
||||
refreshWorldDialogTreeData() {
|
||||
this.treeData = utils.buildTreeData(this.worldDialog.ref);
|
||||
},
|
||||
downloadAndSaveJson(id, ref) {
|
||||
this.$emit('download-and-save-json', id, ref);
|
||||
downloadAndSaveJson(fileName, data) {
|
||||
utils.downloadAndSaveJson(fileName, data);
|
||||
},
|
||||
copyWorldId() {
|
||||
navigator.clipboard
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
<div class="options-container" style="margin-top: 0">
|
||||
<span class="header">{{ $t('view.charts.header') }}</span>
|
||||
</div>
|
||||
<instance-activity
|
||||
<InstanceActivity
|
||||
:get-world-name="getWorldName"
|
||||
:is-dark-mode="isDarkMode"
|
||||
:dt-hour12="dtHour12"
|
||||
:friends-map="friendsMap"
|
||||
:localFavoriteFriends="localFavoriteFriends"
|
||||
@open-previous-instance-info-dialog="$emit('open-previous-instance-info-dialog', $event)"
|
||||
></instance-activity>
|
||||
:local-favorite-friends="localFavoriteFriends"
|
||||
@open-previous-instance-info-dialog="$emit('open-previous-instance-info-dialog', $event)" />
|
||||
<el-backtop target="#chart" :right="30" :bottom="30"></el-backtop>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
<el-tabs v-model="currentTabName" v-loading="API.isFavoriteLoading" type="card" style="height: 100%">
|
||||
<el-tab-pane name="friend" :label="$t('view.favorite.friends.header')" lazy>
|
||||
<favorites-friend-tab
|
||||
<FavoritesFriendTab
|
||||
:favorite-friends="favoriteFriends"
|
||||
:sort-favorites.sync="isSortByTime"
|
||||
:hide-tooltips="hideTooltips"
|
||||
@@ -38,7 +38,7 @@
|
||||
@change-favorite-group-name="changeFavoriteGroupName" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="world" :label="$t('view.favorite.worlds.header')" lazy>
|
||||
<favorites-world-tab
|
||||
<FavoritesWorldTab
|
||||
@show-world-import-dialog="showWorldImportDialog"
|
||||
@save-sort-favorites-option="saveSortFavoritesOption"
|
||||
@change-favorite-group-name="changeFavoriteGroupName"
|
||||
@@ -59,7 +59,7 @@
|
||||
:local-world-favorites-list="localWorldFavoritesList" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="avatar" :label="$t('view.favorite.avatars.header')" lazy>
|
||||
<favorites-avatar-tab
|
||||
<FavoritesAvatarTab
|
||||
:sort-favorites.sync="isSortByTime"
|
||||
:hide-tooltips="hideTooltips"
|
||||
:shift-held="shiftHeld"
|
||||
|
||||
Reference in New Issue
Block a user