From 2d58d3cbbdb3e8d292de4ebb97c9ee9622125e79 Mon Sep 17 00:00:00 2001 From: Natsumi Date: Mon, 26 May 2025 04:33:41 +1000 Subject: [PATCH] Avatar Gallery Order --- src/api/avatar.js | 21 ++++ src/app.js | 18 +++- src/classes/utils.js | 14 +++ .../dialogs/AvatarDialog/AvatarDialog.vue | 101 +++++++++++++++--- src/localization/en/en.json | 6 +- 5 files changed, 140 insertions(+), 20 deletions(-) diff --git a/src/api/avatar.js b/src/api/avatar.js index d97e84b5..e43f3b08 100644 --- a/src/api/avatar.js +++ b/src/api/avatar.js @@ -215,6 +215,27 @@ const avatarReq = { // window.API.$emit('AVATARGALLERYIMAGE:ADD', args); return args; }); + }, + + /** + * @param {string[]} order + * @returns {Promise<{json: any, params}>} + */ + setAvatarGalleryOrder(order) { + const params = { + ids: order + }; + return window.API.call('files/order', { + method: 'PUT', + params + }).then((json) => { + const args = { + json, + params + }; + // window.API.$emit('AVATARGALLERYIMAGE:ORDER', args); + return args; + }); } }; // #endregion diff --git a/src/app.js b/src/app.js index 029813b2..acb81168 100644 --- a/src/app.js +++ b/src/app.js @@ -9535,6 +9535,7 @@ console.log(`isLinux: ${LINUX}`); bundleSizes: [], platformInfo: {}, galleryImages: [], + galleryLoading: false, lastUpdated: '', inCache: false, cacheSize: 0, @@ -9578,6 +9579,7 @@ console.log(`isLinux: ${LINUX}`); D.bundleSizes = []; D.platformInfo = {}; D.galleryImages = []; + D.galleryLoading = true; D.isFavorite = API.cachedFavoritesByObjectId.has(avatarId) || (API.currentUser.$isVRCPlus && @@ -9637,18 +9639,30 @@ console.log(`isLinux: ${LINUX}`); $app.methods.getAvatarGallery = async function (avatarId) { var D = this.avatarDialog; - const args = await avatarRequest.getAvatarGallery(avatarId); + const args = await avatarRequest + .getAvatarGallery(avatarId) + .finally(() => { + D.galleryLoading = false; + }); if (args.params.galleryId !== D.id) { return; } D.galleryImages = []; - for (const file of args.json) { + // wtf is this? why is order sorting only needed if it's your own avatar? + const sortedGallery = args.json.sort((a, b) => { + if (!a.order && !b.order) { + return 0; + } + return a.order - b.order; + }); + for (const file of sortedGallery) { const url = file.versions[file.versions.length - 1].file.url; D.galleryImages.push(url); } // for JSON tab treeData D.ref.gallery = args.json; + return D.galleryImages; }; $app.methods.selectAvatarWithConfirmation = function (id) { diff --git a/src/classes/utils.js b/src/classes/utils.js index 6a7d1057..db2888b3 100644 --- a/src/classes/utils.js +++ b/src/classes/utils.js @@ -23,6 +23,20 @@ const _utils = { ) ); }, + moveArrayItem(array, fromIndex, toIndex) { + if (!Array.isArray(array) || fromIndex === toIndex) { + return; + } + if (fromIndex < 0 || fromIndex >= array.length) { + return; + } + if (toIndex < 0 || toIndex >= array.length) { + return; + } + const item = array[fromIndex]; + array.splice(fromIndex, 1); + array.splice(toIndex, 0, item); + }, escapeTag(tag) { var s = String(tag); return s.replace(/["&'<>]/g, (c) => `&#${c.charCodeAt(0)};`); diff --git a/src/components/dialogs/AvatarDialog/AvatarDialog.vue b/src/components/dialogs/AvatarDialog/AvatarDialog.vue index 17052c03..c1da7ac9 100644 --- a/src/components/dialogs/AvatarDialog/AvatarDialog.vue +++ b/src/components/dialogs/AvatarDialog/AvatarDialog.vue @@ -4,7 +4,7 @@ class="x-dialog x-avatar-dialog" :visible.sync="avatarDialog.visible" :show-close="false" - width="600px"> + width="700px">
@@ -378,6 +378,7 @@ @change="onFileChangeAvatarGallery" /> - + style="position: absolute; bottom: 5px; left: 33.3%"> + + + +
@@ -1280,16 +1298,22 @@ } const r = new FileReader(); r.onload = function () { + props.avatarDialog.galleryLoading = true; const base64Body = btoa(r.result); - avatarRequest.uploadAvatarGalleryImage(base64Body, props.avatarDialog.id).then((args) => { - $message({ - message: t('message.avatar_gallery.uploaded'), - type: 'success' + avatarRequest + .uploadAvatarGalleryImage(base64Body, props.avatarDialog.id) + .then((args) => { + $message({ + message: t('message.avatar_gallery.uploaded'), + type: 'success' + }); + console.log(args); + props.avatarDialog.galleryImages = getAvatarGallery(props.avatarDialog.id); + return args; + }) + .finally(() => { + props.avatarDialog.galleryLoading = false; }); - console.log(args); - getAvatarGallery(props.avatarDialog.id); - return args; - }); }; r.readAsBinaryString(files[0]); clearFile(); @@ -1302,7 +1326,50 @@ message: t('message.avatar_gallery.deleted'), type: 'success' }); - getAvatarGallery(props.avatarDialog.id); + props.avatarDialog.galleryImages = getAvatarGallery(props.avatarDialog.id); + return args; + }); + } + + function reorderAvatarGalleryImage(imageUrl, direction) { + const fileId = extractFileId(imageUrl); + let fileIds = []; + props.avatarDialog.ref.gallery.forEach((item) => { + fileIds.push(extractFileId(item.id)); + }); + const index = fileIds.indexOf(fileId); + if (index === -1) { + $message({ + message: t('message.avatar_gallery.not_found'), + type: 'error' + }); + return; + } + if (direction === -1 && index === 0) { + $message({ + message: t('message.avatar_gallery.already_first'), + type: 'warning' + }); + return; + } + if (direction === 1 && index === fileIds.length - 1) { + $message({ + message: t('message.avatar_gallery.already_last'), + type: 'warning' + }); + return; + } + if (direction === -1) { + utils.moveArrayItem(fileIds, index, index - 1); + } else { + utils.moveArrayItem(fileIds, index, index + 1); + } + avatarRequest.setAvatarGalleryOrder(fileIds).then((args) => { + $message({ + message: t('message.avatar_gallery.reordered'), + type: 'success' + }); + props.avatarDialog.galleryImages = getAvatarGallery(props.avatarDialog.id); return args; }); } diff --git a/src/localization/en/en.json b/src/localization/en/en.json index 13ce3e6b..951377b3 100644 --- a/src/localization/en/en.json +++ b/src/localization/en/en.json @@ -1643,7 +1643,11 @@ "avatar_gallery": { "uploaded": "Avatar gallery image uploaded", "failed": "Failed to upload avatar gallery image", - "deleted": "Avatar gallery image deleted" + "deleted": "Avatar gallery image deleted", + "not_found": "Avatar gallery fileId not found", + "already_first": "Already first image", + "already_last": "Already last image", + "reordered": "Successfully reordered avatar gallery images" }, "world": { "image_changed": "World image changed",