diff --git a/html/src/app.js b/html/src/app.js index be1ed04f..96778af1 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -18258,6 +18258,9 @@ speechSynthesis.getVoices(); case 'Change Description': this.promptChangeAvatarDescription(D); break; + case 'Change Content Tags': + this.showSetAvatarTagsDialog(D.id); + break; case 'Download Unity Package': this.openExternalLink(this.avatarDialog.ref.unityPackageUrl); break; @@ -19180,13 +19183,25 @@ speechSynthesis.getVoices(); authorTags: [], contentTags: [], debugAllowed: false, - avatarScalingDisabled: false + avatarScalingDisabled: false, + contentHorror: false, + contentGore: false, + contentViolence: false, + contentAdult: false, + contentSex: false }; $app.methods.showSetWorldTagsDialog = function () { this.$nextTick(() => adjustDialogZ(this.$refs.setWorldTagsDialog.$el)); var D = this.setWorldTagsDialog; D.visible = true; + D.debugAllowed = false; + D.avatarScalingDisabled = false; + D.contentHorror = false; + D.contentGore = false; + D.contentViolence = false; + D.contentAdult = false; + D.contentSex = false; var oldTags = this.worldDialog.ref.tags; var authorTags = []; var contentTags = []; @@ -19197,11 +19212,29 @@ speechSynthesis.getVoices(); if (tag.startsWith('content_')) { contentTags.unshift(tag.substring(8)); } - if (tag === 'debug_allowed') { - D.debugAllowed = true; - } - if (tag === 'feature_avatar_scaling_disabled') { - D.avatarScalingDisabled = true; + switch (tag) { + case 'content_horror': + D.contentHorror = true; + break; + case 'content_gore': + D.contentGore = true; + break; + case 'content_violence': + D.contentViolence = true; + break; + case 'content_adult': + D.contentAdult = true; + break; + case 'content_sex': + D.contentSex = true; + break; + + case 'debug_allowed': + D.debugAllowed = true; + break; + case 'feature_avatar_scaling_disabled': + D.avatarScalingDisabled = true; + break; } }); D.authorTags = authorTags.toString(); @@ -19218,11 +19251,36 @@ speechSynthesis.getVoices(); tags.unshift(`author_tag_${tag}`); } }); + // add back custom tags contentTags.forEach((tag) => { - if (tag) { - tags.unshift(`content_${tag}`); + switch (tag) { + case 'horror': + case 'gore': + case 'violence': + case 'adult': + case 'sex': + case '': + break; + default: + tags.unshift(`content_${tag}`); + break; } }); + if (D.contentHorror) { + tags.unshift('content_horror'); + } + if (D.contentGore) { + tags.unshift('content_gore'); + } + if (D.contentViolence) { + tags.unshift('content_violence'); + } + if (D.contentAdult) { + tags.unshift('content_adult'); + } + if (D.contentSex) { + tags.unshift('content_sex'); + } if (D.debugAllowed) { tags.unshift('debug_allowed'); } @@ -19248,6 +19306,197 @@ speechSynthesis.getVoices(); }); }; + // #endregion + // #region | App: Set Avatar Tags Dialog + + $app.data.setAvatarTagsDialog = { + visible: false, + loading: false, + ownAvatars: [], + selectedCount: 0, + forceUpdate: 0, + contentHorror: false, + contentGore: false, + contentViolence: false, + contentAdult: false, + contentSex: false + }; + + $app.methods.showSetAvatarTagsDialog = function (avatarId) { + this.$nextTick(() => adjustDialogZ(this.$refs.setAvatarTagsDialog.$el)); + var D = this.setAvatarTagsDialog; + D.visible = true; + D.loading = false; + D.ownAvatars = []; + D.forceUpdate = 0; + D.contentHorror = false; + D.contentGore = false; + D.contentViolence = false; + D.contentAdult = false; + D.contentSex = false; + var oldTags = this.avatarDialog.ref.tags; + oldTags.forEach((tag) => { + switch (tag) { + case 'content_horror': + D.contentHorror = true; + break; + case 'content_gore': + D.contentGore = true; + break; + case 'content_violence': + D.contentViolence = true; + break; + case 'content_adult': + D.contentAdult = true; + break; + case 'content_sex': + D.contentSex = true; + break; + } + }); + for (var ref of API.cachedAvatars.values()) { + if (ref.authorId === API.currentUser.id) { + ref.$selected = false; + ref.$tagString = ''; + if (avatarId === ref.id) { + ref.$selected = true; + var conentTags = []; + ref.tags.forEach((tag) => { + if (tag.startsWith('content_')) { + conentTags.push(tag.substring(8)); + } + }); + for (var i = 0; i < conentTags.length; ++i) { + var tag = conentTags[i]; + if (i < conentTags.length - 1) { + ref.$tagString += `${tag}, `; + } else { + ref.$tagString += tag; + } + } + } + D.ownAvatars.push(ref); + } + } + this.updateAvatarTagsSelection(); + }; + + $app.data.avatarContentTags = [ + 'content_horror', + 'content_gore', + 'content_violence', + 'content_adult', + 'content_sex' + ]; + + $app.methods.saveSetAvatarTagsDialog = async function () { + var D = this.setAvatarTagsDialog; + if (D.loading) { + return; + } + D.loading = true; + try { + for (var i = D.ownAvatars.length - 1; i >= 0; --i) { + var ref = D.ownAvatars[i]; + if (!D.visible) { + break; + } + if (!ref.$selected) { + continue; + } + var tags = ref.tags; + if (D.contentHorror) { + if (!tags.includes('content_horror')) { + tags.push('content_horror'); + } + } else if (tags.includes('content_horror')) { + tags.splice(tags.indexOf('content_horror'), 1); + } + + if (D.contentGore) { + if (!tags.includes('content_gore')) { + tags.push('content_gore'); + } + } else if (tags.includes('content_gore')) { + tags.splice(tags.indexOf('content_gore'), 1); + } + + if (D.contentViolence) { + if (!tags.includes('content_violence')) { + tags.push('content_violence'); + } + } else if (tags.includes('content_violence')) { + tags.splice(tags.indexOf('content_violence'), 1); + } + + if (D.contentAdult) { + if (!tags.includes('content_adult')) { + tags.push('content_adult'); + } + } else if (tags.includes('content_adult')) { + tags.splice(tags.indexOf('content_adult'), 1); + } + + if (D.contentSex) { + if (!tags.includes('content_sex')) { + tags.push('content_sex'); + } + } else if (tags.includes('content_sex')) { + tags.splice(tags.indexOf('content_sex'), 1); + } + + await API.saveAvatar({ + id: ref.id, + tags + }); + D.selectedCount--; + } + } catch (err) { + this.$message({ + message: 'Error saving avatar tags', + type: 'error' + }); + } finally { + D.loading = false; + D.visible = false; + } + }; + + $app.methods.updateAvatarTagsSelection = function () { + var D = this.setAvatarTagsDialog; + D.selectedCount = 0; + for (var ref of D.ownAvatars) { + if (ref.$selected) { + D.selectedCount++; + } + ref.$tagString = ''; + var conentTags = []; + ref.tags.forEach((tag) => { + if (tag.startsWith('content_')) { + conentTags.push(tag.substring(8)); + } + }); + for (var i = 0; i < conentTags.length; ++i) { + var tag = conentTags[i]; + if (i < conentTags.length - 1) { + ref.$tagString += `${tag}, `; + } else { + ref.$tagString += tag; + } + } + } + this.setAvatarTagsDialog.forceUpdate++; + }; + + $app.methods.setAvatarTagsSelectToggle = function () { + var D = this.setAvatarTagsDialog; + var allSelected = D.ownAvatars.length === D.selectedCount; + for (var ref of D.ownAvatars) { + ref.$selected = !allSelected; + } + this.updateAvatarTagsSelection(); + }; + // #endregion // #region | App: Notification position diff --git a/html/src/index.pug b/html/src/index.pug index 49975ea4..6635d824 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -597,6 +597,12 @@ html el-tag.x-link(v-if="worldDialog.inCache" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px" @click="openFolderGeneric(worldDialog.cachePath)") span(v-text="worldDialog.cacheSize") | {{ $t('dialog.world.tags.cache')}} + div + el-tag(v-if="worldDialog.ref.tags?.includes('content_horror')" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.content_horror') }} + el-tag(v-if="worldDialog.ref.tags?.includes('content_gore')" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.content_gore') }} + el-tag(v-if="worldDialog.ref.tags?.includes('content_violence')" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.content_violence') }} + el-tag(v-if="worldDialog.ref.tags?.includes('content_adult')" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.content_adult') }} + el-tag(v-if="worldDialog.ref.tags?.includes('content_sex')" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.content_sex') }} div(style="margin-top:5px") span(v-show="worldDialog.ref.name !== worldDialog.ref.description" v-text="worldDialog.ref.description" style="font-size:12px") div(style="flex:none;margin-left:10px") @@ -787,6 +793,12 @@ html el-tag.x-link(v-if="avatarDialog.inCache" type="info" effect="plain" size="mini" @click="openFolderGeneric(avatarDialog.cachePath)") span(v-text="avatarDialog.cacheSize") | {{ $t('dialog.avatar.tags.cache') }} + div + el-tag(v-if="avatarDialog.ref.tags?.includes('content_horror')" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.avatar.tags.content_horror') }} + el-tag(v-if="avatarDialog.ref.tags?.includes('content_gore')" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.avatar.tags.content_gore') }} + el-tag(v-if="avatarDialog.ref.tags?.includes('content_violence')" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.avatar.tags.content_violence') }} + el-tag(v-if="avatarDialog.ref.tags?.includes('content_adult')" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.avatar.tags.content_adult') }} + el-tag(v-if="avatarDialog.ref.tags?.includes('content_sex')" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.avatar.tags.content_sex') }} div(style="margin-top:5px") span(v-show="avatarDialog.ref.name !== avatarDialog.ref.description" v-text="avatarDialog.ref.description" style="font-size:12px") div(style="flex:none;margin-left:10px") @@ -810,6 +822,7 @@ html el-dropdown-item(v-else icon="el-icon-user" command="Make Public" divided) {{ $t('dialog.avatar.actions.make_public') }} el-dropdown-item(icon="el-icon-edit" command="Rename") {{ $t('dialog.avatar.actions.rename') }} el-dropdown-item(icon="el-icon-edit" command="Change Description") {{ $t('dialog.avatar.actions.change_description') }} + el-dropdown-item(icon="el-icon-edit" command="Change Content Tags") {{ $t('dialog.avatar.actions.change_content_tags') }} el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") {{ $t('dialog.avatar.actions.change_image') }} el-dropdown-item(v-if="avatarDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") {{ $t('dialog.avatar.actions.download_package') }} el-dropdown-item(icon="el-icon-user" command="Delete" style="color:#F56C6C" divided) {{ $t('dialog.avatar.actions.delete') }} @@ -1435,12 +1448,58 @@ html el-input(type="textarea" v-model="setWorldTagsDialog.authorTags" 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.set_world_tags.content_tags') }} #[br] - el-input(type="textarea" v-model="setWorldTagsDialog.contentTags" size="mini" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") + el-checkbox(v-model="setWorldTagsDialog.contentHorror") {{ $t('dialog.set_world_tags.content_horror') }} + br + el-checkbox(v-model="setWorldTagsDialog.contentGore") {{ $t('dialog.set_world_tags.content_gore') }} + br + el-checkbox(v-model="setWorldTagsDialog.contentViolence") {{ $t('dialog.set_world_tags.content_violence') }} + br + el-checkbox(v-model="setWorldTagsDialog.contentAdult") {{ $t('dialog.set_world_tags.content_adult') }} + br + el-checkbox(v-model="setWorldTagsDialog.contentSex") {{ $t('dialog.set_world_tags.content_sex') }} + //- el-input(type="textarea" v-model="setWorldTagsDialog.contentTags" size="mini" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") template(#footer) div(style="display:flex") el-button(size="small" @click="setWorldTagsDialog.visible = false") {{ $t('dialog.set_world_tags.cancel') }} el-button(type="primary" size="small" @click="saveSetWorldTagsDialog") {{ $t('dialog.set_world_tags.save') }} + //- dialog: Set Avatar Tags + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="setAvatarTagsDialog" :visible.sync="setAvatarTagsDialog.visible" :title="$t('dialog.set_avatar_tags.header')" width="770px") + template(v-if="setAvatarTagsDialog.visible") + el-checkbox(v-model="setAvatarTagsDialog.contentHorror") {{ $t('dialog.set_avatar_tags.content_horror') }} + br + el-checkbox(v-model="setAvatarTagsDialog.contentGore") {{ $t('dialog.set_avatar_tags.content_gore') }} + br + el-checkbox(v-model="setAvatarTagsDialog.contentViolence") {{ $t('dialog.set_avatar_tags.content_violence') }} + br + el-checkbox(v-model="setAvatarTagsDialog.contentAdult") {{ $t('dialog.set_avatar_tags.content_adult') }} + br + el-checkbox(v-model="setAvatarTagsDialog.contentSex") {{ $t('dialog.set_avatar_tags.content_sex') }} + br + template(v-if="setAvatarTagsDialog.ownAvatars.length === setAvatarTagsDialog.selectedCount") + el-button(size="small" @click="setAvatarTagsSelectToggle") {{ $t('dialog.set_avatar_tags.select_none') }} + template(v-else) + el-button(size="small" @click="setAvatarTagsSelectToggle") {{ $t('dialog.set_avatar_tags.select_all') }} + span(style="margin-left:5px") {{ setAvatarTagsDialog.selectedCount }} / {{ setAvatarTagsDialog.ownAvatars.length }} + span(v-if="setAvatarTagsDialog.loading" style="margin-left:5px") + i.el-icon-loading + br + .x-friend-list(style="margin-top:10px;min-height:60px;max-height:280px") + .x-friend-item(v-for="avatar in setAvatarTagsDialog.ownAvatars" :key="setAvatarTagsDialog.forceUpdate" @click="showAvatarDialog(avatar.id)" class="x-friend-item-border" style="width:350px") + .avatar + img(v-if="avatar.thumbnailImageUrl" v-lazy="avatar.thumbnailImageUrl") + .detail + span.name(v-text="avatar.name") + span.extra(v-text="avatar.releaseStatus" v-if="avatar.releaseStatus === 'public'" style="color: #67c23a;") + span.extra(v-text="avatar.releaseStatus" v-else-if="avatar.releaseStatus === 'private'" style="color: #f56c6c;") + span.extra(v-text="avatar.releaseStatus" v-else) + span.extra(v-text="avatar.$tagString") + el-button(type="text" size="mini" @click.stop style="margin-left:5px") + el-checkbox(v-model="avatar.$selected" @change="updateAvatarTagsSelection") + template(#footer) + el-button(size="small" @click="setAvatarTagsDialog.visible = false") {{ $t('dialog.set_avatar_tags.cancel') }} + el-button(type="primary" size="small" @click="saveSetAvatarTagsDialog") {{ $t('dialog.set_avatar_tags.save') }} + //- dialog: Cache Download el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="downloadDialog" :visible.sync="downloadDialog.visible" :title="$t('dialog.download_history.header')" width="770px") template(v-if="downloadDialog.visible") diff --git a/html/src/localization/strings/en.json b/html/src/localization/strings/en.json index c7b9360b..ecf81081 100644 --- a/html/src/localization/strings/en.json +++ b/html/src/localization/strings/en.json @@ -644,7 +644,12 @@ "avatar_scaling_disabled": "Avatar Scaling Disabled", "future_proofing": "Future Proofing", "labs": "Labs", - "cache": "Cache" + "cache": "Cache", + "content_horror": "Horror", + "content_gore": "Gore", + "content_violence": "Violence", + "content_adult": "Adult", + "content_sex": "Sexual" }, "actions": { "delete_cache_tooltip": "Delete world from cache", @@ -715,7 +720,12 @@ "private": "Private", "fallback": "Fallback", "future_proofing": "Future Proofing", - "cache": "Cache" + "cache": "Cache", + "content_horror": "Horror", + "content_gore": "Gore", + "content_violence": "Violence", + "content_adult": "Adult", + "content_sex": "Sexual" }, "labels": { "public": "(Public)", @@ -736,6 +746,7 @@ "make_private": "Make Private", "rename": "Rename", "change_description": "Change Description", + "change_content_tags": "Change Content Tags", "change_image": "Change Image", "download_package": "Download Unity Package", "delete": "Delete" @@ -951,7 +962,25 @@ "avatar_scaling_disabled": "Disable avatar scaling", "enable_debugging": "Enable world debugging for others", "author_tags": "Author Tags (comma separated)", - "content_tags": "Content Tags (comma separated)", + "content_tags": "Content Warning Tags", + "content_horror": "Horror", + "content_gore": "Gore", + "content_violence": "Violence", + "content_adult": "Adult", + "content_sex": "Sexual", + "cancel": "Cancel", + "save": "Save" + }, + "set_avatar_tags": { + "header": "Set Avatar Tags", + "content_tags": "Content Warning Tags", + "content_horror": "Horror", + "content_gore": "Gore", + "content_violence": "Violence", + "content_adult": "Adult", + "content_sex": "Sexual", + "select_all": "Select All", + "select_none": "Select None", "cancel": "Cancel", "save": "Save" },