diff --git a/html/src/app.js b/html/src/app.js index 00935e9d..7a8f8d29 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -688,6 +688,22 @@ speechSynthesis.getVoices(); } } } + if ( + ref.$isVRCPlus && + ref.badges && + ref.badges.every((x) => x.badgeName !== 'Supporter') + ) { + // I doubt this will last long + ref.badges.unshift({ + badgeId: 'bdg_system_supporter', + badgeName: 'Supporter', + badgeDescription: 'Supports VRChat through VRC+', + badgeImageUrl: + 'https://assets.vrchat.com/badges/fa/bdgai_8c9cf371-ffd2-4177-9894-1093e2e34bf7.png', + hidden: true, + showcased: false + }); + } var friendCtx = $app.friends.get(ref.id); if (friendCtx) { friendCtx.ref = ref; @@ -1373,6 +1389,10 @@ speechSynthesis.getVoices(); API.$on('FRIEND:LIST', function (args) { for (var json of args.json) { + if (!json.displayName) { + console.error('/friends gave us garbage', json); + continue; + } this.$emit('USER', { json, params: { @@ -3905,6 +3925,7 @@ speechSynthesis.getVoices(); )}!` }).show(); $app.$refs.menu.activeIndex = 'feed'; + $app.updateStoredUser(this.currentUser); }); API.$on('LOGOUT', async function () { @@ -7036,7 +7057,11 @@ speechSynthesis.getVoices(); }; $app.methods.addFriendship = function (id) { - if (!this.friendLogInitStatus || this.friendLog.has(id) || id === API.currentUser.id) { + if ( + !this.friendLogInitStatus || + this.friendLog.has(id) || + id === API.currentUser.id + ) { return; } var ref = API.cachedUsers.get(id); @@ -7111,7 +7136,7 @@ speechSynthesis.getVoices(); created_at: new Date().toJSON(), type: 'Unfriend', userId: id, - displayName: ctx.displayName + displayName: ctx.displayName || id }; this.friendLogTable.data.push(friendLogHistory); database.addFriendLogHistory(friendLogHistory); @@ -12671,6 +12696,14 @@ speechSynthesis.getVoices(); D.visible = true; }; + $app.methods.newInstanceTabClick = function (tab) { + if (tab === '1') { + this.buildInstance(); + } else { + this.buildLegacyInstance(); + } + }; + $app.methods.makeHome = function (tag) { this.$confirm('Continue? Make Home', 'Confirm', { confirmButtonText: 'Confirm', @@ -13318,7 +13351,9 @@ speechSynthesis.getVoices(); L.instanceType !== 'public' && L.groupAccessType !== 'public' ) { - args.push(`vrchat://launch?id=${location}&shortName=${shortName}`); + args.push( + `vrchat://launch?ref=vrcx.app&id=${location}&shortName=${shortName}` + ); } else { // fetch shortName var newShortName = ''; @@ -13335,10 +13370,10 @@ speechSynthesis.getVoices(); } if (newShortName) { args.push( - `vrchat://launch?id=${location}&shortName=${newShortName}` + `vrchat://launch?ref=vrcx.app&id=${location}&shortName=${newShortName}` ); } else { - args.push(`vrchat://launch?id=${location}`); + args.push(`vrchat://launch?ref=vrcx.app&id=${location}`); } } var { launchArguments, vrcLaunchPathOverride } = @@ -22200,6 +22235,63 @@ speechSynthesis.getVoices(); $app.data.ossDialog = false; + // #region | App: Badges + + API.updateBadge = function (params) { + return this.call( + `users/${API.currentUser.id}/badges/${params.badgeId}`, + { + method: 'PUT', + params: { + userId: API.currentUser.id, + badgeId: params.badgeId, + hidden: params.hidden, + showcased: params.showcased + } + } + ).then((json) => { + var args = { + json, + params + }; + this.$emit('BADGE:UPDATE', args); + return args; + }); + }; + + API.$on('BADGE:UPDATE', function (args) { + if (args.json) { + $app.$message({ + message: 'Badge updated', + type: 'success' + }); + } + }); + + $app.methods.toggleBadgeVisibility = function (badge) { + if (badge.hidden) { + badge.showcased = false; + } + API.updateBadge({ + badgeId: badge.badgeId, + hidden: badge.hidden, + showcased: badge.showcased + }); + }; + + $app.methods.toggleBadgeShowcased = function (badge) { + if (badge.showcased) { + badge.hidden = false; + } + API.updateBadge({ + badgeId: badge.badgeId, + hidden: badge.hidden, + showcased: badge.showcased + }); + }; + + // #endregion + // "$app" is being replaced by Vue, update references inside all the classes $app = new Vue($app); window.$app = $app; diff --git a/html/src/app.scss b/html/src/app.scss index 68323f7d..f18175c1 100644 --- a/html/src/app.scss +++ b/html/src/app.scss @@ -408,6 +408,14 @@ img.friends-list-avatar { filter: none; } +.x-user-badge-hidden { + filter: grayscale(1); +} + +.x-user-badge:hover { + filter: none; +} + .x-friend-item > .avatar.online.mobile > img, .x-friend-item > .avatar.joinme.mobile > img, .x-friend-item > .avatar.askme.mobile > img, diff --git a/html/src/localization/en/en.json b/html/src/localization/en/en.json index 66e3ebb9..67b5b82b 100644 --- a/html/src/localization/en/en.json +++ b/html/src/localization/en/en.json @@ -571,6 +571,11 @@ "friend_no": "Friend No.{number}", "vrchat_team": "VRChat Team" }, + "badges": { + "assigned": "Assigned", + "hidden": "Hidden", + "showcased": "Showcased" + }, "actions": { "favorite_tooltip": "Add to favorites", "unfavorite_tooltip": "Remove from favorites", diff --git a/html/src/mixins/dialogs/newInstance.pug b/html/src/mixins/dialogs/newInstance.pug index f38be40b..5db446bc 100644 --- a/html/src/mixins/dialogs/newInstance.pug +++ b/html/src/mixins/dialogs/newInstance.pug @@ -1,6 +1,6 @@ mixin newInstance() el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="newInstanceDialog" :visible.sync="newInstanceDialog.visible" :title="$t('dialog.new_instance.header')" width="650px") - el-tabs(type="card" v-model="newInstanceDialog.selectedTab") + el-tabs(type="card" v-model="newInstanceDialog.selectedTab" @tab-click="newInstanceTabClick") el-tab-pane(:label="$t('dialog.new_instance.normal')") el-form(v-if="newInstanceDialog.visible" :model="newInstanceDialog" label-width="150px") el-form-item(:label="$t('dialog.new_instance.access_type')") diff --git a/html/src/mixins/dialogs/userDialog.pug b/html/src/mixins/dialogs/userDialog.pug index e605454b..3fd48fee 100644 --- a/html/src/mixins/dialogs/userDialog.pug +++ b/html/src/mixins/dialogs/userDialog.pug @@ -44,7 +44,7 @@ mixin userDialog() el-popover(placement="top" trigger="click") span.x-grey(slot="reference" v-text="API.currentUser.username" style="margin-right:10px;font-family:monospace;font-size:12px;cursor:pointer") span(style="display:block;text-align:center;font-family:monospace") {{ API.currentUser.username | textToHex }} - div + div(style="margin-top:5px") el-tag.name(type="info" effect="plain" size="mini" :class="userDialog.ref.$trustClass" v-text="userDialog.ref.$trustLevel" style="margin-right:5px;margin-top:5px") el-tag.x-tag-friend(v-if="userDialog.isFriend && userDialog.friend" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.user.tags.friend_no', { number: userDialog.friend.no }) }} el-tag.x-tag-troll(v-if="userDialog.ref.$isTroll" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Nuisance @@ -55,8 +55,27 @@ mixin userDialog() el-tag.x-tag-platform-ios(v-else-if="userDialog.ref.last_platform === 'ios'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") iOS el-tag.x-tag-platform-other(v-else-if="userDialog.ref.last_platform" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ userDialog.ref.last_platform }} el-tag.x-tag-age-verification(v-if="userDialog.ref.ageVerificationStatus && userDialog.ref.ageVerificationStatus !== 'hidden'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ userDialog.ref.ageVerificationStatus }} - el-tag.x-tag-vrcplus(v-if="userDialog.ref.$isVRCPlus" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") VRC+ el-tag.name(v-if="userDialog.ref.$customTag" type="info" effect="plain" size="mini" v-text="userDialog.ref.$customTag" :style="{'color':userDialog.ref.$customTagColour, 'border-color':userDialog.ref.$customTagColour}" style="margin-right:5px;margin-top:5px") + br + template(v-for="badge in userDialog.ref.badges") + el-tooltip(placement="top") + template(#content) + span {{ badge.badgeName }} + span(v-if="badge.hidden")  (Hidden) + el-popover(placement="right" width="300px" trigger="click") + img.x-link.x-user-badge(slot="reference" v-lazy="badge.badgeImageUrl" style="flex:none;height:32px;width:32px;border-radius:3px;object-fit:cover;margin-top:5px;margin-right:5px" :class="{'x-user-badge-hidden':badge.hidden}") + img.x-link(v-lazy="badge.badgeImageUrl" style="height:300px" @click="showFullscreenImageDialog(badge.badgeImageUrl)") + br + span {{ badge.badgeName }} + br + span.x-grey(style="font-size:12px") {{ badge.badgeDescription }} + br + span.x-grey(v-if="badge.assignedAt" style="font-family:monospace;font-size:12px") {{ $t('dialog.user.badges.assigned') }}: {{ badge.assignedAt | formatDate('long') }} + template(v-if="userDialog.id === API.currentUser.id") + br + el-checkbox(@change="toggleBadgeVisibility(badge)" v-model="badge.hidden" style="margin-top:5px") {{ $t('dialog.user.badges.hidden') }} + br + el-checkbox(@change="toggleBadgeShowcased(badge)" v-model="badge.showcased" style="margin-top:5px") {{ $t('dialog.user.badges.showcased') }} div(style="margin-top:5px") span(v-text="userDialog.ref.statusDescription" style="font-size:12px") div(v-if="userDialog.ref.userIcon" style="flex:none;margin-right:10px") diff --git a/html/src/theme.dark.scss b/html/src/theme.dark.scss index aeba91bc..e51eb3fa 100644 --- a/html/src/theme.dark.scss +++ b/html/src/theme.dark.scss @@ -258,6 +258,7 @@ button { } .el-popover { + color: #c8c8c8; background-color: #333; border-color: #5f5f5f; }