diff --git a/src/api/avatar.js b/src/api/avatar.js index 172381ed..d97e84b5 100644 --- a/src/api/avatar.js +++ b/src/api/avatar.js @@ -167,6 +167,54 @@ const avatarReq = { // window.API.$emit('AVATAR:STYLES', args); return args; }); + }, + + /** + * @param {{ avatarId: string }} params + * @returns {Promise<{json: any, params}>} + */ + getAvatarGallery(avatarId) { + const params = { + tag: 'avatargallery', + galleryId: avatarId, + n: 100, + offset: 0 + }; + return window.API.call(`files`, { + params, + method: 'GET' + }).then((json) => { + const args = { + json, + params + }; + // window.API.$emit('AVATAR:GALLERY', args); + return args; + }); + }, + + /** + * @param {{ imageData: string, avatarId: string }} params + * @returns {Promise<{json: any, params}>} + */ + uploadAvatarGalleryImage(imageData, avatarId) { + const params = { + tag: 'avatargallery', + galleryId: avatarId + }; + return window.API.call('file/image', { + uploadImage: true, + matchingDimensions: false, + postData: JSON.stringify(params), + imageData + }).then((json) => { + const args = { + json, + params + }; + // window.API.$emit('AVATARGALLERYIMAGE:ADD', args); + return args; + }); } }; // #endregion diff --git a/src/api/misc.js b/src/api/misc.js index fe26a2c9..6598b7b6 100644 --- a/src/api/misc.js +++ b/src/api/misc.js @@ -185,6 +185,18 @@ const miscReq = { // window.API.$emit('VISITS', args); return args; }); + }, + + deleteFile(fileId) { + return window.API.call(`file/${fileId}`, { + method: 'DELETE' + }).then((json) => { + const args = { + json, + fileId + }; + return args; + }); } // /** diff --git a/src/api/vrcPlusIcon.js b/src/api/vrcPlusIcon.js index ba7a4ecf..fae0bfe6 100644 --- a/src/api/vrcPlusIcon.js +++ b/src/api/vrcPlusIcon.js @@ -15,18 +15,6 @@ const VRCPlusIconsReq = { }); }, - deleteFile(fileId) { - return window.API.call(`file/${fileId}`, { - method: 'DELETE' - }).then((json) => { - const args = { - json, - fileId - }; - return args; - }); - }, - uploadVRCPlusIcon(imageData) { const params = { tag: 'icon' diff --git a/src/app.js b/src/app.js index eeebfb11..029813b2 100644 --- a/src/app.js +++ b/src/app.js @@ -356,7 +356,9 @@ console.log(`isLinux: ${LINUX}`); languageClass: this.languageClass, showGroupDialog: this.showGroupDialog, showGallerySelectDialog: this.showGallerySelectDialog, - showGalleryDialog: this.showGalleryDialog + showGalleryDialog: this.showGalleryDialog, + getImageUrlFromImageId: this.getImageUrlFromImageId, + getAvatarGallery: this.getAvatarGallery }; }, el: '#root', @@ -1474,6 +1476,10 @@ console.log(`isLinux: ${LINUX}`); ref.unityPackages = unityPackages; } } + for (const listing of ref?.publishedListings) { + listing.displayName = $utils.replaceBioSymbols(listing.displayName); + listing.description = $utils.replaceBioSymbols(listing.description); + } ref.name = $utils.replaceBioSymbols(ref.name); ref.description = $utils.replaceBioSymbols(ref.description); return ref; @@ -9528,6 +9534,7 @@ console.log(`isLinux: ${LINUX}`); isIos: false, bundleSizes: [], platformInfo: {}, + galleryImages: [], lastUpdated: '', inCache: false, cacheSize: 0, @@ -9570,6 +9577,7 @@ console.log(`isLinux: ${LINUX}`); D.lastUpdated = ''; D.bundleSizes = []; D.platformInfo = {}; + D.galleryImages = []; D.isFavorite = API.cachedFavoritesByObjectId.has(avatarId) || (API.currentUser.$isVRCPlus && @@ -9592,6 +9600,7 @@ console.log(`isLinux: ${LINUX}`); .then((args) => { var { ref } = args; D.ref = ref; + this.getAvatarGallery(avatarId); this.updateVRChatAvatarCache(); if (/quest/.test(ref.tags)) { D.isQuestFallback = true; @@ -9626,6 +9635,22 @@ console.log(`isLinux: ${LINUX}`); }); }; + $app.methods.getAvatarGallery = async function (avatarId) { + var D = this.avatarDialog; + const args = await avatarRequest.getAvatarGallery(avatarId); + if (args.params.galleryId !== D.id) { + return; + } + D.galleryImages = []; + for (const file of args.json) { + const url = file.versions[file.versions.length - 1].file.url; + D.galleryImages.push(url); + } + + // for JSON tab treeData + D.ref.gallery = args.json; + }; + $app.methods.selectAvatarWithConfirmation = function (id) { this.$confirm(`Continue? Select Avatar`, 'Confirm', { confirmButtonText: 'Confirm', @@ -11153,6 +11178,10 @@ console.log(`isLinux: ${LINUX}`); return user.currentAvatarImageUrl; }; + $app.methods.getImageUrlFromImageId = function (imageId) { + return `https://api.vrchat.cloud/api/1/file/${imageId}/1/`; + }; + $app.methods.showConsole = function () { AppApi.ShowDevTools(); if ( diff --git a/src/app.scss b/src/app.scss index 9e28e56e..0f0da22c 100644 --- a/src/app.scss +++ b/src/app.scss @@ -940,6 +940,11 @@ i.x-status-icon.red { border-radius: 4px; } +.el-carousel__mask { + // looks bad + display: none; +} + // FIXME // Something changed the CSS of element-ui // The other parts are the same diff --git a/src/classes/websocket.js b/src/classes/websocket.js index 1cc5e5b8..c1d91e27 100644 --- a/src/classes/websocket.js +++ b/src/classes/websocket.js @@ -555,8 +555,13 @@ export default class extends baseClass { // hmm } else if (contentType === 'created') { // on avatar upload + } else if (contentType === 'avatargallery') { + // on avatar gallery image upload } else { - console.log('Unknown content-refresh', content); + console.log( + 'Unknown content-refresh type', + content.contentType + ); } break; diff --git a/src/components/dialogs/AvatarDialog/AvatarDialog.vue b/src/components/dialogs/AvatarDialog/AvatarDialog.vue index 0f0ed322..17052c03 100644 --- a/src/components/dialogs/AvatarDialog/AvatarDialog.vue +++ b/src/components/dialogs/AvatarDialog/AvatarDialog.vue @@ -365,7 +365,70 @@ -
+
+
+ {{ t('dialog.avatar.info.gallery') }} + + {{ t('dialog.screenshot_metadata.upload') }} + + + + + + +
+
+ {{ t('dialog.avatar.info.listings') }} +
+
+ +
+
+ {{ listing.displayName }} + ${{ commaNumber(listing.priceTokens) }}V + +
+
+
{{ t('dialog.avatar.info.memo') }} @@ -551,6 +614,8 @@ const showFavoriteDialog = inject('showFavoriteDialog'); const openExternalLink = inject('openExternalLink'); const adjustDialogZ = inject('adjustDialogZ'); + const getImageUrlFromImageId = inject('getImageUrlFromImageId'); + const getAvatarGallery = inject('getAvatarGallery'); const { t } = useI18n(); const instance = getCurrentInstance(); @@ -689,6 +754,10 @@ emit('deleteVRChatCache', ref); } + function commaNumber(num) { + return utils.commaNumber(num); + } + function avatarDialogCommand(command) { const D = props.avatarDialog; switch (command) { @@ -1177,4 +1246,64 @@ D.loading = false; }); } + + function displayAvatarGalleryUpload() { + document.getElementById('AvatarGalleryUploadButton').click(); + } + + function onFileChangeAvatarGallery(e) { + const clearFile = function () { + if (document.querySelector('#AvatarGalleryUploadButton')) { + document.querySelector('#AvatarGalleryUploadButton').value = ''; + } + }; + const files = e.target.files || e.dataTransfer.files; + if (!files.length) { + return; + } + if (files[0].size >= 100000000) { + // 100MB + $message({ + message: t('message.file.too_large'), + type: 'error' + }); + clearFile(); + return; + } + if (!files[0].type.match(/image.*/)) { + $message({ + message: t('message.file.not_image'), + type: 'error' + }); + clearFile(); + return; + } + const r = new FileReader(); + r.onload = function () { + const base64Body = btoa(r.result); + avatarRequest.uploadAvatarGalleryImage(base64Body, props.avatarDialog.id).then((args) => { + $message({ + message: t('message.avatar_gallery.uploaded'), + type: 'success' + }); + console.log(args); + getAvatarGallery(props.avatarDialog.id); + return args; + }); + }; + r.readAsBinaryString(files[0]); + clearFile(); + } + + function deleteAvatarGalleryImage(imageUrl) { + const fileId = extractFileId(imageUrl); + miscRequest.deleteFile(fileId).then((args) => { + $message({ + message: t('message.avatar_gallery.deleted'), + type: 'success' + }); + getAvatarGallery(props.avatarDialog.id); + return args; + }); + } diff --git a/src/components/dialogs/UserDialog/GalleryDialog.vue b/src/components/dialogs/UserDialog/GalleryDialog.vue index c452186e..2124ecbb 100644 --- a/src/components/dialogs/UserDialog/GalleryDialog.vue +++ b/src/components/dialogs/UserDialog/GalleryDialog.vue @@ -447,7 +447,7 @@