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"
},